{"id":7677,"date":"2024-02-20T13:33:55","date_gmt":"2024-02-20T19:33:55","guid":{"rendered":"https:\/\/gregsowell.com\/?p=7677"},"modified":"2024-02-20T13:33:55","modified_gmt":"2024-02-20T19:33:55","slug":"automating-vmware-alternatives-with-ansible-and-ascender","status":"publish","type":"post","link":"https:\/\/gregsowell.com\/?p=7677","title":{"rendered":"Automating VMware Alternatives With Ansible And Ascender"},"content":{"rendered":"<p><a href=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/thumbnail-template.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/thumbnail-template-300x169.jpg\" alt=\"\" width=\"300\" height=\"169\" class=\"aligncenter size-medium wp-image-7679\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/thumbnail-template-300x169.jpg 300w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/thumbnail-template-768x432.jpg 768w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/thumbnail-template-1024x576.jpg 1024w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/thumbnail-template.jpg 1280w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Automating VMware Alternatives With Ansible And Ascender<br \/>\nI have personally used and had good success with VMware for nearly two decades.  While it is a good product, I occasionally have folks talk about some alternatives, and how viable they are.  For this article\/demo I\u2019m going to use Proxmox VE, which is a competent\/user friendly hypervisor.  Really, I\u2019m going to examine this question from an automation perspective.<\/p>\n<p>First, and most importantly, <strong>the user experience is exactly the same<\/strong> no matter what hypervisor you use.  This means your users can smoothly transition from one platform to the other with no knowledge that anything has changed.<\/p>\n<p>The backend, using Ansible and Ascender, will have different playbooks, which means you will be using different modules, and often some slightly different procedures, but frequently they aren\u2019t so different.<\/p>\n<h2>Demo Video<\/h2>\n<p><iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/SuuFYNLxDWM?si=I49UAasUhiG3aljh\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe><\/p>\n<h2>Interfaces Compared<\/h2>\n<p>VMware\u2019s Vcenter has been a pretty consistent interface for a while now:<br \/>\n<a href=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_1.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_1-300x140.jpg\" alt=\"\" width=\"300\" height=\"140\" class=\"aligncenter size-medium wp-image-7680\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_1-300x140.jpg 300w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_1-768x358.jpg 768w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_1-1024x477.jpg 1024w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_1.jpg 1868w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Proxmox VE may be new to you, but the interface should look and feel awfully familiar:<br \/>\n<a href=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_2-300x144.jpg\" alt=\"\" width=\"300\" height=\"144\" class=\"aligncenter size-medium wp-image-7681\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_2-300x144.jpg 300w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_2-768x368.jpg 768w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_2-1024x491.jpg 1024w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_2.jpg 1891w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>They both will very similarly allow you to access and edit settings, add\/delete VMs and templates\u2026BUT, who wants to manage infrastructure manually?<\/p>\n<h2>Playbooks Compared<\/h2>\n<p>You can find my <a href=\"https:\/\/github.com\/gregsowell\/ansible-ascender-proxmox\">Proxmox playbooks here<\/a>, and my <a href=\"https:\/\/github.com\/gregsowell\/ascender-vmware\">VMware playbooks are here<\/a>.<\/p>\n<p>The two playbooks in question, one for Proxmox and one for VMware, are structured very similarly, but use their respective modules.<\/p>\n<p>I\u2019m going to breakdown and comment on each playbook below.<br \/>\n<strong>Proxmox Playbook(proxmox-vm.yml)<\/strong><\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">---\r\n- name: Create and control VMs on Proxmox using Ascender\r\n  hosts: localhost\r\n  gather_facts: false\r\n  vars:\r\n    # Configure the api connection info for Proxmox host\r\n    proxmox_auth: &amp;proxmox_auth\r\n      api_host: proxmox.gregsowell.com\r\n      api_user: &quot;{{ gen1_user }}&quot;\r\n      # api_user: root@pam # username format example\r\n      # Use standard password\r\n      api_password: &quot;{{ gen1_pword }}&quot;\r\n      # Use api token and secret - example format\r\n      # api_token_id: gregisa5.0\r\n      # api_token_secret: 72a72987-ff68-44f1-9fee-c09adaaecf4d<\/code><\/pre>\n<p>Above I use a concept in YAML known as an anchor.  In every task below I will reference this anchor with an alias.  This essentially allows me to reference a set of options and inject them in various other places in my playbook.  An anchor is set via the &#038; symbol, which says \u201ceverything else after this is part of the anchor.\u201d<\/p>\n<p>Here I\u2019m setting up the authentication.  I have examples of doing username \/ password or using an api token.  Notice that for username and password I\u2019m using variables.  This is because I\u2019m passing in a custom credential via Ascender to the playbook at run time.  Doing this allows me to securely maintain those credentials in the Ascender database.<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">    # Configure template to clone for new vm\r\n    clone_template: rocky9-template\r\n\r\n    # Configure location on Host to store new vm\r\n    storage_location: local-lvm\r\n\r\n    # Linked Clone needs format=unspecified and full=false\r\n    # Format of new VM\r\n    vm_format: qcow2\r\n\r\n    # Default name to use for the VM\r\n    vm_name: test-rocky9\r\n\r\n    # How many cores\r\n    # vm_cores: 2\r\n\r\n    # How many vcpus:\r\n    # vm_vcpus: 2\r\n    \r\n    # Options for specifying network interface type\r\n    #vm_net0: &#039;virtio,bridge=vmbr0&#039;\r\n\r\n    #vm_ipconfig0: &#039;ip=192.168.1.1\/24,gw=192.168.1.1&#039;<\/code><\/pre>\n<p>Above here you can see that I\u2019m setting up defaults for my standard variables that can be overridden at run time.  Remember that if you pass in variables as extra_vars they have the highest level of precedence.<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">    # Switches for playbook control\r\n    # vm_action: provision\r\n    # vm_action: start\r\n    # vm_action: stop\r\n    # vm_action: delete\r\n\r\n\r\n  tasks:\r\n  - name: Block for creating a vm\r\n    when: vm_action == &quot;provision&quot;\r\n    block:\r\n    - name: Create a VM based on a template\r\n      community.general.proxmox_kvm:\r\n        # api_user: root@pam\r\n        # api_password: secret\r\n        # api_host: helldorado\r\n        &lt;&lt;: *proxmox_auth\r\n        clone: &quot;{{ clone_template }}&quot;\r\n        name: &quot;{{ vm_name }}&quot;\r\n        node: proxmox\r\n        storage: &quot;{{ storage_location }}&quot;\r\n        format: &quot;{{ vm_format }}&quot;\r\n        timeout: 500\r\n        cores: &quot;{{ vm_cores | default(omit) }}&quot;\r\n        vcpus: &quot;{{ vm_vcpus | default(omit) }}&quot;\r\n        net:\r\n          net0: &quot;{{ vm_net0 | default(omit) }}&quot;\r\n        ipconfig:\r\n          ipconfig0: &quot;{{ vm_ipconfig0 | default(omit) }}&quot;\r\n      register: vm_provision_info\r\n\r\n    - name: Pause after provision to give the API a chance to catch up\r\n      ansible.builtin.pause:\r\n        seconds: 10<\/code><\/pre>\n<p>Here you can see my first two tasks.  I\u2019m looking for the vm_action variable to be set to provision, and if it is I will run this block of code.  I\u2019ll then clone a template.  Here I\u2019m doing a full clone, but I could also set it to be a linked clone if I wanted.  You can also see I have some customization variables here, that when not set are omitted.  After the VM provisions, it will pause for about 10 seconds to give the system time to register the new VM before it proceeds on.<\/p>\n<p>This is also where you see the anchor being referenced.  The \u201c<<: *proxmox_auth\u201d is the alias with override.  This will take the variable chunk from above and inject it into this module(which makes modification to it easier and saves several lines of code in each task).\n\n\n\n<pre class=\"gs-code\"><code class=\"language-plaintext\">  - name: Start VM\r\n    when: (vm_action == &quot;provision&quot; and vm_provision_info.changed) or vm_action == &quot;start&quot;\r\n    community.general.proxmox_kvm:\r\n      &lt;&lt;: *proxmox_auth\r\n      name: &quot;{{ vm_name }}&quot;\r\n      node: proxmox\r\n      state: started<\/code><\/pre>\n<p>You can see in this start task that I have two conditionals.  One if the vm_action is set to start and one if the action is set to provision and it actually made a change when doing the provision.  It does this on the provision task because by default when you clone a template it won\u2019t be started.  We also check for the changed status because the clone operation is idempotent, which means if that VM already exists, it won\u2019t do anything, it will simply report back \u201cok\u201d.<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">  - name: Stop VM\r\n    when: vm_action == &quot;stop&quot;\r\n    community.general.proxmox_kvm:\r\n      &lt;&lt;: *proxmox_auth\r\n      name: &quot;{{ vm_name }}&quot;\r\n      node: proxmox\r\n      state: stopped\r\n\r\n  - name: Delete VM block\r\n    when: vm_action == &quot;delete&quot;\r\n    block:\r\n    - name: Stop VM with force\r\n      community.general.proxmox_kvm:\r\n        &lt;&lt;: *proxmox_auth\r\n        name: &quot;{{ vm_name }}&quot;\r\n        node: proxmox\r\n        state: stopped\r\n        force: true\r\n\r\n    - name: Pause to allow shutdown to complete\r\n      ansible.builtin.pause:\r\n        seconds: 10\r\n\r\n    - name: Delete VM\r\n      community.general.proxmox_kvm:\r\n        &lt;&lt;: *proxmox_auth\r\n        name: &quot;{{ vm_name }}&quot;\r\n        node: proxmox\r\n        state: absent<\/code><\/pre>\n<p>The delete block isn\u2019t too complex.  It first stops the VM, pauses so the system will register the change, then performs the delete from disk.<\/p>\n<p><strong>VMware Playbook(vmware-vm.yml)<\/strong><br \/>\nCompare and contrast the two playbooks: they are laid out almost identically, the tasks are in the same order, and they are configured almost the same.  This means transitioning from one to the other should be pretty seamless.<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">---\r\n- name: Create and control VMs on VMware using Ascender\r\n  hosts: localhost\r\n  gather_facts: false\r\n  vars:\r\n    # below are all of the details for the VM.  I&#039;m overriding these at runtime.\r\n    vm_datacenter: MNS\r\n    vm_name: snowtest2\r\n#    vm_template: Windows2016\r\n    vm_template: Rocky8.6\r\n#    vm_template: Rocky8\r\n#    vm_template: Rocky9\r\n    vm_folder: \/Greg\/ciq\r\n    vm_disksize: 50\r\n    vm_datastore: SSD\r\n    # minimum of 4GB of RAM\r\n    vm_memory: 4096\r\n    vm_cpus: 4\r\n    vm_netname: Greg\r\n    vm_ip: 10.1.12.56\r\n    vm_netmask: 255.255.255.0\r\n    vm_gateway: 10.1.12.1\r\n\r\n    vmware_auth: &amp;vmware_auth\r\n      hostname: &quot;{{ vcenter_hostname }}&quot;\r\n      username: &quot;{{ gen1_user }}&quot;\r\n      password: &quot;{{ gen1_pword }}&quot;\r\n      validate_certs: no\r\n\r\n    # Switches for playbook control\r\n    # vm_action: provision\r\n    # vm_action: start\r\n    # vm_action: stop\r\n    # vm_action: delete\r\n\r\n\r\n  tasks:\r\n  - name: Provision a VM\r\n    when: vm_action == &quot;provision&quot;\r\n    community.vmware.vmware_guest:\r\n      &lt;&lt;: *vmware_auth\r\n      folder: &quot;{{ vm_folder }}&quot;\r\n      name: &quot;{{ vm_name }}&quot;\r\n      datacenter: &quot;{{ vm_datacenter }}&quot;\r\n      state: poweredon\r\n#      guest_id: centos64Guest\r\n      template: &quot;{{ vm_template }}&quot;\r\n  # This is hostname of particular ESXi server on which user wants VM to be deployed\r\n      disk:\r\n      - size_gb: &quot;{{ vm_disksize }}&quot;\r\n        type: thin\r\n        datastore: &quot;{{ vm_datastore }}&quot;\r\n      hardware:\r\n        memory_mb: &quot;{{ vm_memory }}&quot;\r\n        num_cpus: &quot;{{ vm_cpus}}&quot;\r\n        scsi: paravirtual\r\n      networks:\r\n      - name: &quot;{{ vm_netname}}&quot;\r\n        connected: true\r\n        start_connected: true\r\n        type: dhcp\r\n        # type: static\r\n        # ip: &quot;{{ vm_ip }}&quot;\r\n        # netmask: &quot;{{ vm_netmask }}&quot;\r\n        # gateway: &quot;{{ vm_gateway }}&quot;\r\n        # dns_servers: &quot;{{ vm_gateway }}&quot;\r\n#      wait_for_ip_address: true\r\n#        device_type: vmxnet3\r\n    register: deploy_vm\r\n\r\n  - name: Start a VM\r\n    when: vm_action == &quot;start&quot;\r\n    community.vmware.vmware_guest:\r\n      &lt;&lt;: *vmware_auth\r\n      folder: &quot;{{ vm_folder }}&quot;\r\n      name: &quot;{{ vm_name }}&quot;\r\n      datacenter: &quot;{{ vm_datacenter }}&quot;\r\n      state: poweredon\r\n\r\n  - name: Stop a VM\r\n    when: vm_action == &quot;stop&quot;\r\n    community.vmware.vmware_guest:\r\n      &lt;&lt;: *vmware_auth\r\n      folder: &quot;{{ vm_folder }}&quot;\r\n      name: &quot;{{ vm_name }}&quot;\r\n      datacenter: &quot;{{ vm_datacenter }}&quot;\r\n      # state: poweredoff\r\n      state: shutdownguest \r\n\r\n  - name: Delete a VM\r\n    when: vm_action == &quot;delete&quot;\r\n    community.vmware.vmware_guest:\r\n      &lt;&lt;: *vmware_auth\r\n      folder: &quot;{{ vm_folder }}&quot;\r\n      name: &quot;{{ vm_name }}&quot;\r\n      datacenter: &quot;{{ vm_datacenter }}&quot;\r\n      state: absent\r\n      force: true<\/code><\/pre>\n<h2>Interface Comparison In Ascender<\/h2>\n<p>For my job templates(how you pull your playbook and required components together in Ascender) I\u2019m using something called a survey.  This allows you to quickly\/easily configure a set of questions for the user to answer before the automation is run.  Here\u2019s an example of my VMware survey:<br \/>\n<a href=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_3.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_3-300x173.jpg\" alt=\"\" width=\"300\" height=\"173\" class=\"aligncenter size-medium wp-image-7682\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_3-300x173.jpg 300w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_3-768x444.jpg 768w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_3-1024x592.jpg 1024w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_3.jpg 1465w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Adding an entry is as simple as clicking add and filling in the blanks:<br \/>\n<a href=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_4.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_4-300x75.jpg\" alt=\"\" width=\"300\" height=\"75\" class=\"aligncenter size-medium wp-image-7683\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_4-300x75.jpg 300w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_4-768x193.jpg 768w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_4.jpg 968w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<a href=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_5.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_5-300x147.jpg\" alt=\"\" width=\"300\" height=\"147\" class=\"aligncenter size-medium wp-image-7684\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_5-300x147.jpg 300w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_5-768x377.jpg 768w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_5-1024x502.jpg 1024w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_5.jpg 1311w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Notice in the above there is a blank space for \u201cAnswer variable name\u201d.  This is the extra_vars variable that the info will be passed to the playbook with.  That\u2019s how these surveys work; they simply pass info to the playbook as an extra_var.<\/p>\n<p>So for the sake of comparison, here\u2019s what it looks like when you launch the two different job templates:<br \/>\n<strong>VMware Job Template:<\/strong><br \/>\n<a href=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_6.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_6-239x300.jpg\" alt=\"\" width=\"239\" height=\"300\" class=\"aligncenter size-medium wp-image-7685\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_6-239x300.jpg 239w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_6.jpg 677w\" sizes=\"auto, (max-width: 239px) 100vw, 239px\" \/><\/a><\/p>\n<p><strong>Proxmox Job Template:<\/strong><br \/>\n<a href=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_7.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_7-248x300.jpg\" alt=\"\" width=\"248\" height=\"300\" class=\"aligncenter size-medium wp-image-7686\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_7-248x300.jpg 248w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_7.jpg 712w\" sizes=\"auto, (max-width: 248px) 100vw, 248px\" \/><\/a><\/p>\n<p>Notice how they are almost identical.  I added all of the options to the VMware JT, but I kept the Proxmox one a little cleaner.  I could have just as easily added all of the knobs, but I wanted to show how you can make them full featured or simple.  In the end they accomplish the same task.  You put in the VM\u2019s name, choose an action to perform, and add any additional data required.  That\u2019s literally all there is to it!<\/p>\n<p>When I say choose an action it\u2019s as easy as this:<br \/>\n<a href=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_8.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_8-300x273.jpg\" alt=\"\" width=\"300\" height=\"273\" class=\"aligncenter size-medium wp-image-7687\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_8-300x273.jpg 300w, https:\/\/gregsowell.com\/wp-content\/uploads\/2024\/02\/Screenshot_8.jpg 374w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<h2>Conclusion<\/h2>\n<p>Now this should just serve to show you how easy it is to automate different hypervisors.  Keep in mind that this example is simple, but can easily be expanded to easily automate virtually all of the functions of your virtual environment.<\/p>\n<p>As always, I\u2019m looking for feedback.  How would you use this in your environment\u2026how would you tweak or tune this?  <\/p>\n<p>CIQ also does professional services, so if  you need help building, configuring, or migrating your automation strategy, environments, or systems, please reach out!<\/p>\n<p>Thanks and happy automating!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Automating VMware Alternatives With Ansible And Ascender I have personally used and had good success with VMware for nearly two decades. While it is\u2026<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[49,59,14,13,40],"tags":[],"class_list":["post-7677","post","type-post","status-publish","format-standard","hentry","category-ansible","category-ascender","category-linux","category-server","category-vmware"],"_links":{"self":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts\/7677","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7677"}],"version-history":[{"count":2,"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts\/7677\/revisions"}],"predecessor-version":[{"id":7688,"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts\/7677\/revisions\/7688"}],"wp:attachment":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7677"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7677"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7677"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}