# Buggy code
def deploy_vm(self):
    # https://github.com/vmware/pyvmomi-community-samples/blob/master/samples/clone_vm.py
    # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.vm.CloneSpec.html
    # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.vm.ConfigSpec.html
    # https://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.RelocateSpec.html

    # FIXME:
    #   - static IPs

    self.folder = self.params.get("folder", None)
    if self.folder is None:
        self.module.fail_json(
            msg="Folder is required parameter while deploying new virtual machine"
        )

    # Prepend / if it was missing from the folder path, also strip trailing slashes
    if not self.folder.startswith("/"):
        self.folder = "/%(folder)s" % self.params
    self.folder = self.folder.rstrip("/")

    datacenter = self.cache.find_obj(
        self.content, [vim.Datacenter], self.params["datacenter"]
    )
    if datacenter is None:
        self.module.fail_json(
            msg="No datacenter named %(datacenter)s was found" % self.params
        )

    dcpath = compile_folder_path_for_object(datacenter)

    # Nested folder does not have trailing /
    if not dcpath.endswith("/"):
        dcpath += "/"

    # Check for full path first in case it was already supplied
    if self.folder.startswith(
        dcpath + self.params["datacenter"] + "/vm"
    ) or self.folder.startswith(dcpath + "/" + self.params["datacenter"] + "/vm"):
        fullpath = self.folder
    elif self.folder.startswith("/vm/") or self.folder == "/vm":
        fullpath = "%s%s%s" % (dcpath, self.params["datacenter"], self.folder)
    elif self.folder.startswith("/"):
        fullpath = "%s%s/vm%s" % (dcpath, self.params["datacenter"], self.folder)
    else:
        fullpath = "%s%s/vm/%s" % (dcpath, self.params["datacenter"], self.folder)

    f_obj = self.content.searchIndex.FindByInventoryPath(fullpath)

    # abort if no strategy was successful
    if f_obj is None:
        # Add some debugging values in failure.
        details = {
            "datacenter": datacenter.name,
            "datacenter_path": dcpath,
            "folder": self.folder,
            "full_search_path": fullpath,
        }
        self.module.fail_json(
            msg="No folder %s matched in the search path : %s"
            % (self.folder, fullpath),
            details=details,
        )

    destfolder = f_obj

    if self.params["template"]:
        vm_obj = self.get_vm_or_template(template_name=self.params["template"])
        if vm_obj is None:
            self.module.fail_json(
                msg="Could not find a template named %(template)s" % self.params
            )
    else:
        vm_obj = None

    # always get a resource_pool
    resource_pool = self.get_resource_pool()

    # set the destination datastore for VM & disks
    (datastore, datastore_name) = self.select_datastore(vm_obj)

    self.configspec = vim.vm.ConfigSpec()
    self.configspec.deviceChange = []
    self.configure_guestid(vm_obj=vm_obj, vm_creation=True)
    self.configure_cpu_and_memory(vm_obj=vm_obj, vm_creation=True)
    self.configure_hardware_params(vm_obj=vm_obj)
    self.configure_resource_alloc_info(vm_obj=vm_obj)
    self.configure_disks(vm_obj=vm_obj)
    self.configure_network(vm_obj=vm_obj)
    self.configure_cdrom(vm_obj=vm_obj)

    # Find if we need network customizations (find keys in dictionary that requires customizations)
    network_changes = False
    for nw in self.params["networks"]:
        for key in nw:
            # We don't need customizations for these keys
            if key not in ("device_type", "mac", "name", "vlan"):
                network_changes = True
                break

    if len(self.params["customization"]) > 0 or network_changes is True:
        self.customize_vm(vm_obj=vm_obj)

    clonespec = None
    clone_method = None
    try:
        if self.params["template"]:
            # create the relocation spec
            relospec = vim.vm.RelocateSpec()

            # Only select specific host when ESXi hostname is provided
            if self.params["esxi_hostname"]:
                relospec.host = self.select_host()
            relospec.datastore = datastore

            # https://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.RelocateSpec.html
            # > pool: For a clone operation from a template to a virtual machine, this argument is required.
            relospec.pool = resource_pool

            linked_clone = self.params.get("linked_clone")
            snapshot_src = self.params.get("snapshot_src", None)
            if linked_clone:
                if snapshot_src is not None:
                    relospec.diskMoveType = (
                        vim.vm.RelocateSpec.DiskMoveOptions.createNewChildDiskBacking
                    )
                else:
                    self.module.fail_json(
                        msg="Parameter 'linked_src' and 'snapshot_src' are"
                        " required together for linked clone operation."
                    )

            clonespec = vim.vm.CloneSpec(
                template=self.params["is_template"], location=relospec
            )
            if self.customspec:
                clonespec.customization = self.customspec

            if snapshot_src is not None:
                snapshot = self.get_snapshots_by_name_recursively(
                    snapshots=vm_obj.snapshot.rootSnapshotList, snapname=snapshot_src
                )
                if len(snapshot) != 1:
                    self.module.fail_json(
                        msg='virtual machine "%(template)s" does not contain'
                        ' snapshot named "%(snapshot_src)s"' % self.params
                    )

                clonespec.snapshot = snapshot[0].snapshot

            clonespec.config = self.configspec
            clone_method = "Clone"
            try:
                task = vm_obj.Clone(
                    folder=destfolder, name=self.params["name"], spec=clonespec
                )
            except vim.fault.NoPermission as e:
                self.module.fail_json(
                    msg="Failed to clone virtual machine %s to folder %s "
                    "due to permission issue: %s"
                    % (self.params["name"], destfolder, to_native(e.msg))
                )
            self.change_detected = True
        else:
            # ConfigSpec require name for VM creation
            self.configspec.name = self.params["name"]
            self.configspec.files = vim.vm.FileInfo(
                logDirectory=None,
                snapshotDirectory=None,
                suspendDirectory=None,
                vmPathName="[" + datastore_name + "]",
            )

            clone_method = "CreateVM_Task"
            try:
                task = destfolder.CreateVM_Task(
                    config=self.configspec, pool=resource_pool
                )
            except vmodl.fault.InvalidRequest as e:
                self.module.fail_json(
                    msg="Failed to create virtual machine due to invalid configuration "
                    "parameter %s" % to_native(e.msg)
                )
            except vim.fault.RestrictedVersion as e:
                self.module.fail_json(
                    msg="Failed to create virtual machine due to "
                    "product versioning restrictions: %s" % to_native(e.msg)
                )
            self.change_detected = True
        self.wait_for_task(task)
    except TypeError as e:
        self.module.fail_json(
            msg="TypeError was returned, please ensure to give correct inputs. %s"
            % to_text(e)
        )

    if task.info.state == "error":
        # https://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2021361
        # https://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2173

        # provide these to the user for debugging
        clonespec_json = serialize_spec(clonespec)
        configspec_json = serialize_spec(self.configspec)
        kwargs = {
            "changed": self.change_detected,
            "failed": True,
            "msg": task.info.error.msg,
            "clonespec": clonespec_json,
            "configspec": configspec_json,
            "clone_method": clone_method,
        }

        return kwargs
    else:
        # set annotation
        vm = task.info.result
        if self.params["annotation"]:
            annotation_spec = vim.vm.ConfigSpec()
            annotation_spec.annotation = str(self.params["annotation"])
            task = vm.ReconfigVM_Task(annotation_spec)
            self.wait_for_task(task)

        if self.params["customvalues"]:
            vm_custom_spec = vim.vm.ConfigSpec()
            self.customize_customvalues(vm_obj=vm, config_spec=vm_custom_spec)
            task = vm.ReconfigVM_Task(vm_custom_spec)
            self.wait_for_task(task)

        if self.params["wait_for_ip_address"] or self.params["state"] in [
            "poweredon",
            "restarted",
        ]:
            set_vm_power_state(self.content, vm, "poweredon", force=False)

            if self.params["wait_for_ip_address"]:
                self.wait_for_vm_ip(vm)

        vm_facts = self.gather_facts(vm)
        return {"changed": self.change_detected, "failed": False, "instance": vm_facts}


# Traceback (TypeError)
TASK [azure_load_balancer : Get lbs] *********************************************************************************************
task path: /home/vmadmin/cluster_build/roles/azure_load_balancer/tasks/main.yaml:15
Using module file /home/vmadmin/.local/lib/python2.7/site-packages/ansible/modules/cloud/azure/azure_rm_loadbalancer_facts.py
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: vmadmin
<localhost> EXEC /bin/sh -c 'echo ~ &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 &amp;&amp; mkdir -p "` echo /home/vmadmin/.ansible/tmp/ansible-tmp-1504708358.3-41710485333814 `" &amp;&amp; echo ansible-tmp-1504708358.3-41710485333814="` echo /home/vmadmin/.ansible/tmp/ansible-tmp-1504708358.3-41710485333814 `" ) &amp;&amp; sleep 0'
<localhost> PUT /tmp/tmpy_CiqC TO /home/vmadmin/.ansible/tmp/ansible-tmp-1504708358.3-41710485333814/azure_rm_loadbalancer_facts.py
<localhost> EXEC /bin/sh -c 'chmod u+x /home/vmadmin/.ansible/tmp/ansible-tmp-1504708358.3-41710485333814/ /home/vmadmin/.ansible/tmp/ansible-tmp-1504708358.3-41710485333814/azure_rm_loadbalancer_facts.py &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /home/vmadmin/.ansible/tmp/ansible-tmp-1504708358.3-41710485333814/azure_rm_loadbalancer_facts.py; rm -rf "/home/vmadmin/.ansible/tmp/ansible-tmp-1504708358.3-41710485333814/" > /dev/null 2>&amp;1 &amp;&amp; sleep 0'
The full traceback is:
Traceback (most recent call last):
File "/tmp/ansible_VTaHxN/ansible_module_azure_rm_loadbalancer_facts.py", line 180, in <module>
main()
File "/tmp/ansible_VTaHxN/ansible_module_azure_rm_loadbalancer_facts.py", line 177, in main
AzureRMLoadBalancerFacts()
File "/tmp/ansible_VTaHxN/ansible_module_azure_rm_loadbalancer_facts.py", line 123, in __init__
facts_module=True
File "/tmp/ansible_VTaHxN/ansible_modlib.zip/ansible/module_utils/azure_rm_common.py", line 255, in __init__
File "/tmp/ansible_VTaHxN/ansible_module_azure_rm_loadbalancer_facts.py", line 133, in exec_module
else self.list_items()
File "/tmp/ansible_VTaHxN/ansible_module_azure_rm_loadbalancer_facts.py", line 162, in list_items
response = self.network_client.load_balancers.list()
TypeError: list() takes at least 2 arguments (1 given)

fatal: [localhost]: FAILED! => {
"changed": false,
"failed": true,
"module_stderr": "Traceback (most recent call last):\n  File \"/tmp/ansible_VTaHxN/ansible_module_azure_rm_loadbalancer_facts.py\", line 180, in <module>\n    main()\n  File \"/tmp/ansible_VTaHxN/ansible_module_azure_rm_loadbalancer_facts.py\", line 177, in main\n    AzureRMLoadBalancerFacts()\n  File \"/tmp/ansible_VTaHxN/ansible_module_azure_rm_loadbalancer_facts.py\", line 123, in __init__\n    facts_module=True\n  File \"/tmp/ansible_VTaHxN/ansible_modlib.zip/ansible/module_utils/azure_rm_common.py\", line 255, in __init__\n  File \"/tmp/ansible_VTaHxN/ansible_module_azure_rm_loadbalancer_facts.py\", line 133, in exec_module\n    else self.list_items()\n  File \"/tmp/ansible_VTaHxN/ansible_module_azure_rm_loadbalancer_facts.py\", line 162, in list_items\n    response = self.network_client.load_balancers.list()\nTypeError: list() takes at least 2 arguments (1 given)\n",
"module_stdout": "",
"msg": "MODULE FAILURE",
"rc": 0
}

# Fixed code
def deploy_vm(self):
    # https://github.com/vmware/pyvmomi-community-samples/blob/master/samples/clone_vm.py
    # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.vm.CloneSpec.html
    # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.vm.ConfigSpec.html
    # https://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.RelocateSpec.html

    # FIXME:
    #   - static IPs

    self.folder = self.params.get("folder", None)
    if self.folder is None:
        self.module.fail_json(
            msg="Folder is required parameter while deploying new virtual machine"
        )

    # Prepend / if it was missing from the folder path, also strip trailing slashes
    if not self.folder.startswith("/"):
        self.folder = "/%(folder)s" % self.params
    self.folder = self.folder.rstrip("/")

    datacenter = self.cache.find_obj(
        self.content, [vim.Datacenter], self.params["datacenter"]
    )
    if datacenter is None:
        self.module.fail_json(
            msg="No datacenter named %(datacenter)s was found" % self.params
        )

    dcpath = compile_folder_path_for_object(datacenter)

    # Nested folder does not have trailing /
    if not dcpath.endswith("/"):
        dcpath += "/"

    # Check for full path first in case it was already supplied
    if self.folder.startswith(
        dcpath + self.params["datacenter"] + "/vm"
    ) or self.folder.startswith(dcpath + "/" + self.params["datacenter"] + "/vm"):
        fullpath = self.folder
    elif self.folder.startswith("/vm/") or self.folder == "/vm":
        fullpath = "%s%s%s" % (dcpath, self.params["datacenter"], self.folder)
    elif self.folder.startswith("/"):
        fullpath = "%s%s/vm%s" % (dcpath, self.params["datacenter"], self.folder)
    else:
        fullpath = "%s%s/vm/%s" % (dcpath, self.params["datacenter"], self.folder)

    f_obj = self.content.searchIndex.FindByInventoryPath(fullpath)

    # abort if no strategy was successful
    if f_obj is None:
        # Add some debugging values in failure.
        details = {
            "datacenter": datacenter.name,
            "datacenter_path": dcpath,
            "folder": self.folder,
            "full_search_path": fullpath,
        }
        self.module.fail_json(
            msg="No folder %s matched in the search path : %s"
            % (self.folder, fullpath),
            details=details,
        )

    destfolder = f_obj

    if self.params["template"]:
        vm_obj = self.get_vm_or_template(template_name=self.params["template"])
        if vm_obj is None:
            self.module.fail_json(
                msg="Could not find a template named %(template)s" % self.params
            )
    else:
        vm_obj = None

    # always get a resource_pool
    resource_pool = self.get_resource_pool()

    # set the destination datastore for VM & disks
    if self.params["datastore"]:
        # Give precendence to datastore value provided by user
        # User may want to deploy VM to specific datastore.
        datastore_name = self.params["datastore"]
        # Check if user has provided datastore cluster first
        datastore_cluster = self.cache.find_obj(
            self.content, [vim.StoragePod], datastore_name
        )
        if datastore_cluster:
            # If user specified datastore cluster so get recommended datastore
            datastore_name = self.get_recommended_datastore(
                datastore_cluster_obj=datastore_cluster
            )
        # Check if get_recommended_datastore or user specified datastore exists or not
        datastore = self.cache.find_obj(self.content, [vim.Datastore], datastore_name)
    else:
        (datastore, datastore_name) = self.select_datastore(vm_obj)

    self.configspec = vim.vm.ConfigSpec()
    self.configspec.deviceChange = []
    self.configure_guestid(vm_obj=vm_obj, vm_creation=True)
    self.configure_cpu_and_memory(vm_obj=vm_obj, vm_creation=True)
    self.configure_hardware_params(vm_obj=vm_obj)
    self.configure_resource_alloc_info(vm_obj=vm_obj)
    self.configure_disks(vm_obj=vm_obj)
    self.configure_network(vm_obj=vm_obj)
    self.configure_cdrom(vm_obj=vm_obj)

    # Find if we need network customizations (find keys in dictionary that requires customizations)
    network_changes = False
    for nw in self.params["networks"]:
        for key in nw:
            # We don't need customizations for these keys
            if key not in ("device_type", "mac", "name", "vlan"):
                network_changes = True
                break

    if len(self.params["customization"]) > 0 or network_changes is True:
        self.customize_vm(vm_obj=vm_obj)

    clonespec = None
    clone_method = None
    try:
        if self.params["template"]:
            # create the relocation spec
            relospec = vim.vm.RelocateSpec()

            # Only select specific host when ESXi hostname is provided
            if self.params["esxi_hostname"]:
                relospec.host = self.select_host()
            relospec.datastore = datastore

            # https://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.RelocateSpec.html
            # > pool: For a clone operation from a template to a virtual machine, this argument is required.
            relospec.pool = resource_pool

            linked_clone = self.params.get("linked_clone")
            snapshot_src = self.params.get("snapshot_src", None)
            if linked_clone:
                if snapshot_src is not None:
                    relospec.diskMoveType = (
                        vim.vm.RelocateSpec.DiskMoveOptions.createNewChildDiskBacking
                    )
                else:
                    self.module.fail_json(
                        msg="Parameter 'linked_src' and 'snapshot_src' are"
                        " required together for linked clone operation."
                    )

            clonespec = vim.vm.CloneSpec(
                template=self.params["is_template"], location=relospec
            )
            if self.customspec:
                clonespec.customization = self.customspec

            if snapshot_src is not None:
                snapshot = self.get_snapshots_by_name_recursively(
                    snapshots=vm_obj.snapshot.rootSnapshotList, snapname=snapshot_src
                )
                if len(snapshot) != 1:
                    self.module.fail_json(
                        msg='virtual machine "%(template)s" does not contain'
                        ' snapshot named "%(snapshot_src)s"' % self.params
                    )

                clonespec.snapshot = snapshot[0].snapshot

            clonespec.config = self.configspec
            clone_method = "Clone"
            try:
                task = vm_obj.Clone(
                    folder=destfolder, name=self.params["name"], spec=clonespec
                )
            except vim.fault.NoPermission as e:
                self.module.fail_json(
                    msg="Failed to clone virtual machine %s to folder %s "
                    "due to permission issue: %s"
                    % (self.params["name"], destfolder, to_native(e.msg))
                )
            self.change_detected = True
        else:
            # ConfigSpec require name for VM creation
            self.configspec.name = self.params["name"]
            self.configspec.files = vim.vm.FileInfo(
                logDirectory=None,
                snapshotDirectory=None,
                suspendDirectory=None,
                vmPathName="[" + datastore_name + "]",
            )

            clone_method = "CreateVM_Task"
            try:
                task = destfolder.CreateVM_Task(
                    config=self.configspec, pool=resource_pool
                )
            except vmodl.fault.InvalidRequest as e:
                self.module.fail_json(
                    msg="Failed to create virtual machine due to invalid configuration "
                    "parameter %s" % to_native(e.msg)
                )
            except vim.fault.RestrictedVersion as e:
                self.module.fail_json(
                    msg="Failed to create virtual machine due to "
                    "product versioning restrictions: %s" % to_native(e.msg)
                )
            self.change_detected = True
        self.wait_for_task(task)
    except TypeError as e:
        self.module.fail_json(
            msg="TypeError was returned, please ensure to give correct inputs. %s"
            % to_text(e)
        )

    if task.info.state == "error":
        # https://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2021361
        # https://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2173

        # provide these to the user for debugging
        clonespec_json = serialize_spec(clonespec)
        configspec_json = serialize_spec(self.configspec)
        kwargs = {
            "changed": self.change_detected,
            "failed": True,
            "msg": task.info.error.msg,
            "clonespec": clonespec_json,
            "configspec": configspec_json,
            "clone_method": clone_method,
        }

        return kwargs
    else:
        # set annotation
        vm = task.info.result
        if self.params["annotation"]:
            annotation_spec = vim.vm.ConfigSpec()
            annotation_spec.annotation = str(self.params["annotation"])
            task = vm.ReconfigVM_Task(annotation_spec)
            self.wait_for_task(task)

        if self.params["customvalues"]:
            vm_custom_spec = vim.vm.ConfigSpec()
            self.customize_customvalues(vm_obj=vm, config_spec=vm_custom_spec)
            task = vm.ReconfigVM_Task(vm_custom_spec)
            self.wait_for_task(task)

        if self.params["wait_for_ip_address"] or self.params["state"] in [
            "poweredon",
            "restarted",
        ]:
            set_vm_power_state(self.content, vm, "poweredon", force=False)

            if self.params["wait_for_ip_address"]:
                self.wait_for_vm_ip(vm)

        vm_facts = self.gather_facts(vm)
        return {"changed": self.change_detected, "failed": False, "instance": vm_facts}