-1

Trying to get a variable defined when the task is partially failed/ignored. When a VM is not found in Vsphere it throws an error: "msg": "Unable to gather information for non-existing VM vm2"

I tried with and without ignore_errors: True and failed_when: 0 > 1 but no change. I need the variable vm_fact to be defined even when a non-existing VM is in the decom_list. The plan is to change the list after i have identified which VM's are non-existing. Please note: this task does work when all vm's are present in the system. When one is missing the task fails. I need the task not to fail so that i can clean the decom_list and then run it again.

- name: check/power(on/off) hosts on vsphere
  hosts: localhost
  ignore_errors: True
  vars:
     decom_list:
        - vm1
        - vm2
        - vm3
  tasks:

    - name: check hosts on vsphere
      vmware_guest_info:
        hostname: "{{ vcenter_hostname }}"
        username: "{{ vcenter_username }}"
        password: "{{ vcenter_password }}"
        name: "{{ item }}"
        schema: vsphere
        datacenter: DC1
      loop: "{{ decom_list }}"
      register: vm_fact
      ignore_errors: True
      failed_when: 0 > 1

Whatever i try does not work because my vm_fact is not defined.

    - debug:
        var: "{{ vm_fact }}"

error:

TASK [debug] **************************************************************************************************************************
ok: [localhost] => {
    "<class 'dict'>": "VARIABLE IS NOT DEFINED!"
}

Just to confirm i did try all i know.

When i try it with a loop:

    - debug:
        var: "{{ item['item'] }}"
      loop: "{{ vm_fact['results'] }}"
      when: '"Unable to gather information for non-existing VM" in item.msg'

I get error:

ok: [localhost] => (item={'failed': False, 'msg': 'Unable to gather information for non-existing VM vm2', 'invocation': {'module_args': {'hostname': 'hostname.domain', 'username': 'username', 'password': 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER', 'name': 'vm2', 'schema': 'vsphere', 'datacenter': 'DC1', 'port': 443, 'validate_certs': True, 'name_match': 'first', 'use_instance_uuid': False, 'tags': False, 'tag_details': False, 'proxy_host': None, 'proxy_port': None, 'uuid': None, 'moid': None, 'folder': None, 'properties': None}}, 'changed': False, 'failed_when_result': False, 'item': 'vm2', 'ansible_loop_var': 'item'}) => {
    "ansible_loop_var": "item",
    "item": {
        "ansible_loop_var": "item",
        "changed": false,
        "failed": false,
        "failed_when_result": false,
        "invocation": {
            "module_args": {
                "datacenter": "DC1",
                "folder": null,
                "hostname": "hostname.domain",
                "moid": null,
                "name": "vm2",
                "name_match": "first",
                "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "port": 443,
                "properties": null,
                "proxy_host": null,
                "proxy_port": null,
                "schema": "vsphere",
                "tag_details": false,
                "tags": false,
                "use_instance_uuid": false,
                "username": "username",
                "uuid": null,
                "validate_certs": true
            }
        },
        "item": "vm2",
        "msg": "Unable to gather information for non-existing VM vm2"
    },
    "vm2": "VARIABLE IS NOT DEFINED!"
}
ok: [localhost] => (item={'failed': False, 'msg': 'Unable to gather information for non-existing VM vm3', 'invocation': {'module_args': {'hostname': 'hostname.domain', 'username': 'username', 'password': 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER', 'name': 'vm3', 'schema': 'vsphere', 'datacenter': 'DC1', 'port': 443, 'validate_certs': True, 'name_match': 'first', 'use_instance_uuid': False, 'tags': False, 'tag_details': False, 'proxy_host': None, 'proxy_port': None, 'uuid': None, 'moid': None, 'folder': None, 'properties': None}}, 'changed': False, 'failed_when_result': False, 'item': 'vm3', 'ansible_loop_var': 'item'}) => {
    "ansible_loop_var": "item",
    "item": {
        "ansible_loop_var": "item",
        "changed": false,
        "failed": false,
        "failed_when_result": false,
        "invocation": {
            "module_args": {
                "datacenter": "DC1",
                "folder": null,
                "hostname": "hostname.domain",
                "moid": null,
                "name": "vm3",
                "name_match": "first",
                "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "port": 443,
                "properties": null,
                "proxy_host": null,
                "proxy_port": null,
                "schema": "vsphere",
                "tag_details": false,
                "tags": false,
                "use_instance_uuid": false,
                "username": "username",
                "uuid": null,
                "validate_certs": true
            }
        },
        "item": "vm3",
        "msg": "Unable to gather information for non-existing VM vm3"
    },
    "vm3": "VARIABLE IS NOT DEFINED!"
}
fatal: [localhost]: FAILED! => {"msg": "The conditional check '\"Unable to gather information for non-existing VM\" in item.msg' failed. The error was: error while evaluating conditional (\"Unable to gather information for non-existing VM\" in item.msg): 'dict object' has no attribute 'msg'\n\nThe error appears to be in 'location': line 33, column 24, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n      #    - debug: var=vm_fact\n                       ^ here\n\nThere appears to be both 'k=v' shorthand syntax and YAML in this task. Only one syntax may be used.\n"}

Tried:


- debug:
    msg: "{{ vm_fact['results']|json_query('msg') }}"

- debug:
    msg: "{{ vm_fact['results']|to_json|from_json|map(attribute='msg') }}"

- debug:
    msg: "{{ vm_fact['results']|map(attribute='msg') }}"

- debug:
    msg: "{{ vm_fact['results']|dict2items|map(attribute='msg') }}"

- debug:
    msg: "{{ vm_fact['results']|flatten|map(attribute='msg') }}"

error:

TASK [debug] **************************************************************************************************************************
ok: [localhost] => {
    "msg": ""
}

TASK [debug] **************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'msg'\n\nThe error appears to be in 'location': line 42, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n    - debug:\n      ^ here\n"}
...ignoring

TASK [debug] **************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'msg'\n\nThe error appears to be in 'location': line 45, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n    - debug:\n      ^ here\n"}
...ignoring

TASK [debug] **************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{ vm_fact['results']|dict2items|map(attribute='msg') }}): dict2items requires a dictionary, got <class 'list'> instead."}
...ignoring

TASK [debug] **************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'msg'\n\nThe error appears to be in 'lcoation': line 51, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n    - debug:\n      ^ here\n"}
...ignoring

trainin99
  • 109
  • 10

1 Answers1

1

You are, frankly, making things very difficult for yourself. Ansible loops through hosts, use it.

decom.inv:

[decom]
vm1
vm2
vm3

decom.yml:

- name: check/power(on/off) hosts on vsphere
  hosts: decom
  gather_facts: no
  tasks:
  - name: check hosts on vsphere
    vmware_guest_info:
      hostname: "{{ vcenter_hostname }}"
      username: "{{ vcenter_username }}"
      password: "{{ vcenter_password }}"
      name: "{{ ansible_hostname }}"
      schema: vsphere
      datacenter: DC1
    register: vm_fact
    ignore_errors: True
    failed_when: false
    delegate_to: localhost

  - name: Show results
    debug:
      var: vm_fact
Jack
  • 5,801
  • 1
  • 15
  • 20
  • How is this relevant or helpful in a decommission scenario where vm's can be on,off,deleted? I need to pass through Vsphere to check whether the power is on/off and/if the vm is still existing. Looping through a host that is powered off or not on the infrastructure will not work, i believe. – trainin99 Dec 08 '22 at 15:25
  • 1
    It will work, so long as you have `gather_facts: no`, because you have `delegate_to: localhost`. The `debug` module is always run on `localhost`. – Jack Dec 12 '22 at 21:43