Repository: ansible/ansible

Issue:
vmware_guests require unnecessary privileges
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
vmware_guest module

##### ANSIBLE VERSION
```
ansible 2.3.0 (devel c3c4ae87dd) last updated 2017/05/31 11:17:49 (GMT +200)
  config file = 
  configured module search path = Default w/o overrides
```

##### OS / ENVIRONMENT
NA

##### SUMMARY
The vmware_guest module requires, when deploying a vm from template,  the permisions `VirtualMachine.Config.CPUCount` and `VirtualMachine.Config.Memory`

##### STEPS TO REPRODUCE 
Run this play
```yaml
-   hosts: localhost
    gather_facts: false
    tasks:
    -   name: test
        vmware_guest:
            datacenter: "datacenter"
            cluster: "cluster"
            name: hostname.domainname
            hostname: "vcenter"
            password: "username"
            username: "password"
            template: template
            folder: /vm
            disk:
            -   size: 25GB
                type: thin
                datastore: datastore
            networks:
            -   name: portgroupname
                ip: 192.168.1.10
                netmask: 255.255.255.0
                gateway: 192.168.1.1
            customization:
                dns_servers:
                -   8.8.8.8
                hostname: hostname
                domain: domainname
            state: poweredon
```
using the credentials of a user missing one or both of the `VirtualMachine.Config.CPUCount` and `VirtualMachine.Config.CPUCount` privileges

##### EXPECTED RESULTS
A vm should be deployed from the given template, inheriting settings from the template such as cpu count (`hardware.num_cpus` / `ConfigSpec.numCPUs`) and assigned RAM (`hardware.memory_mb` / `ConfigSpec.MemoryMB`)
##### ACTUAL RESULTS
The command fails with this error:
```
Traceback (most recent call last):
  File "/tmp/ansible_5yxo1b/ansible_module_vmware_guest.py", line 1384, in <module>
    main()
  File "/tmp/ansible_5yxo1b/ansible_module_vmware_guest.py", line 1373, in main
    result = pyv.deploy_vm()
  File "/tmp/ansible_5yxo1b/ansible_module_vmware_guest.py", line 1128, in deploy_vm
    task = vm_obj.Clone(folder=destfolder, name=self.params['name'], spec=clonespec)
  File "/usr/local/lib/python2.7/dist-packages/pyVmomi/VmomiSupport.py", line 580, in <lambda>
    self.f(*(self.args + (obj,) + args), **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/pyVmomi/VmomiSupport.py", line 386, in _InvokeMethod
    return self._stub.InvokeMethod(self, info, args)
  File "/usr/local/lib/python2.7/dist-packages/pyVmomi/SoapAdapter.py", line 1370, in InvokeMethod
    raise obj # pylint: disable-msg=E0702
pyVmomi.VmomiSupport.NoPermission: (vim.fault.NoPermission) {
   dynamicType = <unset>,
   dynamicProperty = (vmodl.DynamicProperty) [],
   msg = 'Permission to perform this operation was denied.',
   faultCause = <unset>,
   faultMessage = (vmodl.LocalizableMessage) [],
   object = 'vim.Folder:group-v3',
   privilegeId = 'VirtualMachine.Config.Memory'
}
```


Discussion:

Resolving patch:
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest.py b/lib/ansible/modules/cloud/vmware/vmware_guest.py
--- a/lib/ansible/modules/cloud/vmware/vmware_guest.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest.py
@@ -82,6 +82,8 @@
     description:
     - Manage some VM hardware attributes.
     - 'Valid attributes are:'
+    - ' - C(hotadd_cpu) (boolean): Allow cpus to be added while the VM is running.'
+    - ' - C(hotadd_memory) (boolean): Allow memory to be added while the VM is running.'
     - ' - C(memory_mb) (integer): Amount of memory in MB.'
     - ' - C(num_cpus) (integer): Number of CPUs.'
     - ' - C(scsi) (string): Valid values are C(buslogic), C(lsilogic), C(lsilogicsas) and C(paravirtual) (default).'
@@ -605,6 +607,16 @@ def configure_cpu_and_memory(self, vm_obj, vm_creation=False):
             elif vm_creation and not self.params['template']:
                 self.module.fail_json(msg="hardware.memory_mb attribute is mandatory for VM creation")
 
+            if 'hotadd_memory' in self.params['hardware']:
+                self.configspec.memoryHotAddEnabled = bool(self.params['hardware']['hotadd_memory'])
+                if vm_obj is None or self.configspec.memoryHotAddEnabled != vm_obj.config.memoryHotAddEnabled:
+                    self.change_detected = True
+
+            if 'hotadd_cpu' in self.params['hardware']:
+                self.configspec.cpuHotAddEnabled = bool(self.params['hardware']['hotadd_cpu'])
+                if vm_obj is None or self.configspec.cpuHotAddEnabled != vm_obj.config.cpuHotAddEnabled:
+                    self.change_detected = True
+
     def configure_cdrom(self, vm_obj):
         # Configure the VM CD-ROM
         if "cdrom" in self.params and self.params["cdrom"]:
@@ -1267,7 +1279,7 @@ def deploy_vm(self):
         # set the destination datastore for VM & disks
         (datastore, datastore_name) = self.select_datastore(vm_obj)
 
-        self.configspec = vim.vm.ConfigSpec(cpuHotAddEnabled=True, memoryHotAddEnabled=True)
+        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)


Test patch:
diff --git a/test/integration/targets/vmware_guest/tasks/create_d1_c1_f0.yml b/test/integration/targets/vmware_guest/tasks/create_d1_c1_f0.yml
--- a/test/integration/targets/vmware_guest/tasks/create_d1_c1_f0.yml
+++ b/test/integration/targets/vmware_guest/tasks/create_d1_c1_f0.yml
@@ -68,6 +68,8 @@
     hardware:
         num_cpus: 1
         memory_mb: 512
+        hotadd_memory: true
+        hotadd_cpu: false
     disk:
         - size: 0gb
           type: thin