Repository: ansible/ansible

Issue:
proxmox_kvm : delete args
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME

proxmox_kvm

##### ANSIBLE VERSION

```
2.2.1.0
```

plus

https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/cloud/misc/proxmox_kvm.py

##### SUMMARY

Deleting ```args``` does not work.

##### STEPS TO REPRODUCE

```
  tasks:

  - name: Remove
    proxmox_kvm:
      api_user: "{{ api_user }}"
      api_password: "{{ api_password }}"
      api_host: "{{ api_host }}"
      node: "{{ node }}"
      name: "{{ vmname }}"
      delete: args
```

##### EXPECTED RESULTS

```args``` get's removed from vm config.

##### ACTUAL RESULTS

Playbook exits successful, but the args are stil in the vm config.
Fixes #28584: modules/windows/win_get_url.ps1: Change -msg option to -message
##### SUMMARY
Fixes #28584: modules/windows/win_get_url.ps1: Change -msg option to -message

Invalid option `-msg` causes `DEPRECATION WARNING` string to display as None.

##### ISSUE TYPE
 - Bugfix Pull Request

##### COMPONENT NAME
win_get_url

##### ANSIBLE VERSION
```
ansible 2.4.0 (issue/28584 1a3e7dfb32) last updated 2017/08/24 02:20:57 (GMT -400)
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/ansible/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/ansible/ansible/lib/ansible
  executable location = /home/ansible/ansible/bin/ansible
  python version = 2.7.5 (default, May  3 2017, 07:55:04) [GCC 4.8.5 20150623 (Red Hat 4.8.5-14)]
```

##### ADDITIONAL INFORMATION
I can't demonstrate as I don't have a Windows box to test on. Please see Issue #28584 for more details.



Discussion:
@helldorado : Any ideas? ;)
@morph027 oup's , the state `present` take the precedence. i will add update => Yes|No parameter and use set method to modify the KVM. 


Resolving patch:
diff --git a/lib/ansible/modules/cloud/misc/proxmox_kvm.py b/lib/ansible/modules/cloud/misc/proxmox_kvm.py
--- a/lib/ansible/modules/cloud/misc/proxmox_kvm.py
+++ b/lib/ansible/modules/cloud/misc/proxmox_kvm.py
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
-# (c) 2016, Abdoul Bah (@helldorado) <abdoul.bah at alterway.fr>
+# (c) 2016, Abdoul Bah (@helldorado) <bahabdoul at gmail.com>
 
 """
 Ansible module to manage Qemu(KVM) instance in Proxmox VE cluster.
@@ -28,7 +28,7 @@
 description:
   - Allows you to create/delete/stop Qemu(KVM) Virtual Machines in Proxmox VE cluster.
 version_added: "2.3"
-author: "Abdoul Bah (@helldorado) <abdoul.bah at alterway.fr>"
+author: "Abdoul Bah (@helldorado) <bahabdoul at gmail.com>"
 options:
   acpi:
     description:
@@ -36,21 +36,18 @@
     required: false
     default: "yes"
     choices: [ "yes", "no" ]
-    type: boolean
   agent:
     description:
       - Specify if the QEMU GuestAgent should be enabled/disabled.
     required: false
     default: null
     choices: [ "yes", "no" ]
-    type: boolean
   args:
     description:
       - Pass arbitrary arguments to kvm.
       - This option is for experts only!
     default: "-serial unix:/var/run/qemu-server/VMID.serial,server,nowait"
     required: false
-    type: string
   api_host:
     description:
       - Specify the target host of the Proxmox VE cluster.
@@ -71,80 +68,73 @@
     required: false
     default: "no"
     choices: [ "yes", "no" ]
-    type: boolean
   balloon:
     description:
       - Specify the amount of RAM for the VM in MB.
       - Using zero disables the balloon driver.
     required: false
     default: 0
-    type: integer
   bios:
     description:
       - Specify the BIOS implementation.
     choices: ['seabios', 'ovmf']
     required: false
     default: null
-    type: string
   boot:
     description:
       - Specify the boot order -> boot on floppy C(a), hard disk C(c), CD-ROM C(d), or network C(n).
       - You can combine to set order.
     required: false
     default: cnd
-    type: string
   bootdisk:
     description:
       - Enable booting from specified disk. C((ide|sata|scsi|virtio)\d+)
     required: false
     default: null
-    type: string
+  clone:
+    description:
+      - Name of VM to be cloned. If C(vmid) is setted, C(clone) can take arbitrary value but required for intiating the clone.
+    required: false
+    default: null
   cores:
     description:
       - Specify number of cores per socket.
     required: false
     default: 1
-    type: integer
   cpu:
     description:
       - Specify emulated CPU type.
     required: false
     default: kvm64
-    type: string
   cpulimit:
     description:
       - Specify if CPU usage will be limited. Value 0 indicates no CPU limit.
       - If the computer has 2 CPUs, it has total of '2' CPU time
     required: false
     default: null
-    type: integer
   cpuunits:
     description:
       - Specify CPU weight for a VM.
       - You can disable fair-scheduler configuration by setting this to 0
     default: 1000
     required: false
-    type: integer
   delete:
     description:
       - Specify a list of settings you want to delete.
     required: false
     default: null
-    type: string
   description:
     description:
       - Specify the description for the VM. Only used on the configuration web interface.
       - This is saved as comment inside the configuration file.
     required: false
     default: null
-    type: string
   digest:
     description:
       - Specify if to prevent changes if current configuration file has different SHA1 digest.
       - This can be used to prevent concurrent modifications.
     required: false
     default: null
-    type: string
   force:
     description:
       - Allow to force stop VM.
@@ -152,14 +142,27 @@
     default: null
     choices: [ "yes", "no" ]
     required: false
-    type: boolean
+  format:
+    description:
+      - Target drive’s backing file’s data format.
+      - Used only with clone
+    default: qcow2
+    choices: [ "cloop", "cow", "qcow", "qcow2", "qed", "raw", "vmdk" ]
+    required: false
   freeze:
     description:
       - Specify if PVE should freeze CPU at startup (use 'c' monitor command to start execution).
     required: false
     default: null
     choices: [ "yes", "no" ]
-    type: boolean
+  full:
+    description:
+      - Create a full copy of all disk. This is always done when you clone a normal VM.
+      - For VM templates, we try to create a linked clone by default.
+      - Used only with clone
+    default: yes
+    choices: [ "yes", "no"]
+    required: false
   hostpci:
     description:
       - Specify a hash/dictionary of map host pci devices into guest. C(hostpci='{"key":"value", "key":"value"}').
@@ -172,7 +175,6 @@
       - /!\ This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
     required: false
     default: null
-    type: A hash/dictionary defining host pci devices
   hotplug:
     description:
       - Selectively enable hotplug features.
@@ -180,14 +182,12 @@
       - Value 0 disables hotplug completely and value 1 is an alias for the default C('network,disk,usb').
     required: false
     default: null
-    type: string
   hugepages:
     description:
       - Enable/disable hugepages memory.
     choices: ['any', '2', '1024']
     required: false
     default: null
-    type: string
   ide:
     description:
       - A hash/dictionary of volume used as IDE hard disk or CD-ROM. C(ide='{"key":"value", "key":"value"}').
@@ -198,20 +198,17 @@
       - C(format) is the drive’s backing file’s data format. C(qcow2|raw|subvol).
     required: false
     default: null
-    type: A hash/dictionary defining ide
   keyboard:
     description:
       - Sets the keyboard layout for VNC server.
     required: false
     default: null
-    type: string
   kvm:
     description:
       - Enable/disable KVM hardware virtualization.
     required: false
     default: "yes"
     choices: [ "yes", "no" ]
-    type: boolean
   localtime:
     description:
       - Sets the real time clock to local time.
@@ -219,40 +216,34 @@
     required: false
     default: null
     choices: [ "yes", "no" ]
-    type: boolean
   lock:
     description:
       - Lock/unlock the VM.
     choices: ['migrate', 'backup', 'snapshot', 'rollback']
     required: false
     default: null
-    type: string
   machine:
     description:
       - Specifies the Qemu machine type.
       - type => C((pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?))
     required: false
     default: null
-    type: string
   memory:
     description:
       - Memory size in MB for instance.
     required: false
     default: 512
-    type: integer
   migrate_downtime:
     description:
       - Sets maximum tolerated downtime (in seconds) for migrations.
     required: false
     default: null
-    type: integer
   migrate_speed:
     description:
       - Sets maximum speed (in MB/s) for migrations.
       - A value of 0 is no limit.
     required: false
     default: null
-    type: integer
   name:
     description:
       - Specifies the VM name. Only used on the configuration web interface.
@@ -271,7 +262,12 @@
       - If you specify no bridge, we create a kvm 'user' (NATed) network device, which provides DHCP and DNS services.
     default: null
     required: false
-    type: A hash/dictionary defining interfaces
+  newid:
+    description:
+      - VMID for the clone. Used only with clone.
+      - If newid is not set, the next available VM ID will be fetched from ProxmoxAPI.
+    default: null
+    required: false
   node:
     description:
       - Proxmox VE node, where the new VM will be created.
@@ -290,14 +286,12 @@
       - C(policy) NUMA allocation policy.
     default: null
     required: false
-    type: A hash/dictionary defining NUMA topology
   onboot:
     description:
       - Specifies whether a VM will be started during system bootup.
     default: "yes"
     choices: [ "yes", "no" ]
     required: false
-    type: boolean
   ostype:
     description:
       - Specifies guest operating system. This is used to enable special optimization/features for specific operating systems.
@@ -305,7 +299,6 @@
     choices: ['other', 'wxp', 'w2k', 'w2k3', 'w2k8', 'wvista', 'win7', 'win8', 'l24', 'l26', 'solaris']
     default: l26
     required: false
-    type: string
   parallel:
     description:
       - A hash/dictionary of map host parallel devices. C(parallel='{"key":"value", "key":"value"}').
@@ -313,27 +306,28 @@
       - Values allowed are - C("/dev/parport\d+|/dev/usb/lp\d+").
     default: null
     required: false
-    type: A hash/dictionary defining host parallel devices
+  pool:
+    description:
+      - Add the new VM to the specified pool.
+    default: null
+    required: false
   protection:
     description:
       - Enable/disable the protection flag of the VM. This will enable/disable the remove VM and remove disk operations.
     default: null
     choices: [ "yes", "no" ]
     required: false
-    type: boolean
   reboot:
     description:
       - Allow reboot. If set to yes, the VM exit on reboot.
     default: null
     choices: [ "yes", "no" ]
     required: false
-    type: boolean
   revert:
     description:
       - Revert a pending change.
     default: null
     required: false
-    type: string
   sata:
     description:
       - A hash/dictionary of volume used as sata hard disk or CD-ROM. C(sata='{"key":"value", "key":"value"}').
@@ -344,7 +338,6 @@
       - C(format) is the drive’s backing file’s data format. C(qcow2|raw|subvol).
     default: null
     required: false
-    type: A hash/dictionary defining sata
   scsi:
     description:
       - A hash/dictionary of volume used as SCSI hard disk or CD-ROM. C(scsi='{"key":"value", "key":"value"}').
@@ -355,14 +348,12 @@
       - C(format) is the drive’s backing file’s data format. C(qcow2|raw|subvol).
     default: null
     required: false
-    type: A hash/dictionary defining scsi
   scsihw:
     description:
       - Specifies the SCSI controller model.
     choices: ['lsi', 'lsi53c810', 'virtio-scsi-pci', 'virtio-scsi-single', 'megasas', 'pvscsi']
     required: false
     default: null
-    type: string
   serial:
     description:
       - A hash/dictionary of serial device to create inside the VM. C('{"key":"value", "key":"value"}').
@@ -371,7 +362,6 @@
       - /!\ If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
     default: null
     required: false
-    type: A hash/dictionary defining serial
   shares:
     description:
       - Rets amount of memory shares for auto-ballooning. (0 - 50000).
@@ -380,34 +370,33 @@
       - Using 0 disables auto-ballooning, this means no limit.
     required: false
     default: null
-    type: integer
   skiplock:
     description:
       - Ignore locks
       - Only root is allowed to use this option.
     required: false
     default: null
-    choices: [ "yes", "no" ]
-    type: boolean
   smbios:
     description:
       - Specifies SMBIOS type 1 fields.
     required: false
     default: null
-    type: string
+  snapname:
+    description:
+      - The name of the snapshot. Used only with clone.
+    default: null
+    required: false
   sockets:
     description:
       - Sets the number of CPU sockets. (1 - N).
     required: false
     default: 1
-    type: integer
   startdate:
     description:
       - Sets the initial date of the real time clock.
       - Valid format for date are C('now') or C('2016-09-25T16:01:21') or C('2016-09-25').
     required: false
     default: null
-    type: string
   startup:
     description:
       - Startup and shutdown behavior. C([[order=]\d+] [,up=\d+] [,down=\d+]).
@@ -415,7 +404,6 @@
       - Shutdown in done with reverse ordering.
     required: false
     default: null
-    type: string
   state:
     description:
       - Indicates desired state of the instance.
@@ -423,46 +411,59 @@
     choices: ['present', 'started', 'absent', 'stopped', 'restarted','current']
     required: false
     default: present
+  storage:
+    description:
+      - Target storage for full clone.
+    default: null
+    required: false
   tablet:
     description:
       - Enables/disables the USB tablet device.
     required: false
     choices: [ "yes", "no" ]
     default: "no"
-    type: boolean
+  target:
+    description:
+      - Target node. Only allowed if the original VM is on shared storage.
+      - Used only with clone
+    default: null
+    required: false
   tdf:
     description:
       - Enables/disables time drift fix.
     required: false
     default: null
     choices: [ "yes", "no" ]
-    type: boolean
   template:
     description:
       - Enables/disables the template.
     required: false
     default: "no"
     choices: [ "yes", "no" ]
-    type: boolean
   timeout:
     description:
       - Timeout for operations.
     default: 30
     required: false
-    type: integer
+  update:
+    description:
+      - If C(yes), the VM will be update with new value.
+      - Cause of the operations of the API and security reasons, I have disabled the update of the following parameters
+      - C(net, virtio, ide, sata, scsi). Per example updating C(net) update the MAC address and C(virtio) create always new disk...
+    default: "no"
+    choices: [ "yes", "no" ]
+    required: false
   validate_certs:
     description:
       - If C(no), SSL certificates will not be validated. This should only be used on personally controlled sites using self-signed certificates.
     default: "no"
     choices: [ "yes", "no" ]
     required: false
-    type: boolean
   vcpus:
     description:
       - Sets number of hotplugged vcpus.
     required: false
     default: null
-    type: integer
   vga:
     description:
       - Select VGA type. If you want to use high resolution modes (>= 1280x1024x16) then you should use option 'std' or 'vmware'.
@@ -479,7 +480,6 @@
       - C(format) is the drive’s backing file’s data format. C(qcow2|raw|subvol).
     required: false
     default: null
-    type: A hash/dictionary defining virtio
   vmid:
     description:
       - Specifies the VM ID. Instead use I(name) parameter.
@@ -491,7 +491,6 @@
       - Creates a virtual hardware watchdog device.
     required: false
     default: null
-    type: string
 Notes:
   - Requires proxmoxer and requests modules on host. This modules can be installed with pip.
 requirements: [ "proxmoxer", "requests" ]
@@ -536,6 +535,32 @@
     cores       : 4
     vcpus       : 2
 
+# Clone VM with only source VM name
+- proxmox_kvm:
+    api_user    : root@pam
+    api_password: secret
+    api_host    : helldorado
+    clone       : spynal   # The VM source
+    name        : zavala  # The target VM name
+    node        : sabrewulf
+    storage     : VMs
+    format      : qcow2
+    timeout     : 500  # Note: The task can take a while. Adapt
+
+# Clone VM with source vmid and target newid and raw format
+- proxmox_kvm:
+    api_user    : root@pam
+    api_password: secret
+    api_host    : helldorado
+    clone       : arbitrary_name
+    vmid        : 108
+    newid       : 152
+    name        : zavala  # The target VM name
+    node        : sabrewulf
+    storage     : LVM_STO
+    format      : raw
+    timeout     : 300  # Note: The task can take a while. Adapt
+
 # Create new VM and lock it for snapashot.
 - proxmox_kvm:
     api_user    : root@pam
@@ -608,6 +633,35 @@
     name        : spynal
     node        : sabrewulf
     state       : current
+
+# Update VM configuration
+- proxmox_kvm:
+    api_user    : root@pam
+    api_password: secret
+    api_host    : helldorado
+    name        : spynal
+    node        : sabrewulf
+    cpu         : 8
+    memory      : 16384
+    update      : yes
+
+# Delete QEMU parameters
+- proxmox_kvm:
+    api_user    : root@pam
+    api_password: secret
+    api_host    : helldorado
+    name        : spynal
+    node        : sabrewulf
+    delete      : 'args,template,cpulimit'
+
+# Revert a pending change
+- proxmox_kvm:
+    api_user    : root@pam
+    api_password: secret
+    api_host    : helldorado
+    name        : spynal
+    node        : sabrewulf
+    revert      : 'template,cpulimit'
 '''
 
 RETURN = '''
@@ -655,266 +709,380 @@
 
 
 try:
-  from proxmoxer import ProxmoxAPI
-  HAS_PROXMOXER = True
+    from proxmoxer import ProxmoxAPI
+    HAS_PROXMOXER = True
 except ImportError:
-  HAS_PROXMOXER = False
+    HAS_PROXMOXER = False
+
+VZ_TYPE = 'qemu'
 
-VZ_TYPE='qemu'
 
 def get_nextvmid(proxmox):
-  try:
-    vmid = proxmox.cluster.nextid.get()
-    return vmid
-  except Exception as e:
-    module.fail_json(msg="Unable to get next vmid. Failed with exception: %s")
+    try:
+        vmid = proxmox.cluster.nextid.get()
+        return vmid
+    except Exception as e:
+        module.fail_json(msg="Unable to get next vmid. Failed with exception: %s")
+
 
 def get_vmid(proxmox, name):
-    return [ vm['vmid'] for vm in proxmox.cluster.resources.get(type='vm') if vm['name'] == name ]
+    return [vm['vmid'] for vm in proxmox.cluster.resources.get(type='vm') if vm['name'] == name]
+
 
 def get_vm(proxmox, vmid):
-  return [ vm for vm in proxmox.cluster.resources.get(type='vm') if vm['vmid'] == int(vmid) ]
+    return [vm for vm in proxmox.cluster.resources.get(type='vm') if vm['vmid'] == int(vmid)]
+
 
 def node_check(proxmox, node):
-  return [ True for nd in proxmox.nodes.get() if nd['node'] == node ]
+    return [True for nd in proxmox.nodes.get() if nd['node'] == node]
+
 
 def get_vminfo(module, proxmox, node, vmid, **kwargs):
-        global results
-        results = {}
-        mac = {}
-        devices = {}
-        try:
-          vm = proxmox.nodes(node).qemu(vmid).config.get()
-        except Exception as e:
-          module.fail_json(msg='Getting information for VM with vmid = %s failed with exception: %s' % (vmid, e))
+    global results
+    results = {}
+    mac = {}
+    devices = {}
+    try:
+        vm = proxmox.nodes(node).qemu(vmid).config.get()
+    except Exception as e:
+        module.fail_json(msg='Getting information for VM with vmid = %s failed with exception: %s' % (vmid, e))
 
-        # Sanitize kwargs. Remove not defined args and ensure True and False converted to int.
-        kwargs = dict((k,v) for k, v in kwargs.items() if v is not None)
+    # Sanitize kwargs. Remove not defined args and ensure True and False converted to int.
+    kwargs = dict((k, v) for k, v in kwargs.items() if v is not None)
 
-        # Convert all dict in kwargs to elements. For hostpci[n], ide[n], net[n], numa[n], parallel[n], sata[n], scsi[n], serial[n], virtio[n]
-        for k in kwargs.keys():
-          if isinstance(kwargs[k], dict):
-             kwargs.update(kwargs[k])
-             del kwargs[k]
+    # Convert all dict in kwargs to elements. For hostpci[n], ide[n], net[n], numa[n], parallel[n], sata[n], scsi[n], serial[n], virtio[n]
+    for k in kwargs.keys():
+        if isinstance(kwargs[k], dict):
+            kwargs.update(kwargs[k])
+            del kwargs[k]
 
-        # Split information by type
-        for k, v in kwargs.items():
-          if re.match(r'net[0-9]', k) is not None:
+    # Split information by type
+    for k, v in kwargs.items():
+        if re.match(r'net[0-9]', k) is not None:
             interface = k
             k = vm[k]
             k = re.search('=(.*?),', k).group(1)
             mac[interface] = k
-          if re.match(r'virtio[0-9]', k) is not None or re.match(r'ide[0-9]', k) is not None or re.match(r'scsi[0-9]', k) is not None or re.match(r'sata[0-9]', k) is not None:
+        if re.match(r'virtio[0-9]', k) is not None or re.match(r'ide[0-9]', k) is not None or re.match(r'scsi[0-9]', k) is not None or re.match(r'sata[0-9]', k) is not None:
             device = k
             k = vm[k]
             k = re.search('(.*?),', k).group(1)
             devices[device] = k
 
-        results['mac'] = mac
-        results['devices'] = devices
-        results['vmid'] = int(vmid)
-
-def create_vm(module, proxmox, vmid, node, name, memory, cpu, cores, sockets, timeout, **kwargs):
-  # Available only in PVE 4
-  only_v4 = ['force','protection','skiplock']
-  # Default args for vm. Note: -args option is for experts only. It allows you to pass arbitrary arguments to kvm.
-  vm_args = "-serial unix:/var/run/qemu-server/{}.serial,server,nowait".format(vmid)
-
-  proxmox_node = proxmox.nodes(node)
-
-  # Sanitize kwargs. Remove not defined args and ensure True and False converted to int.
-  kwargs = dict((k,v) for k, v in kwargs.items() if v is not None)
-  kwargs.update(dict([k, int(v)] for k, v in kwargs.items() if isinstance(v, bool)))
-
-  # The features work only on PVE 4
-  if PVE_MAJOR_VERSION < 4:
-    for p in only_v4:
-      if p in kwargs:
-         del kwargs[p]
-
-  # Convert all dict in kwargs to elements. For hostpci[n], ide[n], net[n], numa[n], parallel[n], sata[n], scsi[n], serial[n], virtio[n]
-  for k in kwargs.keys():
-    if isinstance(kwargs[k], dict):
-      kwargs.update(kwargs[k])
-      del kwargs[k]
-
-  # -args and skiplock require root@pam user
-  if module.params['api_user'] == "root@pam" and module.params['args'] is None:
-    kwargs['args'] = vm_args
-  elif module.params['api_user'] == "root@pam" and module.params['args'] is not None:
-    kwargs['args'] = module.params['args']
-  elif module.params['api_user'] != "root@pam" and module.params['args'] is not None:
-    module.fail_json(msg='args parameter require root@pam user. ')
-
-  if module.params['api_user'] != "root@pam" and module.params['skiplock'] is not None:
-    module.fail_json(msg='skiplock parameter require root@pam user. ')
-
-  taskid = getattr(proxmox_node, VZ_TYPE).create(vmid=vmid, name=name, memory=memory, cpu=cpu, cores=cores, sockets=sockets, **kwargs)
-
-  while timeout:
-    if ( proxmox_node.tasks(taskid).status.get()['status'] == 'stopped'
-        and proxmox_node.tasks(taskid).status.get()['exitstatus'] == 'OK' ):
-      return True
-    timeout = timeout - 1
-    if timeout == 0:
-      module.fail_json(msg='Reached timeout while waiting for creating VM. Last line in task before timeout: %s'
-                       % proxmox_node.tasks(taskid).log.get()[:1])
-    time.sleep(1)
-  return False
+    results['mac'] = mac
+    results['devices'] = devices
+    results['vmid'] = int(vmid)
+
+
+def settings(module, proxmox, vmid, node, name, timeout, **kwargs):
+    proxmox_node = proxmox.nodes(node)
+
+    # Sanitize kwargs. Remove not defined args and ensure True and False converted to int.
+    kwargs = dict((k, v) for k, v in kwargs.items() if v is not None)
+
+    if getattr(proxmox_node, VZ_TYPE)(vmid).config.set(**kwargs) is None:
+        return True
+    else:
+        return False
+
+
+def create_vm(module, proxmox, vmid, newid, node, name, memory, cpu, cores, sockets, timeout, update, **kwargs):
+    # Available only in PVE 4
+    only_v4 = ['force', 'protection', 'skiplock']
+
+    # valide clone parameters
+    valid_clone_params = ['format', 'full', 'pool', 'snapname', 'storage', 'target']
+    clone_params = {}
+    # Default args for vm. Note: -args option is for experts only. It allows you to pass arbitrary arguments to kvm.
+    vm_args = "-serial unix:/var/run/qemu-server/{}.serial,server,nowait".format(vmid)
+
+    proxmox_node = proxmox.nodes(node)
+
+    # Sanitize kwargs. Remove not defined args and ensure True and False converted to int.
+    kwargs = dict((k,v) for k, v in kwargs.items() if v is not None)
+    kwargs.update(dict([k, int(v)] for k, v in kwargs.items() if isinstance(v, bool)))
+
+    # The features work only on PVE 4
+    if PVE_MAJOR_VERSION < 4:
+        for p in only_v4:
+            if p in kwargs:
+                del kwargs[p]
+
+    # If update, don't update disk (virtio, ide, sata, scsi) and network interface
+    if update:
+        if 'virtio' in kwargs:
+            del kwargs['virtio']
+        if 'sata' in kwargs:
+            del kwargs['sata']
+        if 'scsi' in kwargs:
+            del kwargs['scsi']
+        if 'ide' in kwargs:
+            del kwargs['ide']
+        if 'net' in kwargs:
+            del kwargs['net']
+
+    # Convert all dict in kwargs to elements. For hostpci[n], ide[n], net[n], numa[n], parallel[n], sata[n], scsi[n], serial[n], virtio[n]
+    for k in kwargs.keys():
+        if isinstance(kwargs[k], dict):
+            kwargs.update(kwargs[k])
+            del kwargs[k]
+
+    # Rename numa_enabled  to numa. According the API documentation
+    if 'numa_enabled' in kwargs:
+        kwargs['numa'] = kwargs['numa_enabled']
+        del kwargs['numa_enabled']
+
+    # -args and skiplock require root@pam user
+    if module.params['api_user'] == "root@pam" and module.params['args'] is None:
+        if not update:
+            kwargs['args'] = vm_args
+    elif module.params['api_user'] == "root@pam" and module.params['args'] is not None:
+        kwargs['args'] = module.params['args']
+    elif module.params['api_user'] != "root@pam" and module.params['args'] is not None:
+        module.fail_json(msg='args parameter require root@pam user. ')
+
+    if module.params['api_user'] != "root@pam" and module.params['skiplock'] is not None:
+        module.fail_json(msg='skiplock parameter require root@pam user. ')
+
+    if update:
+        if getattr(proxmox_node, VZ_TYPE)(vmid).config.set(name=name, memory=memory, cpu=cpu, cores=cores, sockets=sockets, **kwargs) is None:
+            return True
+        else:
+            return False
+    elif module.params['clone'] is not None:
+        for param in valid_clone_params:
+            if module.params[param] is not None:
+                clone_params[param] = module.params[param]
+        clone_params.update(dict([k, int(v)] for k, v in clone_params.items() if isinstance(v, bool)))
+        taskid = proxmox_node.qemu(vmid).clone.post(newid=newid, name=name, **clone_params)
+    else:
+        taskid = getattr(proxmox_node, VZ_TYPE).create(vmid=vmid, name=name, memory=memory, cpu=cpu, cores=cores, sockets=sockets, **kwargs)
+
+    while timeout:
+        if (proxmox_node.tasks(taskid).status.get()['status'] == 'stopped'
+            and proxmox_node.tasks(taskid).status.get()['exitstatus'] == 'OK'):
+            return True
+        timeout = timeout - 1
+        if timeout == 0:
+            module.fail_json(msg='Reached timeout while waiting for creating VM. Last line in task before timeout: %s'
+                             % proxmox_node.tasks(taskid).log.get()[:1])
+        time.sleep(1)
+    return False
+
 
 def start_vm(module, proxmox, vm, vmid, timeout):
-  taskid = getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.start.post()
-  while timeout:
-    if ( proxmox.nodes(vm[0]['node']).tasks(taskid).status.get()['status'] == 'stopped'
-        and proxmox.nodes(vm[0]['node']).tasks(taskid).status.get()['exitstatus'] == 'OK' ):
-      return True
-    timeout = timeout - 1
-    if timeout == 0:
-      module.fail_json(msg='Reached timeout while waiting for starting VM. Last line in task before timeout: %s'
-                       % proxmox.nodes(vm[0]['node']).tasks(taskid).log.get()[:1])
-
-    time.sleep(1)
-  return False
+    taskid = getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.start.post()
+    while timeout:
+        if (proxmox.nodes(vm[0]['node']).tasks(taskid).status.get()['status'] == 'stopped'
+            and proxmox.nodes(vm[0]['node']).tasks(taskid).status.get()['exitstatus'] == 'OK' ):
+            return True
+        timeout = timeout - 1
+        if timeout == 0:
+            module.fail_json(msg='Reached timeout while waiting for starting VM. Last line in task before timeout: %s'
+                             % proxmox.nodes(vm[0]['node']).tasks(taskid).log.get()[:1])
+
+        time.sleep(1)
+    return False
+
 
 def stop_vm(module, proxmox, vm, vmid, timeout, force):
-  if force:
-    taskid = getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.shutdown.post(forceStop=1)
-  else:
-    taskid = getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.shutdown.post()
-  while timeout:
-    if ( proxmox.nodes(vm[0]['node']).tasks(taskid).status.get()['status'] == 'stopped'
-        and proxmox.nodes(vm[0]['node']).tasks(taskid).status.get()['exitstatus'] == 'OK' ):
-      return True
-    timeout = timeout - 1
-    if timeout == 0:
-      module.fail_json(msg='Reached timeout while waiting for stopping VM. Last line in task before timeout: %s'
-                       % proxmox.nodes(vm[0]['node']).tasks(taskid).log.get()[:1])
-
-    time.sleep(1)
-  return False
+    if force:
+        taskid = getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.shutdown.post(forceStop=1)
+    else:
+        taskid = getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.shutdown.post()
+    while timeout:
+        if (proxmox.nodes(vm[0]['node']).tasks(taskid).status.get()['status'] == 'stopped'
+            and proxmox.nodes(vm[0]['node']).tasks(taskid).status.get()['exitstatus'] == 'OK'):
+            return True
+        timeout = timeout - 1
+        if timeout == 0:
+            module.fail_json(msg='Reached timeout while waiting for stopping VM. Last line in task before timeout: %s'
+                             % proxmox.nodes(vm[0]['node']).tasks(taskid).log.get()[:1])
+        time.sleep(1)
+    return False
+
 
 def main():
-  module = AnsibleModule(
-      argument_spec = dict(
-          acpi = dict(type='bool', default='yes'),
-          agent = dict(type='bool'),
-          args = dict(type='str', default=None),
-          api_host = dict(required=True),
-          api_user = dict(required=True),
-          api_password = dict(no_log=True),
-          autostart = dict(type='bool', default='no'),
-          balloon = dict(type='int',default=0),
-          bios = dict(choices=['seabios', 'ovmf']),
-          boot = dict(type='str', default='cnd'),
-          bootdisk = dict(type='str'),
-          cores = dict(type='int', default=1),
-          cpu = dict(type='str', default='kvm64'),
-          cpulimit = dict(type='int'),
-          cpuunits = dict(type='int', default=1000),
-          delete = dict(type='str'),
-          description = dict(type='str'),
-          digest = dict(type='str'),
-          force = dict(type='bool', default=None),
-          freeze = dict(type='bool'),
-          hostpci = dict(type='dict'),
-          hotplug = dict(type='str'),
-          hugepages = dict(choices=['any', '2', '1024']),
-          ide = dict(type='dict', default=None),
-          keyboard = dict(type='str'),
-          kvm = dict(type='bool', default='yes'),
-          localtime = dict(type='bool'),
-          lock = dict(choices=['migrate', 'backup', 'snapshot', 'rollback']),
-          machine = dict(type='str'),
-          memory = dict(type='int', default=512),
-          migrate_downtime = dict(type='int'),
-          migrate_speed = dict(type='int'),
-          name = dict(type='str'),
-          net = dict(type='dict'),
-          node = dict(),
-          numa = dict(type='dict'),
-          onboot = dict(type='bool', default='yes'),
-          ostype = dict(default='l26', choices=['other', 'wxp', 'w2k', 'w2k3', 'w2k8', 'wvista', 'win7', 'win8', 'l24', 'l26', 'solaris']),
-          parallel = dict(type='dict'),
-          protection = dict(type='bool'),
-          reboot = dict(type='bool'),
-          revert = dict(),
-          sata = dict(type='dict'),
-          scsi = dict(type='dict'),
-          scsihw = dict(choices=['lsi', 'lsi53c810', 'virtio-scsi-pci', 'virtio-scsi-single', 'megasas', 'pvscsi']),
-          serial = dict(type='dict'),
-          shares = dict(type='int'),
-          skiplock = dict(type='bool'),
-          smbios = dict(type='str'),
-          sockets = dict(type='int', default=1),
-          startdate = dict(type='str'),
-          startup = dict(),
-          state = dict(default='present', choices=['present', 'absent', 'stopped', 'started', 'restarted', 'current']),
-          tablet = dict(type='bool', default='no'),
-          tdf = dict(type='bool'),
-          template = dict(type='bool', default='no'),
-          timeout = dict(type='int', default=30),
-          validate_certs = dict(type='bool', default='no'),
-          vcpus = dict(type='int', default=None),
-          vga = dict(default='std', choices=['std', 'cirrus', 'vmware', 'qxl', 'serial0', 'serial1', 'serial2', 'serial3', 'qxl2', 'qxl3', 'qxl4']),
-          virtio = dict(type='dict', default=None),
-          vmid = dict(type='int', default=None),
-          watchdog = dict(),
-          )
-  )
-
-  if not HAS_PROXMOXER:
-    module.fail_json(msg='proxmoxer required for this module')
-
-  api_user = module.params['api_user']
-  api_host = module.params['api_host']
-  api_password = module.params['api_password']
-  cpu = module.params['cpu']
-  cores = module.params['cores']
-  memory = module.params['memory']
-  name = module.params['name']
-  node = module.params['node']
-  sockets = module.params['sockets'],
-  state = module.params['state']
-  timeout = module.params['timeout']
-  validate_certs = module.params['validate_certs']
-
-  # If password not set get it from PROXMOX_PASSWORD env
-  if not api_password:
-    try:
-      api_password = os.environ['PROXMOX_PASSWORD']
-    except KeyError as e:
-      module.fail_json(msg='You should set api_password param or use PROXMOX_PASSWORD environment variable')
-
-  try:
-    proxmox = ProxmoxAPI(api_host, user=api_user, password=api_password, verify_ssl=validate_certs)
-    global VZ_TYPE
-    global PVE_MAJOR_VERSION
-    PVE_MAJOR_VERSION = 3 if float(proxmox.version.get()['version']) < 4.0 else 4
-  except Exception as e:
-    module.fail_json(msg='authorization on proxmox cluster failed with exception: %s' % e)
-
-
-  # If vmid not set get the Next VM id from ProxmoxAPI
-  # If vm name is set get the VM id from ProxmoxAPI
-  if module.params['vmid'] is not None:
+    module = AnsibleModule(
+        argument_spec = dict(
+            acpi = dict(type='bool', default='yes'),
+            agent = dict(type='bool'),
+            args = dict(type='str', default=None),
+            api_host = dict(required=True),
+            api_user = dict(required=True),
+            api_password = dict(no_log=True),
+            autostart = dict(type='bool', default='no'),
+            balloon = dict(type='int',default=0),
+            bios = dict(choices=['seabios', 'ovmf']),
+            boot = dict(type='str', default='cnd'),
+            bootdisk = dict(type='str'),
+            clone = dict(type='str', default=None),
+            cores = dict(type='int', default=1),
+            cpu = dict(type='str', default='kvm64'),
+            cpulimit = dict(type='int'),
+            cpuunits = dict(type='int', default=1000),
+            delete = dict(type='str', default=None),
+            description = dict(type='str'),
+            digest = dict(type='str'),
+            force = dict(type='bool', default=None),
+            format = dict(type='str', default='qcow2', choices=['cloop', 'cow', 'qcow', 'qcow2', 'qed', 'raw', 'vmdk' ]),
+            freeze = dict(type='bool'),
+            full = dict(type='bool', default='yes'),
+            hostpci = dict(type='dict'),
+            hotplug = dict(type='str'),
+            hugepages = dict(choices=['any', '2', '1024']),
+            ide = dict(type='dict', default=None),
+            keyboard = dict(type='str'),
+            kvm = dict(type='bool', default='yes'),
+            localtime = dict(type='bool'),
+            lock = dict(choices=['migrate', 'backup', 'snapshot', 'rollback']),
+            machine = dict(type='str'),
+            memory = dict(type='int', default=512),
+            migrate_downtime = dict(type='int'),
+            migrate_speed = dict(type='int'),
+            name = dict(type='str'),
+            net = dict(type='dict'),
+            newid = dict(type='int', default=None),
+            node = dict(),
+            numa = dict(type='dict'),
+            numa_enabled = dict(type='bool'),
+            onboot = dict(type='bool', default='yes'),
+            ostype = dict(default='l26', choices=['other', 'wxp', 'w2k', 'w2k3', 'w2k8', 'wvista', 'win7', 'win8', 'l24', 'l26', 'solaris']),
+            parallel = dict(type='dict'),
+            pool = dict(type='str'),
+            protection = dict(type='bool'),
+            reboot = dict(type='bool'),
+            revert = dict(type='str', default=None),
+            sata = dict(type='dict'),
+            scsi = dict(type='dict'),
+            scsihw = dict(choices=['lsi', 'lsi53c810', 'virtio-scsi-pci', 'virtio-scsi-single', 'megasas', 'pvscsi']),
+            serial = dict(type='dict'),
+            shares = dict(type='int'),
+            skiplock = dict(type='bool'),
+            smbios = dict(type='str'),
+            snapname = dict(type='str'),
+            sockets = dict(type='int', default=1),
+            startdate = dict(type='str'),
+            startup = dict(),
+            state = dict(default='present', choices=['present', 'absent', 'stopped', 'started', 'restarted', 'current']),
+            storage = dict(type='str'),
+            tablet = dict(type='bool', default='no'),
+            target = dict(type='str'),
+            tdf = dict(type='bool'),
+            template = dict(type='bool', default='no'),
+            timeout = dict(type='int', default=30),
+            update = dict(type='bool', default='no'),
+            validate_certs = dict(type='bool', default='no'),
+            vcpus = dict(type='int', default=None),
+            vga = dict(default='std', choices=['std', 'cirrus', 'vmware', 'qxl', 'serial0', 'serial1', 'serial2', 'serial3', 'qxl2', 'qxl3', 'qxl4']),
+            virtio = dict(type='dict', default=None),
+            vmid = dict(type='int', default=None),
+            watchdog = dict(),
+        ),
+        mutually_exclusive = [('delete', 'revert'), ('delete','update'), ('revert','update'), ('clone', 'update'), ('clone', 'delete'), ('clone','revert')],
+        required_one_of=[('name','vmid',)],
+        required_if=[('state', 'present', ['node'])]
+    )
+
+    if not HAS_PROXMOXER:
+        module.fail_json(msg='proxmoxer required for this module')
+
+    api_user = module.params['api_user']
+    api_host = module.params['api_host']
+    api_password = module.params['api_password']
+    clone = module.params['clone']
+    cpu = module.params['cpu']
+    cores = module.params['cores']
+    delete = module.params['delete']
+    memory = module.params['memory']
+    name = module.params['name']
+    newid = module.params['newid']
+    node = module.params['node']
+    revert = module.params['revert']
+    sockets = module.params['sockets']
+    state = module.params['state']
+    timeout = module.params['timeout']
+    update = bool(module.params['update'])
     vmid = module.params['vmid']
-  elif state == 'present':
-    vmid = get_nextvmid(proxmox)
-  elif module.params['name'] is not None:
-    vmid = get_vmid(proxmox, name)[0]
+    validate_certs = module.params['validate_certs']
+
+    # If password not set get it from PROXMOX_PASSWORD env
+    if not api_password:
+        try:
+            api_password = os.environ['PROXMOX_PASSWORD']
+        except KeyError as e:
+            module.fail_json(msg='You should set api_password param or use PROXMOX_PASSWORD environment variable')
 
-  if state == 'present':
     try:
-      if get_vm(proxmox, vmid) and not module.params['force']:
-        module.exit_json(changed=False, msg="VM with vmid <%s> already exists" % vmid)
-      elif get_vmid(proxmox, name) and not module.params['force']:
-        module.exit_json(changed=False, msg="VM with name <%s> already exists" % name)
-      elif not (node, module.params['name']):
-        module.fail_json(msg='node, name is mandatory for creating vm')
-      elif not node_check(proxmox, node):
-        module.fail_json(msg="node '%s' does not exist in cluster" % node)
-
-      create_vm(module, proxmox, vmid, node, name, memory, cpu, cores, sockets, timeout,
+        proxmox = ProxmoxAPI(api_host, user=api_user, password=api_password, verify_ssl=validate_certs)
+        global VZ_TYPE
+        global PVE_MAJOR_VERSION
+        PVE_MAJOR_VERSION = 3 if float(proxmox.version.get()['version']) < 4.0 else 4
+    except Exception as e:
+        module.fail_json(msg='authorization on proxmox cluster failed with exception: %s' % e)
+
+    # If vmid not set get the Next VM id from ProxmoxAPI
+    # If vm name is set get the VM id from ProxmoxAPI
+    if not vmid:
+        if state == 'present' and ( not update and not clone) and (not delete and not revert):
+            try:
+                vmid = get_nextvmid(proxmox)
+            except Exception as e:
+                module.fail_json(msg="Can't get the next vimd for VM {} automatically. Ensure your cluster state is good".format(name))
+        else:
+            try:
+                if not clone:
+                    vmid = get_vmid(proxmox, name)[0]
+                else:
+                    vmid = get_vmid(proxmox, clone)[0]
+            except Exception as e:
+                if not clone:
+                    module.fail_json(msg="VM {} does not exist in cluster.".format(name))
+                else:
+                    module.fail_json(msg="VM {} does not exist in cluster.".format(clone))
+
+    if clone is not None:
+        if get_vmid(proxmox, name):
+            module.exit_json(changed=False, msg="VM with name <%s> already exists" % name)
+        if vmid is not None:
+            vm = get_vm(proxmox, vmid)
+            if not vm:
+                module.fail_json(msg='VM with vmid = %s does not exist in cluster' % vmid)
+        if not newid:
+            try:
+                newid = get_nextvmid(proxmox)
+            except Exception as e:
+                module.fail_json(msg="Can't get the next vimd for VM {} automatically. Ensure your cluster state is good".format(name))
+        else:
+            vm = get_vm(proxmox, newid)
+            if vm:
+                module.exit_json(changed=False, msg="vmid %s with VM name %s already exists" % (newid, name))
+
+    if delete is not None:
+        try:
+            settings(module, proxmox, vmid, node, name, timeout, delete=delete)
+            module.exit_json(changed=True, msg="Settings has deleted on VM {} with vmid {}".format(name, vmid))
+        except Exception as e:
+            module.fail_json(msg='Unable to delete settings on VM {} with vimd {}: '.format(name, vmid) + str(e))
+    elif revert is not None:
+        try:
+            settings(module, proxmox, vmid, node, name, timeout, revert=revert)
+            module.exit_json(changed=True, msg="Settings has reverted on VM {} with vmid {}".format(name, vmid))
+        except Exception as e:
+            module.fail_json(msg='Unable to revert settings on VM {} with vimd {}: Maybe is not a pending task...   '.format(name, vmid) + str(e))
+
+    if state == 'present':
+        try:
+            if get_vm(proxmox, vmid) and not (update or clone):
+                module.exit_json(changed=False, msg="VM with vmid <%s> already exists" % vmid)
+            elif get_vmid(proxmox, name) and not (update or clone):
+                module.exit_json(changed=False, msg="VM with name <%s> already exists" % name)
+            elif not (node, name):
+                module.fail_json(msg='node, name is mandatory for creating/updating vm')
+            elif not node_check(proxmox, node):
+                module.fail_json(msg="node '%s' does not exist in cluster" % node)
+
+            create_vm(module, proxmox, vmid, newid, node, name, memory, cpu, cores, sockets, timeout, update,
                       acpi = module.params['acpi'],
                       agent = module.params['agent'],
                       autostart = module.params['autostart'],
@@ -924,7 +1092,6 @@ def main():
                       bootdisk = module.params['bootdisk'],
                       cpulimit = module.params['cpulimit'],
                       cpuunits = module.params['cpuunits'],
-                      delete = module.params['delete'],
                       description = module.params['description'],
                       digest = module.params['digest'],
                       force = module.params['force'],
@@ -942,12 +1109,13 @@ def main():
                       migrate_speed = module.params['migrate_speed'],
                       net = module.params['net'],
                       numa = module.params['numa'],
+                      numa_enabled = module.params['numa_enabled'],
                       onboot = module.params['onboot'],
                       ostype = module.params['ostype'],
                       parallel = module.params['parallel'],
+                      pool = module.params['pool'],
                       protection = module.params['protection'],
                       reboot = module.params['reboot'],
-                      revert = module.params['revert'],
                       sata = module.params['sata'],
                       scsi = module.params['scsi'],
                       scsihw = module.params['scsihw'],
@@ -955,9 +1123,11 @@ def main():
                       shares = module.params['shares'],
                       skiplock = module.params['skiplock'],
                       smbios1 = module.params['smbios'],
+                      snapname = module.params['snapname'],
                       startdate = module.params['startdate'],
                       startup = module.params['startup'],
                       tablet = module.params['tablet'],
+                      target = module.params['target'],
                       tdf = module.params['tdf'],
                       template = module.params['template'],
                       vcpus = module.params['vcpus'],
@@ -965,92 +1135,104 @@ def main():
                       virtio = module.params['virtio'],
                       watchdog = module.params['watchdog'])
 
-      get_vminfo(module, proxmox, node, vmid,
-              ide = module.params['ide'],
-              net = module.params['net'],
-              sata = module.params['sata'],
-              scsi = module.params['scsi'],
-              virtio = module.params['virtio'])
-      module.exit_json(changed=True, msg="VM %s with vmid %s deployed" % (name, vmid), **results)
-    except Exception as e:
-          module.fail_json(msg="creation of %s VM %s with vmid %s failed with exception: %s" % ( VZ_TYPE, name, vmid, e ))
-
-  elif state == 'started':
-    try:
-      vm = get_vm(proxmox, vmid)
-      if not vm:
-        module.fail_json(msg='VM with vmid <%s> does not exist in cluster' % vmid)
-      if getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.current.get()['status'] == 'running':
-        module.exit_json(changed=False, msg="VM %s is already running" % vmid)
-
-      if start_vm(module, proxmox, vm, vmid, timeout):
-        module.exit_json(changed=True, msg="VM %s started" % vmid)
-    except Exception as e:
-      module.fail_json(msg="starting of VM %s failed with exception: %s" % ( vmid, e ))
-
-  elif state == 'stopped':
-    try:
-      vm = get_vm(proxmox, vmid)
-      if not vm:
-        module.fail_json(msg='VM with vmid = %s does not exist in cluster' % vmid)
-
-      if getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.current.get()['status'] == 'stopped':
-        module.exit_json(changed=False, msg="VM %s is already stopped" % vmid)
+            if not clone:
+                get_vminfo(module, proxmox, node, vmid,
+                    ide = module.params['ide'],
+                    net = module.params['net'],
+                    sata = module.params['sata'],
+                    scsi = module.params['scsi'],
+                    virtio = module.params['virtio'])
+            if update:
+                module.exit_json(changed=True, msg="VM %s with vmid %s updated" % (name, vmid))
+            elif clone is not None:
+                module.exit_json(changed=True, msg="VM %s with newid %s cloned from vm with vmid %s" % (name, newid, vmid))
+            else:
+                module.exit_json(changed=True, msg="VM %s with vmid %s deployed" % (name, vmid), **results)
+        except Exception as e:
+            if update:
+                module.fail_json(msg="Unable to update vm {} with vimd {}=".format(name, vmid) + str(e))
+            elif clone is not None:
+                module.fail_json(msg="Unable to clone vm {} from vimd {}=".format(name, vmid) + str(e))
+            else:
+                module.fail_json(msg="creation of %s VM %s with vmid %s failed with exception=%s" % (VZ_TYPE, name, vmid, e))
+
+    elif state == 'started':
+        try:
+            vm = get_vm(proxmox, vmid)
+            if not vm:
+                module.fail_json(msg='VM with vmid <%s> does not exist in cluster' % vmid)
+            if getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.current.get()['status'] == 'running':
+                module.exit_json(changed=False, msg="VM %s is already running" % vmid)
+
+            if start_vm(module, proxmox, vm, vmid, timeout):
+                module.exit_json(changed=True, msg="VM %s started" % vmid)
+        except Exception as e:
+            module.fail_json(msg="starting of VM %s failed with exception: %s" % (vmid, e))
 
-      if stop_vm(module, proxmox, vm, vmid, timeout, force = module.params['force']):
-        module.exit_json(changed=True, msg="VM %s is shutting down" % vmid)
-    except Exception as e:
-      module.fail_json(msg="stopping of VM %s failed with exception: %s" % ( vmid, e ))
+    elif state == 'stopped':
+        try:
+            vm = get_vm(proxmox, vmid)
+            if not vm:
+                module.fail_json(msg='VM with vmid = %s does not exist in cluster' % vmid)
 
-  elif state == 'restarted':
-    try:
-      vm = get_vm(proxmox, vmid)
-      if not vm:
-        module.fail_json(msg='VM with vmid = %s does not exist in cluster' % vmid)
-      if getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.current.get()['status'] == 'stopped':
-        module.exit_json(changed=False, msg="VM %s is not running" % vmid)
-
-      if ( stop_vm(module, proxmox, vm, vmid, timeout, force = module.params['force']) and
-          start_vm(module, proxmox, vm, vmid, timeout) ):
-        module.exit_json(changed=True, msg="VM %s is restarted" % vmid)
-    except Exception as e:
-      module.fail_json(msg="restarting of VM %s failed with exception: %s" % ( vmid, e ))
+            if getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.current.get()['status'] == 'stopped':
+                module.exit_json(changed=False, msg="VM %s is already stopped" % vmid)
 
-  elif state == 'absent':
-    try:
-      vm = get_vm(proxmox, vmid)
-      if not vm:
-        module.exit_json(changed=False, msg="VM %s does not exist" % vmid)
+            if stop_vm(module, proxmox, vm, vmid, timeout, force = module.params['force']):
+                module.exit_json(changed=True, msg="VM %s is shutting down" % vmid)
+        except Exception as e:
+            module.fail_json(msg="stopping of VM %s failed with exception: %s" % (vmid, e))
 
-      if getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.current.get()['status'] == 'running':
-        module.exit_json(changed=False, msg="VM %s is running. Stop it before deletion." % vmid)
+    elif state == 'restarted':
+        try:
+            vm = get_vm(proxmox, vmid)
+            if not vm:
+                module.fail_json(msg='VM with vmid = %s does not exist in cluster' % vmid)
+            if getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.current.get()['status'] == 'stopped':
+                module.exit_json(changed=False, msg="VM %s is not running" % vmid)
+
+            if (stop_vm(module, proxmox, vm, vmid, timeout, force = module.params['force'])
+                    and start_vm(module, proxmox, vm, vmid, timeout)):
+                module.exit_json(changed=True, msg="VM %s is restarted" % vmid)
+        except Exception as e:
+            module.fail_json(msg="restarting of VM %s failed with exception: %s" % ( vmid, e ))
 
-      taskid = getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE).delete(vmid)
-      while timeout:
-        if ( proxmox.nodes(vm[0]['node']).tasks(taskid).status.get()['status'] == 'stopped'
-            and proxmox.nodes(vm[0]['node']).tasks(taskid).status.get()['exitstatus'] == 'OK' ):
-          module.exit_json(changed=True, msg="VM %s removed" % vmid)
-        timeout = timeout - 1
-        if timeout == 0:
-          module.fail_json(msg='Reached timeout while waiting for removing VM. Last line in task before timeout: %s'
-                           % proxmox_node.tasks(taskid).log.get()[:1])
+    elif state == 'absent':
+        try:
+            vm = get_vm(proxmox, vmid)
+            if not vm:
+                module.exit_json(changed=False, msg="VM %s does not exist" % vmid)
+
+            if getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.current.get()['status'] == 'running':
+                module.exit_json(changed=False, msg="VM %s is running. Stop it before deletion." % vmid)
+
+            taskid = getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE).delete(vmid)
+            while timeout:
+                if (proxmox.nodes(vm[0]['node']).tasks(taskid).status.get()['status'] == 'stopped'
+                    and proxmox.nodes(vm[0]['node']).tasks(taskid).status.get()['exitstatus'] == 'OK' ):
+                    module.exit_json(changed=True, msg="VM %s removed" % vmid)
+                timeout = timeout - 1
+                if timeout == 0:
+                    module.fail_json(msg='Reached timeout while waiting for removing VM. Last line in task before timeout: %s'
+                                     % proxmox_node.tasks(taskid).log.get()[:1])
+
+                time.sleep(1)
+        except Exception as e:
+            module.fail_json(msg="deletion of VM %s failed with exception: %s" % (vmid, e))
 
-        time.sleep(1)
-    except Exception as e:
-      module.fail_json(msg="deletion of VM %s failed with exception: %s" % ( vmid, e ))
+    elif state == 'current':
+        status = {}
+        try:
+            vm = get_vm(proxmox, vmid)
+            if not vm:
+                module.fail_json(msg='VM with vmid = %s does not exist in cluster' % vmid)
+            current = getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.current.get()['status']
+            status['status'] = current
+            if status:
+                module.exit_json(changed=False, msg="VM %s with vmid = %s is %s" % (name, vmid, current), **status)
+        except Exception as e:
+            module.fail_json(msg="Unable to get vm {} with vmid = {} status: ".format(name, vmid) + str(e))
 
-  elif state == 'current':
-    status = {}
-    try:
-      vm = get_vm(proxmox, vmid)
-      if not vm:
-        module.fail_json(msg='VM with vmid = %s does not exist in cluster' % vmid)
-      current = getattr(proxmox.nodes(vm[0]['node']), VZ_TYPE)(vmid).status.current.get()['status']
-      status['status'] = current
-      if status:
-         module.exit_json(changed=False, msg="VM %s with vmid = %s is %s" % (name, vmid, current), **status)
-    except Exception as e:
-      module.fail_json(msg="Unable to get vm {} with vmid = {} status: ".format(name, vmid) + str(e))
 
 # import module snippets
 from ansible.module_utils.basic import *


Test patch: