# Buggy code
def create(
    self,
    entity=None,
    result_state=None,
    fail_condition=lambda e: False,
    search_params=None,
    update_params=None,
    **kwargs,
):
    """
    Method which is called when state of the entity is 'present'. If user
    don't provide `entity` parameter the entity is searched using
    `search_params` parameter. If entity is found it's updated, whether
    the entity should be updated is checked by `update_check` method.
    The corresponding updated entity is build by `build_entity` method.

    Function executed after entity is created can optionally be specified
    in `post_create` parameter. Function executed after entity is updated
    can optionally be specified in `post_update` parameter.

    :param entity: Entity we want to update, if exists.
    :param result_state: State which should entity has in order to finish task.
    :param fail_condition: Function which checks incorrect state of entity, if it returns `True` Exception is raised.
    :param search_params: Dictionary of parameters to be used for search.
    :param update_params: The params which should be passed to update method.
    :param kwargs: Additional parameters passed when creating entity.
    :return: Dictionary with values returned by Ansible module.
    """
    if entity is None:
        entity = self.search_entity(search_params)

    self.pre_create(entity)

    if entity:
        # Entity exists, so update it:
        entity_service = self._service.service(entity.id)
        if not self.update_check(entity):
            new_entity = self.build_entity()
            if not self._module.check_mode:
                update_params = update_params or {}
                updated_entity = entity_service.update(new_entity, **update_params)
                self.post_update(entity)

            # Update diffs only if user specified --diff parameter,
            # so we don't useless overload API:
            if self._module._diff:
                before = get_dict_of_struct(
                    entity,
                    self._connection,
                    fetch_nested=True,
                    attributes=["name"],
                )
                after = before.copy()
                self.diff_update(after, get_dict_of_struct(new_entity))
                self._diff["before"] = before
                self._diff["after"] = after

            self.changed = True
    else:
        # Entity don't exists, so create it:
        if not self._module.check_mode:
            entity = self._service.add(self.build_entity(), **kwargs)
            self.post_create(entity)
        self.changed = True

    if not self._module.check_mode:
        # Wait for the entity to be created and to be in the defined state:
        entity_service = self._service.service(entity.id)

        def state_condition(entity):
            return entity

        if result_state:

            def state_condition(entity):
                return entity and entity.status == result_state

        wait(
            service=entity_service,
            condition=state_condition,
            fail_condition=fail_condition,
            wait=self._module.params["wait"],
            timeout=self._module.params["timeout"],
            poll_interval=self._module.params["poll_interval"],
        )

    return {
        "changed": self.changed,
        "id": getattr(entity, "id", None),
        type(entity).__name__.lower(): get_dict_of_struct(
            struct=entity,
            connection=self._connection,
            fetch_nested=self._module.params.get("fetch_nested"),
            attributes=self._module.params.get("nested_attributes"),
        ),
        "diff": self._diff,
    }


# Traceback (_raise_error)
[dieter@localhost test]$ ansible-playbook test.yml -vvvv
ansible-playbook 2.7.2
config file = /home/dieter/test/ansible.cfg
configured module search path = ['/home/dieter/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.7/site-packages/ansible
executable location = /usr/bin/ansible-playbook
python version = 3.7.1 (default, Nov 23 2018, 10:01:49) [GCC 8.2.1 20181105 (Red Hat 8.2.1-5)]
Using /home/dieter/test/ansible.cfg as config file
setting up inventory plugins
/home/dieter/test/inventory did not meet host_list requirements, check plugin documentation if this is unexpected
/home/dieter/test/inventory did not meet script requirements, check plugin documentation if this is unexpected
Set default localhost to localhost
Parsed /home/dieter/test/inventory inventory source with ini plugin
Loading callback plugin yaml of type stdout, v2.0 from /usr/lib/python3.7/site-packages/ansible/plugins/callback/yaml.py

PLAYBOOK: test.yml ************************************************************************************************************************************************************************************************
1 plays in test.yml

PLAY [localhost] **************************************************************************************************************************************************************************************************
META: ran handlers

TASK [Obtain SSO token with using username/password credentials] **************************************************************************************************************************************************
task path: /home/dieter/test/test.yml:4
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: dieter
<localhost> EXEC /bin/sh -c 'echo ~dieter &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 &amp;&amp; mkdir -p "` echo /home/dieter/.ansible/tmp/ansible-tmp-1543997181.0548651-245440093272297 `" &amp;&amp; echo ansible-tmp-1543997181.0548651-245440093272297="` echo /home/dieter/.ansible/tmp/ansible-tmp-1543997181.0548651-245440093272297 `" ) &amp;&amp; sleep 0'
Using module file /usr/lib/python3.7/site-packages/ansible/modules/cloud/ovirt/ovirt_auth.py
<localhost> PUT /home/dieter/.ansible/tmp/ansible-local-13341d5brgvhh/tmpxqupj_mt TO /home/dieter/.ansible/tmp/ansible-tmp-1543997181.0548651-245440093272297/AnsiballZ_ovirt_auth.py
<localhost> EXEC /bin/sh -c 'chmod u+x /home/dieter/.ansible/tmp/ansible-tmp-1543997181.0548651-245440093272297/ /home/dieter/.ansible/tmp/ansible-tmp-1543997181.0548651-245440093272297/AnsiballZ_ovirt_auth.py &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /home/dieter/.ansible/tmp/ansible-tmp-1543997181.0548651-245440093272297/AnsiballZ_ovirt_auth.py &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /home/dieter/.ansible/tmp/ansible-tmp-1543997181.0548651-245440093272297/ > /dev/null 2>&amp;1 &amp;&amp; sleep 0'
ok: [localhost] => changed=false
ansible_facts:
ovirt_auth:
ca_file: null
compress: true
headers: null
insecure: true
kerberos: false
timeout: 0
token: Or3g1nm3gQGN2d2dq8PkDBKw15f1nSSDAOwZ94Pd35OFdYTqByIE_MRSe5R1KWYbhYhBXw7NxZyA7UCis1gj6w
url: *****
invocation:
module_args:
ca_file: null
compress: true
headers: null
hostname: null
insecure: true
kerberos: false
ovirt_auth: null
password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER
state: present
timeout: 0
token: null
url: *****
username: admin@internal

TASK [Create virtual machine] *************************************************************************************************************************************************************************************
task path: /home/dieter/test/test.yml:11
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: dieter
<localhost> EXEC /bin/sh -c 'echo ~dieter &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 &amp;&amp; mkdir -p "` echo /home/dieter/.ansible/tmp/ansible-tmp-1543997181.4379315-226070906750108 `" &amp;&amp; echo ansible-tmp-1543997181.4379315-226070906750108="` echo /home/dieter/.ansible/tmp/ansible-tmp-1543997181.4379315-226070906750108 `" ) &amp;&amp; sleep 0'
Using module file /usr/lib/python3.7/site-packages/ansible/modules/cloud/ovirt/ovirt_vm.py
<localhost> PUT /home/dieter/.ansible/tmp/ansible-local-13341d5brgvhh/tmpihb56uyu TO /home/dieter/.ansible/tmp/ansible-tmp-1543997181.4379315-226070906750108/AnsiballZ_ovirt_vm.py
<localhost> EXEC /bin/sh -c 'chmod u+x /home/dieter/.ansible/tmp/ansible-tmp-1543997181.4379315-226070906750108/ /home/dieter/.ansible/tmp/ansible-tmp-1543997181.4379315-226070906750108/AnsiballZ_ovirt_vm.py &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /home/dieter/.ansible/tmp/ansible-tmp-1543997181.4379315-226070906750108/AnsiballZ_ovirt_vm.py &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /home/dieter/.ansible/tmp/ansible-tmp-1543997181.4379315-226070906750108/ > /dev/null 2>&amp;1 &amp;&amp; sleep 0'
The full traceback is:
Traceback (most recent call last):
File "/tmp/ansible_ovirt_vm_payload_1RD2Er/__main__.py", line 2071, in main
) else None,
File "/tmp/ansible_ovirt_vm_payload_1RD2Er/ansible_ovirt_vm_payload.zip/ansible/module_utils/ovirt.py", line 738, in action
getattr(entity_service, action)(**kwargs)
File "/usr/lib64/python2.7/site-packages/ovirtsdk4/services.py", line 30176, in start
return self._internal_action(action, 'start', None, headers, query, wait)
File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 299, in _internal_action
return future.wait() if wait else future
File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 55, in wait
return self._code(response)
File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 296, in callback
self._check_fault(response)
File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 134, in _check_fault
self._raise_error(response, body.fault)
File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 118, in _raise_error
raise error
Error: Fault reason is "Operation Failed". Fault detail is "[Cannot run VM: VM is locked. Please try again in a few minutes.]". HTTP response code is 409.

fatal: [localhost]: FAILED! => changed=false
invocation:
module_args:
affinity_group_mappings: []
affinity_label_mappings: []
allow_partial_import: null
ballooning_enabled: null
boot_devices: null
boot_menu: null
cd_iso: null
clone: false
clone_permissions: false
cloud_init: null
cloud_init_nics: []
cloud_init_persist: false
cluster: Default
cluster_mappings: []
comment: null
cpu_cores: 2
cpu_mode: null
cpu_pinning: null
cpu_shares: null
cpu_sockets: 1
cpu_threads: null
custom_compatibility_version: null
custom_properties: null
delete_protected: null
description: null
disk_format: cow
disks: []
domain_mappings: []
fetch_nested: false
force: false
graphical_console: null
high_availability: false
high_availability_priority: null
host: null
host_devices: null
id: null
initrd_path: null
instance_type: null
io_threads: null
kernel_params: null
kernel_path: null
kvm: null
lease: null
lun_mappings: []
memory: 4GiB
memory_guaranteed: 4GiB
memory_max: 16GiB
name: myvm
nested_attributes: []
nics: []
numa_nodes: []
numa_tune_mode: null
operating_system: null
placement_policy: null
poll_interval: 3
quota_id: null
reassign_bad_macs: null
rng_device: null
role_mappings: []
serial_console: null
serial_policy: null
serial_policy_value: null
smartcard_enabled: null
soundcard_enabled: null
sso: null
state: running
stateless: null
storage_domain: null
sysprep: null
template: rhel7.5-template_2
template_version: null
ticket: null
timeout: 180
timezone: null
type: null
usb_support: null
use_latest_template_version: null
vmware: null
vnic_profile_mappings: []
wait: false
watchdog: null
xen: null
msg: 'Fault reason is "Operation Failed". Fault detail is "[Cannot run VM: VM is locked. Please try again in a few minutes.]". HTTP response code is 409.'
to retry, use: --limit @/home/dieter/test/test.retry

PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1

# Fixed code
def create(
    self,
    entity=None,
    result_state=None,
    fail_condition=lambda e: False,
    search_params=None,
    update_params=None,
    _wait=None,
    **kwargs,
):
    """
    Method which is called when state of the entity is 'present'. If user
    don't provide `entity` parameter the entity is searched using
    `search_params` parameter. If entity is found it's updated, whether
    the entity should be updated is checked by `update_check` method.
    The corresponding updated entity is build by `build_entity` method.

    Function executed after entity is created can optionally be specified
    in `post_create` parameter. Function executed after entity is updated
    can optionally be specified in `post_update` parameter.

    :param entity: Entity we want to update, if exists.
    :param result_state: State which should entity has in order to finish task.
    :param fail_condition: Function which checks incorrect state of entity, if it returns `True` Exception is raised.
    :param search_params: Dictionary of parameters to be used for search.
    :param update_params: The params which should be passed to update method.
    :param kwargs: Additional parameters passed when creating entity.
    :return: Dictionary with values returned by Ansible module.
    """
    if entity is None:
        entity = self.search_entity(search_params)

    self.pre_create(entity)

    if entity:
        # Entity exists, so update it:
        entity_service = self._service.service(entity.id)
        if not self.update_check(entity):
            new_entity = self.build_entity()
            if not self._module.check_mode:
                update_params = update_params or {}
                updated_entity = entity_service.update(new_entity, **update_params)
                self.post_update(entity)

            # Update diffs only if user specified --diff parameter,
            # so we don't useless overload API:
            if self._module._diff:
                before = get_dict_of_struct(
                    entity,
                    self._connection,
                    fetch_nested=True,
                    attributes=["name"],
                )
                after = before.copy()
                self.diff_update(after, get_dict_of_struct(new_entity))
                self._diff["before"] = before
                self._diff["after"] = after

            self.changed = True
    else:
        # Entity don't exists, so create it:
        if not self._module.check_mode:
            entity = self._service.add(self.build_entity(), **kwargs)
            self.post_create(entity)
        self.changed = True

    if not self._module.check_mode:
        # Wait for the entity to be created and to be in the defined state:
        entity_service = self._service.service(entity.id)

        def state_condition(entity):
            return entity

        if result_state:

            def state_condition(entity):
                return entity and entity.status == result_state

        wait(
            service=entity_service,
            condition=state_condition,
            fail_condition=fail_condition,
            wait=_wait if _wait is not None else self._module.params["wait"],
            timeout=self._module.params["timeout"],
            poll_interval=self._module.params["poll_interval"],
        )

    return {
        "changed": self.changed,
        "id": getattr(entity, "id", None),
        type(entity).__name__.lower(): get_dict_of_struct(
            struct=entity,
            connection=self._connection,
            fetch_nested=self._module.params.get("fetch_nested"),
            attributes=self._module.params.get("nested_attributes"),
        ),
        "diff": self._diff,
    }