# Buggy code
def main():
    argument_spec = ovirt_full_argument_spec(
        state=dict(
            type="str",
            default="present",
            choices=[
                "absent",
                "next_run",
                "present",
                "registered",
                "running",
                "stopped",
                "suspended",
            ],
        ),
        name=dict(type="str"),
        id=dict(type="str"),
        cluster=dict(type="str"),
        allow_partial_import=dict(type="bool"),
        template=dict(type="str"),
        template_version=dict(type="int"),
        use_latest_template_version=dict(type="bool"),
        storage_domain=dict(type="str"),
        disk_format=dict(type="str", default="cow", choices=["cow", "raw"]),
        disks=dict(type="list", default=[]),
        memory=dict(type="str"),
        memory_guaranteed=dict(type="str"),
        memory_max=dict(type="str"),
        cpu_sockets=dict(type="int"),
        cpu_cores=dict(type="int"),
        cpu_shares=dict(type="int"),
        cpu_threads=dict(type="int"),
        type=dict(type="str", choices=["server", "desktop", "high_performance"]),
        operating_system=dict(type="str"),
        cd_iso=dict(type="str"),
        boot_devices=dict(type="list"),
        vnic_profile_mappings=dict(default=[], type="list"),
        cluster_mappings=dict(default=[], type="list"),
        role_mappings=dict(default=[], type="list"),
        affinity_group_mappings=dict(default=[], type="list"),
        affinity_label_mappings=dict(default=[], type="list"),
        lun_mappings=dict(default=[], type="list"),
        domain_mappings=dict(default=[], type="list"),
        reassign_bad_macs=dict(default=None, type="bool"),
        boot_menu=dict(type="bool"),
        serial_console=dict(type="bool"),
        usb_support=dict(type="bool"),
        sso=dict(type="bool"),
        quota_id=dict(type="str"),
        high_availability=dict(type="bool"),
        high_availability_priority=dict(type="int"),
        lease=dict(type="str"),
        stateless=dict(type="bool"),
        delete_protected=dict(type="bool"),
        force=dict(type="bool", default=False),
        nics=dict(type="list", default=[]),
        cloud_init=dict(type="dict"),
        cloud_init_nics=dict(type="list", default=[]),
        cloud_init_persist=dict(
            type="bool", default=False, aliases=["sysprep_persist"]
        ),
        sysprep=dict(type="dict"),
        host=dict(type="str"),
        clone=dict(type="bool", default=False),
        clone_permissions=dict(type="bool", default=False),
        kernel_path=dict(type="str"),
        initrd_path=dict(type="str"),
        kernel_params=dict(type="str"),
        instance_type=dict(type="str"),
        description=dict(type="str"),
        comment=dict(type="str"),
        timezone=dict(type="str"),
        serial_policy=dict(type="str", choices=["vm", "host", "custom"]),
        serial_policy_value=dict(type="str"),
        vmware=dict(type="dict"),
        xen=dict(type="dict"),
        kvm=dict(type="dict"),
        cpu_mode=dict(type="str"),
        placement_policy=dict(type="str"),
        cpu_pinning=dict(type="list"),
        soundcard_enabled=dict(type="bool", default=None),
        smartcard_enabled=dict(type="bool", default=None),
        io_threads=dict(type="int", default=None),
        ballooning_enabled=dict(type="bool", default=None),
        rng_device=dict(type="str"),
        numa_tune_mode=dict(type="str", choices=["interleave", "preferred", "strict"]),
        numa_nodes=dict(type="list", default=[]),
        custom_properties=dict(type="list"),
        watchdog=dict(type="dict"),
        graphical_console=dict(type="dict"),
    )
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_one_of=[["id", "name"]],
    )
    check_sdk(module)
    check_params(module)

    try:
        state = module.params["state"]
        auth = module.params.pop("auth")
        connection = create_connection(auth)
        vms_service = connection.system_service().vms_service()
        vms_module = VmsModule(
            connection=connection,
            module=module,
            service=vms_service,
        )
        vm = vms_module.search_entity(list_params={"all_content": True})

        control_state(vm, vms_service, module)
        if state in ("present", "running", "next_run"):
            if module.params["xen"] or module.params["kvm"] or module.params["vmware"]:
                vms_module.changed = import_vm(module, connection)

            # In case VM don't exist, wait for VM DOWN state,
            # otherwise don't wait for any state, just update VM:
            ret = vms_module.create(
                entity=vm,
                result_state=otypes.VmStatus.DOWN if vm is None else None,
                clone=module.params["clone"],
                clone_permissions=module.params["clone_permissions"],
            )
            vms_module.post_present(ret["id"])

            # Run the VM if it was just created, else don't run it:
            if state == "running":
                initialization = vms_module.get_initialization()
                ret = vms_module.action(
                    action="start",
                    post_action=vms_module._post_start_action,
                    action_condition=lambda vm: (
                        vm.status
                        not in [
                            otypes.VmStatus.MIGRATING,
                            otypes.VmStatus.POWERING_UP,
                            otypes.VmStatus.REBOOT_IN_PROGRESS,
                            otypes.VmStatus.WAIT_FOR_LAUNCH,
                            otypes.VmStatus.UP,
                            otypes.VmStatus.RESTORING_STATE,
                        ]
                    ),
                    wait_condition=lambda vm: vm.status == otypes.VmStatus.UP,
                    # Start action kwargs:
                    use_cloud_init=not module.params.get("cloud_init_persist")
                    and module.params.get("cloud_init") is not None,
                    use_sysprep=not module.params.get("cloud_init_persist")
                    and module.params.get("sysprep") is not None,
                    vm=otypes.Vm(
                        placement_policy=otypes.VmPlacementPolicy(
                            hosts=[otypes.Host(name=module.params["host"])]
                        )
                        if module.params["host"]
                        else None,
                        initialization=initialization,
                        os=otypes.OperatingSystem(
                            cmdline=module.params.get("kernel_params"),
                            initrd=module.params.get("initrd_path"),
                            kernel=module.params.get("kernel_path"),
                        )
                        if (
                            module.params.get("kernel_params")
                            or module.params.get("initrd_path")
                            or module.params.get("kernel_path")
                        )
                        else None,
                    )
                    if (
                        module.params.get("kernel_params")
                        or module.params.get("initrd_path")
                        or module.params.get("kernel_path")
                        or module.params.get("host")
                        or initialization is not None
                        and not module.params.get("cloud_init_persist")
                    )
                    else None,
                )

            if state == "next_run":
                # Apply next run configuration, if needed:
                vm = vms_service.vm_service(ret["id"]).get()
                if vm.next_run_configuration_exists:
                    ret = vms_module.action(
                        action="reboot",
                        entity=vm,
                        action_condition=lambda vm: vm.status == otypes.VmStatus.UP,
                        wait_condition=lambda vm: vm.status == otypes.VmStatus.UP,
                    )
            ret["changed"] = vms_module.changed
        elif state == "stopped":
            if module.params["xen"] or module.params["kvm"] or module.params["vmware"]:
                vms_module.changed = import_vm(module, connection)

            ret = vms_module.create(
                entity=vm,
                result_state=otypes.VmStatus.DOWN if vm is None else None,
                clone=module.params["clone"],
                clone_permissions=module.params["clone_permissions"],
            )
            vms_module.post_present(ret["id"])
            if module.params["force"]:
                ret = vms_module.action(
                    action="stop",
                    post_action=vms_module._attach_cd,
                    action_condition=lambda vm: vm.status != otypes.VmStatus.DOWN,
                    wait_condition=vms_module.wait_for_down,
                )
            else:
                ret = vms_module.action(
                    action="shutdown",
                    pre_action=vms_module._pre_shutdown_action,
                    post_action=vms_module._attach_cd,
                    action_condition=lambda vm: vm.status != otypes.VmStatus.DOWN,
                    wait_condition=vms_module.wait_for_down,
                )
        elif state == "suspended":
            vms_module.create(
                entity=vm,
                result_state=otypes.VmStatus.DOWN if vm is None else None,
                clone=module.params["clone"],
                clone_permissions=module.params["clone_permissions"],
            )
            vms_module.post_present(ret["id"])
            ret = vms_module.action(
                action="suspend",
                pre_action=vms_module._pre_suspend_action,
                action_condition=lambda vm: vm.status != otypes.VmStatus.SUSPENDED,
                wait_condition=lambda vm: vm.status == otypes.VmStatus.SUSPENDED,
            )
        elif state == "absent":
            ret = vms_module.remove()
        elif state == "registered":
            storage_domains_service = (
                connection.system_service().storage_domains_service()
            )

            # Find the storage domain with unregistered VM:
            sd_id = get_id_by_name(
                storage_domains_service, module.params["storage_domain"]
            )
            storage_domain_service = storage_domains_service.storage_domain_service(
                sd_id
            )
            vms_service = storage_domain_service.vms_service()

            # Find the the unregistered VM we want to register:
            vms = vms_service.list(unregistered=True)
            vm = next(
                (
                    vm
                    for vm in vms
                    if (
                        vm.id == module.params["id"] or vm.name == module.params["name"]
                    )
                ),
                None,
            )
            changed = False
            if vm is None:
                vm = vms_module.search_entity()
                if vm is None:
                    raise ValueError(
                        "VM '%s(%s)' wasn't found."
                        % (module.params["name"], module.params["id"])
                    )
            else:
                # Register the vm into the system:
                changed = True
                vm_service = vms_service.vm_service(vm.id)
                vm_service.register(
                    allow_partial_import=module.params["allow_partial_import"],
                    cluster=otypes.Cluster(name=module.params["cluster"])
                    if module.params["cluster"]
                    else None,
                    vnic_profile_mappings=_get_vnic_profile_mappings(module)
                    if module.params["vnic_profile_mappings"]
                    else None,
                    reassign_bad_macs=module.params["reassign_bad_macs"]
                    if module.params["reassign_bad_macs"] is not None
                    else None,
                    registration_configuration=otypes.RegistrationConfiguration(
                        cluster_mappings=_get_cluster_mappings(module),
                        role_mappings=_get_role_mappings(module),
                        domain_mappings=_get_domain_mappings(module),
                        lun_mappings=_get_lun_mappings(module),
                        affinity_group_mappings=_get_affinity_group_mappings(module),
                        affinity_label_mappings=_get_affinity_label_mappings(module),
                    )
                    if (
                        module.params["cluster_mappings"]
                        or module.params["role_mappings"]
                        or module.params["domain_mappings"]
                        or module.params["lun_mappings"]
                        or module.params["affinity_group_mappings"]
                        or module.params["affinity_label_mappings"]
                    )
                    else None,
                )

                if module.params["wait"]:
                    vm = vms_module.wait_for_import()
                else:
                    # Fetch vm to initialize return.
                    vm = vm_service.get()
            ret = {"changed": changed, "id": vm.id, "vm": get_dict_of_struct(vm)}

        module.exit_json(**ret)
    except Exception as e:
        module.fail_json(msg=str(e), exception=traceback.format_exc())
    finally:
        connection.close(logout=auth.get("token") is None)


# Traceback (AttributeError)
$ ansible-playbook -vvvv -i inventory/hosts site.yml --check
ansible-playbook 2.4.3.0
config file = None
configured module search path = [u'/Users/mvrgotic/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python2.7/site-packages/ansible
executable location = /usr/local/bin/ansible-playbook
python version = 2.7.14 (default, Feb  6 2018, 20:04:00) [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)]
No config file found; using defaults
setting up inventory plugins
Set default localhost to localhost
Parsed /Users/mvrgotic/Git/awesome-ovirt-platform/playbooks/awesome-2113-lab-scsk/ovirt_vms/inventory/hosts inventory source with ini plugin
Loading callback plugin default of type stdout, v2.0 from /usr/local/lib/python2.7/site-packages/ansible/plugins/callback/default.pyc

PLAYBOOK: site.yml ******************************************************************************************************************************************************************
1 plays in site.yml
Read vars_file 'passwords.yml'
Read vars_file 'passwords.yml'

PLAY [Spawn VM Guest(s) in Awesome] *************************************************************************************************************************************************
Read vars_file 'passwords.yml'

TASK [Login to oVirt] ***************************************************************************************************************************************************************
task path: /Users/mvrgotic/Git/awesome-ovirt-platform/playbooks/awesome-2113-lab-scsk/ovirt_vms/spawn-ovirt-vms.yml:16
Using module file /usr/local/lib/python2.7/site-packages/ansible/modules/cloud/ovirt/ovirt_auth.py
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: mvrgotic
<localhost> EXEC /bin/sh -c 'echo ~ &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 &amp;&amp; mkdir -p "` echo /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632255.36-166348216953816 `" &amp;&amp; echo ansible-tmp-1519632255.36-166348216953816="` echo /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632255.36-166348216953816 `" ) &amp;&amp; sleep 0'
<localhost> PUT /var/folders/wm/k9rx7dw951x46dzqsrs30kmr0000gn/T/tmpNpEerq TO /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632255.36-166348216953816/ovirt_auth.py
<localhost> EXEC /bin/sh -c 'chmod u+x /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632255.36-166348216953816/ /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632255.36-166348216953816/ovirt_auth.py &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632255.36-166348216953816/ovirt_auth.py; rm -rf "/Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632255.36-166348216953816/" > /dev/null 2>&amp;1 &amp;&amp; sleep 0'
ok: [localhost] => {
"ansible_facts": {
"ovirt_auth": {
"ca_file": null,
"compress": true,
"headers": null,
"insecure": true,
"kerberos": false,
"timeout": 0,
"token": "pNn-IczUx4yF9aVZlIei-mdfCcCV-KkOaveX3D99yBlMRlecQZajVAjAwyx8eNGzh6vX0TXWwn4XJZ77RI3DRw",
"url": "https://aws-engine-01.avinity.tv/ovirt-engine/api"
}
},
"changed": false,
"invocation": {
"module_args": {
"ca_file": null,
"compress": true,
"headers": null,
"insecure": true,
"kerberos": false,
"ovirt_auth": null,
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"state": "present",
"timeout": 0,
"url": "https://aws-engine-01.avinity.tv/ovirt-engine/api",
"username": "admin@internal"
}
}
}
META: ran handlers
Read vars_file 'passwords.yml'

TASK [Spawning oVirt VM Guest(s) from 01-S-CentOS-72-20180214v1] ********************************************************************************************************************
task path: /Users/mvrgotic/Git/awesome-ovirt-platform/playbooks/awesome-2113-lab-scsk/ovirt_vms/spawn-ovirt-vms.yml:25
Using module file /usr/local/lib/python2.7/site-packages/ansible/modules/cloud/ovirt/ovirt_vms.py
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: mvrgotic
<localhost> EXEC /bin/sh -c 'echo ~ &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 &amp;&amp; mkdir -p "` echo /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.01-204625682216668 `" &amp;&amp; echo ansible-tmp-1519632256.01-204625682216668="` echo /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.01-204625682216668 `" ) &amp;&amp; sleep 0'
<localhost> PUT /var/folders/wm/k9rx7dw951x46dzqsrs30kmr0000gn/T/tmpLCwudA TO /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.01-204625682216668/ovirt_vms.py
<localhost> EXEC /bin/sh -c 'chmod u+x /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.01-204625682216668/ /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.01-204625682216668/ovirt_vms.py &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.01-204625682216668/ovirt_vms.py; rm -rf "/Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.01-204625682216668/" > /dev/null 2>&amp;1 &amp;&amp; sleep 0'
The full traceback is:
Traceback (most recent call last):
File "/var/folders/wm/k9rx7dw951x46dzqsrs30kmr0000gn/T/ansible_mOXdyO/ansible_module_ovirt_vms.py", line 1201, in main
clone_permissions=module.params['clone_permissions'],
File "/var/folders/wm/k9rx7dw951x46dzqsrs30kmr0000gn/T/ansible_mOXdyO/ansible_modlib.zip/ansible/module_utils/ovirt.py", line 580, in create
entity_service = self._service.service(entity.id)
AttributeError: 'NoneType' object has no attribute 'id'

failed: [localhost] (item=scsk2113csm1) => {
"changed": false,
"invocation": {
"module_args": {
"allow_partial_import": null,
"boot_devices": null,
"cd_iso": null,
"clone": false,
"clone_permissions": false,
"cloud_init": {
"host_name": "scsk2113csm1"
},
"cloud_init_nics": null,
"cluster": "AWSEUOPS",
"comment": null,
"cpu_cores": null,
"cpu_shares": null,
"cpu_sockets": null,
"delete_protected": null,
"description": null,
"disk_format": "cow",
"disks": [],
"fetch_nested": false,
"force": false,
"high_availability": null,
"host": null,
"id": null,
"initrd_path": null,
"instance_type": null,
"kernel_params": null,
"kernel_path": null,
"kvm": null,
"lease": null,
"memory": null,
"memory_guaranteed": null,
"name": "scsk2113csm1",
"nested_attributes": [],
"nics": [],
"operating_system": null,
"poll_interval": 3,
"serial_policy": null,
"serial_policy_value": null,
"state": "present",
"stateless": null,
"storage_domain": null,
"sysprep": null,
"template": "01-S-CentOS-72-20180214v1",
"template_version": null,
"timeout": 180,
"timezone": null,
"type": null,
"use_latest_template_version": null,
"vmware": null,
"wait": true,
"xen": null
}
},
"item": "scsk2113csm1",
"msg": "'NoneType' object has no attribute 'id'"
}
Using module file /usr/local/lib/python2.7/site-packages/ansible/modules/cloud/ovirt/ovirt_vms.py
<localhost> EXEC /bin/sh -c 'echo ~ &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 &amp;&amp; mkdir -p "` echo /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.62-247808153224737 `" &amp;&amp; echo ansible-tmp-1519632256.62-247808153224737="` echo /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.62-247808153224737 `" ) &amp;&amp; sleep 0'
<localhost> PUT /var/folders/wm/k9rx7dw951x46dzqsrs30kmr0000gn/T/tmpfVCef6 TO /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.62-247808153224737/ovirt_vms.py
<localhost> EXEC /bin/sh -c 'chmod u+x /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.62-247808153224737/ /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.62-247808153224737/ovirt_vms.py &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.62-247808153224737/ovirt_vms.py; rm -rf "/Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632256.62-247808153224737/" > /dev/null 2>&amp;1 &amp;&amp; sleep 0'
The full traceback is:
Traceback (most recent call last):
File "/var/folders/wm/k9rx7dw951x46dzqsrs30kmr0000gn/T/ansible_W3df8w/ansible_module_ovirt_vms.py", line 1201, in main
clone_permissions=module.params['clone_permissions'],
File "/var/folders/wm/k9rx7dw951x46dzqsrs30kmr0000gn/T/ansible_W3df8w/ansible_modlib.zip/ansible/module_utils/ovirt.py", line 580, in create
entity_service = self._service.service(entity.id)
AttributeError: 'NoneType' object has no attribute 'id'

failed: [localhost] (item=scsk2113csm2) => {
"changed": false,
"invocation": {
"module_args": {
"allow_partial_import": null,
"boot_devices": null,
"cd_iso": null,
"clone": false,
"clone_permissions": false,
"cloud_init": {
"host_name": "scsk2113csm2"
},
"cloud_init_nics": null,
"cluster": "AWSEUOPS",
"comment": null,
"cpu_cores": null,
"cpu_shares": null,
"cpu_sockets": null,
"delete_protected": null,
"description": null,
"disk_format": "cow",
"disks": [],
"fetch_nested": false,
"force": false,
"high_availability": null,
"host": null,
"id": null,
"initrd_path": null,
"instance_type": null,
"kernel_params": null,
"kernel_path": null,
"kvm": null,
"lease": null,
"memory": null,
"memory_guaranteed": null,
"name": "scsk2113csm2",
"nested_attributes": [],
"nics": [],
"operating_system": null,
"poll_interval": 3,
"serial_policy": null,
"serial_policy_value": null,
"state": "present",
"stateless": null,
"storage_domain": null,
"sysprep": null,
"template": "01-S-CentOS-72-20180214v1",
"template_version": null,
"timeout": 180,
"timezone": null,
"type": null,
"use_latest_template_version": null,
"vmware": null,
"wait": true,
"xen": null
}
},
"item": "scsk2113csm2",
"msg": "'NoneType' object has no attribute 'id'"
}
Using module file /usr/local/lib/python2.7/site-packages/ansible/modules/cloud/ovirt/ovirt_vms.py
<localhost> EXEC /bin/sh -c 'echo ~ &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 &amp;&amp; mkdir -p "` echo /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632257.17-74238433490364 `" &amp;&amp; echo ansible-tmp-1519632257.17-74238433490364="` echo /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632257.17-74238433490364 `" ) &amp;&amp; sleep 0'
<localhost> PUT /var/folders/wm/k9rx7dw951x46dzqsrs30kmr0000gn/T/tmpOuoGrk TO /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632257.17-74238433490364/ovirt_vms.py
<localhost> EXEC /bin/sh -c 'chmod u+x /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632257.17-74238433490364/ /Users/mvrgotic/.ansible/tmp/ansible-tmp-1519632257.17-74238433490364/ovirt_vms.py &amp;&amp; sleep 0'
^C [ERROR]: User interrupted execution

# Fixed code
def main():
    argument_spec = ovirt_full_argument_spec(
        state=dict(
            type="str",
            default="present",
            choices=[
                "absent",
                "next_run",
                "present",
                "registered",
                "running",
                "stopped",
                "suspended",
            ],
        ),
        name=dict(type="str"),
        id=dict(type="str"),
        cluster=dict(type="str"),
        allow_partial_import=dict(type="bool"),
        template=dict(type="str"),
        template_version=dict(type="int"),
        use_latest_template_version=dict(type="bool"),
        storage_domain=dict(type="str"),
        disk_format=dict(type="str", default="cow", choices=["cow", "raw"]),
        disks=dict(type="list", default=[]),
        memory=dict(type="str"),
        memory_guaranteed=dict(type="str"),
        memory_max=dict(type="str"),
        cpu_sockets=dict(type="int"),
        cpu_cores=dict(type="int"),
        cpu_shares=dict(type="int"),
        cpu_threads=dict(type="int"),
        type=dict(type="str", choices=["server", "desktop", "high_performance"]),
        operating_system=dict(type="str"),
        cd_iso=dict(type="str"),
        boot_devices=dict(type="list"),
        vnic_profile_mappings=dict(default=[], type="list"),
        cluster_mappings=dict(default=[], type="list"),
        role_mappings=dict(default=[], type="list"),
        affinity_group_mappings=dict(default=[], type="list"),
        affinity_label_mappings=dict(default=[], type="list"),
        lun_mappings=dict(default=[], type="list"),
        domain_mappings=dict(default=[], type="list"),
        reassign_bad_macs=dict(default=None, type="bool"),
        boot_menu=dict(type="bool"),
        serial_console=dict(type="bool"),
        usb_support=dict(type="bool"),
        sso=dict(type="bool"),
        quota_id=dict(type="str"),
        high_availability=dict(type="bool"),
        high_availability_priority=dict(type="int"),
        lease=dict(type="str"),
        stateless=dict(type="bool"),
        delete_protected=dict(type="bool"),
        force=dict(type="bool", default=False),
        nics=dict(type="list", default=[]),
        cloud_init=dict(type="dict"),
        cloud_init_nics=dict(type="list", default=[]),
        cloud_init_persist=dict(
            type="bool", default=False, aliases=["sysprep_persist"]
        ),
        sysprep=dict(type="dict"),
        host=dict(type="str"),
        clone=dict(type="bool", default=False),
        clone_permissions=dict(type="bool", default=False),
        kernel_path=dict(type="str"),
        initrd_path=dict(type="str"),
        kernel_params=dict(type="str"),
        instance_type=dict(type="str"),
        description=dict(type="str"),
        comment=dict(type="str"),
        timezone=dict(type="str"),
        serial_policy=dict(type="str", choices=["vm", "host", "custom"]),
        serial_policy_value=dict(type="str"),
        vmware=dict(type="dict"),
        xen=dict(type="dict"),
        kvm=dict(type="dict"),
        cpu_mode=dict(type="str"),
        placement_policy=dict(type="str"),
        cpu_pinning=dict(type="list"),
        soundcard_enabled=dict(type="bool", default=None),
        smartcard_enabled=dict(type="bool", default=None),
        io_threads=dict(type="int", default=None),
        ballooning_enabled=dict(type="bool", default=None),
        rng_device=dict(type="str"),
        numa_tune_mode=dict(type="str", choices=["interleave", "preferred", "strict"]),
        numa_nodes=dict(type="list", default=[]),
        custom_properties=dict(type="list"),
        watchdog=dict(type="dict"),
        graphical_console=dict(type="dict"),
    )
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_one_of=[["id", "name"]],
    )
    check_sdk(module)
    check_params(module)

    try:
        state = module.params["state"]
        auth = module.params.pop("auth")
        connection = create_connection(auth)
        vms_service = connection.system_service().vms_service()
        vms_module = VmsModule(
            connection=connection,
            module=module,
            service=vms_service,
        )
        vm = vms_module.search_entity(list_params={"all_content": True})

        control_state(vm, vms_service, module)
        if state in ("present", "running", "next_run"):
            if module.params["xen"] or module.params["kvm"] or module.params["vmware"]:
                vms_module.changed = import_vm(module, connection)

            # In case VM don't exist, wait for VM DOWN state,
            # otherwise don't wait for any state, just update VM:
            ret = vms_module.create(
                entity=vm,
                result_state=otypes.VmStatus.DOWN if vm is None else None,
                clone=module.params["clone"],
                clone_permissions=module.params["clone_permissions"],
            )
            # If VM is going to be created and check_mode is on, return now:
            if module.check_mode and ret.get("id") is None:
                module.exit_json(**ret)

            vms_module.post_present(ret["id"])
            # Run the VM if it was just created, else don't run it:
            if state == "running":
                initialization = vms_module.get_initialization()
                ret = vms_module.action(
                    action="start",
                    post_action=vms_module._post_start_action,
                    action_condition=lambda vm: (
                        vm.status
                        not in [
                            otypes.VmStatus.MIGRATING,
                            otypes.VmStatus.POWERING_UP,
                            otypes.VmStatus.REBOOT_IN_PROGRESS,
                            otypes.VmStatus.WAIT_FOR_LAUNCH,
                            otypes.VmStatus.UP,
                            otypes.VmStatus.RESTORING_STATE,
                        ]
                    ),
                    wait_condition=lambda vm: vm.status == otypes.VmStatus.UP,
                    # Start action kwargs:
                    use_cloud_init=not module.params.get("cloud_init_persist")
                    and module.params.get("cloud_init") is not None,
                    use_sysprep=not module.params.get("cloud_init_persist")
                    and module.params.get("sysprep") is not None,
                    vm=otypes.Vm(
                        placement_policy=otypes.VmPlacementPolicy(
                            hosts=[otypes.Host(name=module.params["host"])]
                        )
                        if module.params["host"]
                        else None,
                        initialization=initialization,
                        os=otypes.OperatingSystem(
                            cmdline=module.params.get("kernel_params"),
                            initrd=module.params.get("initrd_path"),
                            kernel=module.params.get("kernel_path"),
                        )
                        if (
                            module.params.get("kernel_params")
                            or module.params.get("initrd_path")
                            or module.params.get("kernel_path")
                        )
                        else None,
                    )
                    if (
                        module.params.get("kernel_params")
                        or module.params.get("initrd_path")
                        or module.params.get("kernel_path")
                        or module.params.get("host")
                        or initialization is not None
                        and not module.params.get("cloud_init_persist")
                    )
                    else None,
                )

            if state == "next_run":
                # Apply next run configuration, if needed:
                vm = vms_service.vm_service(ret["id"]).get()
                if vm.next_run_configuration_exists:
                    ret = vms_module.action(
                        action="reboot",
                        entity=vm,
                        action_condition=lambda vm: vm.status == otypes.VmStatus.UP,
                        wait_condition=lambda vm: vm.status == otypes.VmStatus.UP,
                    )
            ret["changed"] = vms_module.changed
        elif state == "stopped":
            if module.params["xen"] or module.params["kvm"] or module.params["vmware"]:
                vms_module.changed = import_vm(module, connection)

            ret = vms_module.create(
                entity=vm,
                result_state=otypes.VmStatus.DOWN if vm is None else None,
                clone=module.params["clone"],
                clone_permissions=module.params["clone_permissions"],
            )
            vms_module.post_present(ret["id"])
            if module.params["force"]:
                ret = vms_module.action(
                    action="stop",
                    post_action=vms_module._attach_cd,
                    action_condition=lambda vm: vm.status != otypes.VmStatus.DOWN,
                    wait_condition=vms_module.wait_for_down,
                )
            else:
                ret = vms_module.action(
                    action="shutdown",
                    pre_action=vms_module._pre_shutdown_action,
                    post_action=vms_module._attach_cd,
                    action_condition=lambda vm: vm.status != otypes.VmStatus.DOWN,
                    wait_condition=vms_module.wait_for_down,
                )
        elif state == "suspended":
            vms_module.create(
                entity=vm,
                result_state=otypes.VmStatus.DOWN if vm is None else None,
                clone=module.params["clone"],
                clone_permissions=module.params["clone_permissions"],
            )
            vms_module.post_present(ret["id"])
            ret = vms_module.action(
                action="suspend",
                pre_action=vms_module._pre_suspend_action,
                action_condition=lambda vm: vm.status != otypes.VmStatus.SUSPENDED,
                wait_condition=lambda vm: vm.status == otypes.VmStatus.SUSPENDED,
            )
        elif state == "absent":
            ret = vms_module.remove()
        elif state == "registered":
            storage_domains_service = (
                connection.system_service().storage_domains_service()
            )

            # Find the storage domain with unregistered VM:
            sd_id = get_id_by_name(
                storage_domains_service, module.params["storage_domain"]
            )
            storage_domain_service = storage_domains_service.storage_domain_service(
                sd_id
            )
            vms_service = storage_domain_service.vms_service()

            # Find the the unregistered VM we want to register:
            vms = vms_service.list(unregistered=True)
            vm = next(
                (
                    vm
                    for vm in vms
                    if (
                        vm.id == module.params["id"] or vm.name == module.params["name"]
                    )
                ),
                None,
            )
            changed = False
            if vm is None:
                vm = vms_module.search_entity()
                if vm is None:
                    raise ValueError(
                        "VM '%s(%s)' wasn't found."
                        % (module.params["name"], module.params["id"])
                    )
            else:
                # Register the vm into the system:
                changed = True
                vm_service = vms_service.vm_service(vm.id)
                vm_service.register(
                    allow_partial_import=module.params["allow_partial_import"],
                    cluster=otypes.Cluster(name=module.params["cluster"])
                    if module.params["cluster"]
                    else None,
                    vnic_profile_mappings=_get_vnic_profile_mappings(module)
                    if module.params["vnic_profile_mappings"]
                    else None,
                    reassign_bad_macs=module.params["reassign_bad_macs"]
                    if module.params["reassign_bad_macs"] is not None
                    else None,
                    registration_configuration=otypes.RegistrationConfiguration(
                        cluster_mappings=_get_cluster_mappings(module),
                        role_mappings=_get_role_mappings(module),
                        domain_mappings=_get_domain_mappings(module),
                        lun_mappings=_get_lun_mappings(module),
                        affinity_group_mappings=_get_affinity_group_mappings(module),
                        affinity_label_mappings=_get_affinity_label_mappings(module),
                    )
                    if (
                        module.params["cluster_mappings"]
                        or module.params["role_mappings"]
                        or module.params["domain_mappings"]
                        or module.params["lun_mappings"]
                        or module.params["affinity_group_mappings"]
                        or module.params["affinity_label_mappings"]
                    )
                    else None,
                )

                if module.params["wait"]:
                    vm = vms_module.wait_for_import()
                else:
                    # Fetch vm to initialize return.
                    vm = vm_service.get()
            ret = {"changed": changed, "id": vm.id, "vm": get_dict_of_struct(vm)}

        module.exit_json(**ret)
    except Exception as e:
        module.fail_json(msg=str(e), exception=traceback.format_exc())
    finally:
        connection.close(logout=auth.get("token") is None)