1

I'm building an ansible playbook designed to run on a vcenter VM. It's run on startup by ansible-pull. My goal is to read the tags on the vm using ansible, then make some config changes to the guest system based on those tags.

The difficulty is that I need to read the tags on the guest from inside the guest. The vmware_guest_facts module will let me do this, but it requires the name or uuid of the guest.

Currently the only way I can see to do that is to use vmware_vm_facts to get the facts of ALL the VMs, then find the VM where ansible_default_ipv4.address matches the ip address, set that as a fact, then use vmware_guest_facts to read the tags from that VM by UUID. It seems like overkill.

Is there an easy way for a VM to read its own tags I'm overlooking?

Here's what I have to do now:

- hosts: localhost
  connection: local

  vars_files:
    - vars.yaml

  pre_tasks:
    - name:  Read VMware vm facts
      vmware_vm_facts:
        hostname: "{{vc_host}}"
        password: "{{vc_pass}}"
        username: "{{vc_user}}"
        validate_certs: no
        vm_type: vm
      delegate_to: localhost
      register: vmfacts

    - name: scan for ip
      set_fact:
        vm_uuid: "{{ item.uuid }}"
        vm_name: "{{ item.guest_name }}"
      with_items: "{{ vmfacts.virtual_machines }}"
      when:
        - item.ip_address is defined
        - ansible_default_ipv4.address == item.ip_address


    - name:  Read VMware guest facts
      vmware_guest_facts:
        datacenter: ASDC
        hostname: "{{vc_host}}"
        uuid: "{{vm_uuid}}"
        password: "{{vc_pass}}"
        username: "{{vc_user}}"
        tags: yes
        validate_certs: no
      register: vmguestfacts


    - name:  set up tags var
      set_fact:
        vm_tags: "{{ vmguestfacts.instance.tags }}"

    - debug:
        msg: "{{ vm_tags }}"

Mike A
  • 500
  • 4
  • 16
  • Are these Linux guests? You can find the system UUID using `dmidecode`, which should match the VM UUID. Programmatically retrieved with `dmidecode -s system-uuid`. If Windows I'm sure there is something comparable, but I can't help with that sorry. – Matt P Aug 06 '19 at 23:39
  • They are linux guests. However the uuid and hw_product_uuid reported by ansible do not match the uuid reported by dmidecode. `dmidecode | grep "Serial Number: VMware"` returns `Serial Number: VMware-xx xx xx xx xx xx xx xx-xx xx xx xx xx xx xx xx` and the hex string matches the vmware uuid. The catch is that dmidecode requires root access, so I'll have to tweak something else to get it to work. – Mike A Aug 07 '19 at 19:51

3 Answers3

1

I maintain vmware_vm_facts and raised a PR https://github.com/ansible/ansible/pull/60220 to get tags for all Virtual Machines using vmware_vm_facts. With this feature you will be able to gather VM tags.

After PR is merged, task will look like this -

- name: Get Tags from given VM Name
  block:
    - name: Get virtual machine facts
      vmware_vm_facts:
        hostname: '{{ vcenter_hostname }}'
        username: '{{ vcenter_username }}'
        password: '{{ vcenter_password }}'
        folder: "/datacenter/vm/folder"
        show_tag: True
      delegate_to: localhost
      register: vm_facts

    - debug:
        msg: "{{ item.tags }}"
      with_items:
        - "{{ vm_facts.virtual_machines | json_query(query) }}"
      vars:
        query: "[?guest_name=='DC0_H0_VM0']"
Abhijeet Kasurde
  • 3,937
  • 1
  • 24
  • 33
0

The version I posted above takes 37 seconds to run, because it's requesting info on ALL vms on the vCenter. I discovered that dmidecode -s system-serial-number will give the system serial which matches the uuid of the vm in hex format Serial Number: VMware-xx xx xx xx xx xx xx xx-xx xx xx xx xx xx xx xx

The following runs in about 7 seconds:

- hosts: localhost
  connection: local

  vars_files:
    - vars.yaml

  pre_tasks:
    - name:  get uuid
      shell: |
        sudo /usr/sbin/dmidecode -s system-serial-number
      register: dmiout

    - set_fact:
        singleuuid: "{{ dmiout.stdout | regex_replace('.*VMware-(.*)$', '\\1') | replace(' ','') | replace('-','') }}"

    - set_fact:
        localuuid: "{{singleuuid[0:8]}}-{{singleuuid[8:12]}}-{{singleuuid[12:16]}}-{{singleuuid[16:20]}}-{{singleuuid[20:32]}}"

    - name:  Read VMware guest facts
      vmware_guest_facts:
        datacenter: ASDC
        hostname: "{{vc_host}}"
        uuid: "{{localuuid}}"
        password: "{{vc_pass}}"
        username: "{{vc_user}}"
        tags: yes
        validate_certs: no
      register: vmguestfacts


    - name:  set up tags var
      set_fact:
        vm_tags: "{{ vmguestfacts.instance.tags }}"

    - debug:
        msg: "{{ vm_tags }}"

The only catch is that dmidecode requires root access to run. Since this is running as a normal user foouser, I had to add this line to sudoers:

foouser ALL=(ALL) NOPASSWD:/usr/sbin/dmidecode

This whole thing is clunkier than I'd like, so in the next iteration I'll probably change the playbook to run as root, so I can remove the sudo needs.

EDIT:
Someone asked what the regex does, so here's a bit of explanation. We start with

sudo /usr/sbin/dmidecode -s system-serial-number

which returns

VMware-24 25 26 27 76 15 29 9d-0e 56 e5 b3 52 9f 41 a2

The first regex_replace replaces VMware- with nothing, giving us

24 25 26 27 76 15 29 9d-0e 56 e5 b3 52 9f 41 a2

The second replace replaces spaces with nothing, giving us

242526277615299d-0e56e5b3529f41a2

The third replace replaces the dash with nothing, giving us

242526277615299d0e56e5b3529f41a2

The next line adds dashes at the correct locations to turn that into a valid uuid.

Abhijeet Kasurde
  • 3,937
  • 1
  • 24
  • 33
Mike A
  • 500
  • 4
  • 16
0

Quick update, I use Ansible fact instead of the shell module:

- set_fact:
    singleuuid: "{{ ansible_product_serial | regex_replace('.*VMware-(.*)$', '\\1') | replace(' ','') | replace('-','') }}"
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83