# Buggy code
def core(module):
    state = module.params.get("state", None)
    autostart = module.params.get("autostart", None)
    guest = module.params.get("name", None)
    command = module.params.get("command", None)
    uri = module.params.get("uri", None)
    xml = module.params.get("xml", None)

    v = Virt(uri, module)
    res = dict()

    if state and command == "list_vms":
        res = v.list_vms(state=state)
        if not isinstance(res, dict):
            res = {command: res}
        return VIRT_SUCCESS, res

    if state:
        if not guest:
            module.fail_json(msg="state change requires a guest specified")

        if state == "running":
            if v.status(guest) is "paused":
                res["changed"] = True
                res["msg"] = v.unpause(guest)
            elif v.status(guest) is not "running":
                res["changed"] = True
                res["msg"] = v.start(guest)
        elif state == "shutdown":
            if v.status(guest) is not "shutdown":
                res["changed"] = True
                res["msg"] = v.shutdown(guest)
        elif state == "destroyed":
            if v.status(guest) is not "shutdown":
                res["changed"] = True
                res["msg"] = v.destroy(guest)
        elif state == "paused":
            if v.status(guest) is "running":
                res["changed"] = True
                res["msg"] = v.pause(guest)
        else:
            module.fail_json(msg="unexpected state")

        return VIRT_SUCCESS, res

    if autostart is not None and v.autostart(guest, autostart):
        res["changed"] = True

    if command:
        if command in VM_COMMANDS:
            if not guest:
                module.fail_json(msg="%s requires 1 argument: guest" % command)
            if command == "define":
                if not xml:
                    module.fail_json(msg="define requires xml argument")
                try:
                    v.get_vm(guest)
                except VMNotFound:
                    v.define(xml)
                    res = {"changed": True, "created": guest}
                return VIRT_SUCCESS, res
            res = getattr(v, command)(guest)
            if not isinstance(res, dict):
                res = {command: res}
            return VIRT_SUCCESS, res

        elif hasattr(v, command):
            res = getattr(v, command)()
            if not isinstance(res, dict):
                res = {command: res}
            return VIRT_SUCCESS, res

        else:
            module.fail_json(msg="Command %s not recognized" % command)

    module.fail_json(msg="expected state or command parameter to be specified")


# Traceback (libvirtError)
The full traceback is:
Traceback (most recent call last):
File "/tmp/ansible_CDu9Fc/ansible_module_virt.py", line 527, in main
rc, result = core(module)
File "/tmp/ansible_CDu9Fc/ansible_module_virt.py", line 477, in core
if autostart is not None and v.autostart(guest, autostart):
File "/tmp/ansible_CDu9Fc/ansible_module_virt.py", line 340, in autostart
if self.conn.get_autostart(vmid) != as_flag:
File "/tmp/ansible_CDu9Fc/ansible_module_virt.py", line 249, in get_autostart
vm = self.conn.lookupByName(vmid)
File "/usr/lib64/python2.7/site-packages/libvirt.py", line 4227, in lookupByName
if ret is None:raise libvirtError('virDomainLookupByName() failed', conn=self)
libvirtError: Domain not found: no domain with matching name 'test_vm'

fatal: [kvm01.ams]: FAILED! => {
"changed": false,
"invocation": {
"module_args": {
"autostart": true,
"command": "define",
"name": "test_vm",
"state": null,
"uri": "qemu:///system",
"xml": "<domain type='kvm'>\n  <name>test_vm</name>\n ... and the rest of the xml ...</domain>\n\n"
}
},
"msg": "Domain not found: no domain with matching name 'test_vm'"
}

# Fixed code
def core(module):
    state = module.params.get("state", None)
    autostart = module.params.get("autostart", None)
    guest = module.params.get("name", None)
    command = module.params.get("command", None)
    uri = module.params.get("uri", None)
    xml = module.params.get("xml", None)

    v = Virt(uri, module)
    res = dict()

    if state and command == "list_vms":
        res = v.list_vms(state=state)
        if not isinstance(res, dict):
            res = {command: res}
        return VIRT_SUCCESS, res

    if autostart is not None and command != "define":
        if not guest:
            module.fail_json(msg="autostart requires 1 argument: name")
        try:
            v.get_vm(guest)
        except VMNotFound:
            module.fail_json(msg="domain %s not found" % guest)
        res["changed"] = v.autostart(guest, autostart)
        if not command and not state:
            return VIRT_SUCCESS, res

    if state:
        if not guest:
            module.fail_json(msg="state change requires a guest specified")

        if state == "running":
            if v.status(guest) is "paused":
                res["changed"] = True
                res["msg"] = v.unpause(guest)
            elif v.status(guest) is not "running":
                res["changed"] = True
                res["msg"] = v.start(guest)
        elif state == "shutdown":
            if v.status(guest) is not "shutdown":
                res["changed"] = True
                res["msg"] = v.shutdown(guest)
        elif state == "destroyed":
            if v.status(guest) is not "shutdown":
                res["changed"] = True
                res["msg"] = v.destroy(guest)
        elif state == "paused":
            if v.status(guest) is "running":
                res["changed"] = True
                res["msg"] = v.pause(guest)
        else:
            module.fail_json(msg="unexpected state")

        return VIRT_SUCCESS, res

    if command:
        if command in VM_COMMANDS:
            if command == "define":
                if not xml:
                    module.fail_json(msg="define requires xml argument")
                if guest:
                    # there might be a mismatch between quest 'name' in the module and in the xml
                    module.warn("'xml' is given - ignoring 'name'")
                found_name = re.search("<name>(.*)</name>", xml).groups()
                if found_name:
                    domain_name = found_name[0]
                else:
                    module.fail_json(msg="Could not find domain 'name' in xml")

                # From libvirt docs (https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainDefineXML):
                # -- A previous definition for this domain would be overridden if it already exists.
                #
                # In real world testing with libvirt versions 1.2.17-13, 2.0.0-10 and 3.9.0-14
                # on qemu and lxc domains results in:
                # operation failed: domain '<name>' already exists with <uuid>
                #
                # In case a domain would be indeed overwritten, we should protect idempotency:
                try:
                    existing_domain = v.get_vm(domain_name)
                except VMNotFound:
                    existing_domain = None
                try:
                    domain = v.define(xml)
                    if existing_domain:
                        # if we are here, then libvirt redefined existing domain as the doc promised
                        if existing_domain.XMLDesc() != domain.XMLDesc():
                            res = {"changed": True, "change_reason": "config changed"}
                    else:
                        res = {"changed": True, "created": domain.name()}
                except libvirtError as e:
                    if e.get_error_code() != 9:  # 9 means 'domain already exists' error
                        module.fail_json(msg="libvirtError: %s" % e.message)
                if autostart is not None and v.autostart(domain_name, autostart):
                    res = {"changed": True, "change_reason": "autostart"}

            elif not guest:
                module.fail_json(msg="%s requires 1 argument: guest" % command)
            else:
                res = getattr(v, command)(guest)
                if not isinstance(res, dict):
                    res = {command: res}

            return VIRT_SUCCESS, res

        elif hasattr(v, command):
            res = getattr(v, command)()
            if not isinstance(res, dict):
                res = {command: res}
            return VIRT_SUCCESS, res

        else:
            module.fail_json(msg="Command %s not recognized" % command)

    module.fail_json(msg="expected state or command parameter to be specified")