Repository: ansible/ansible

Issue:
cloud/vmware/vmware_vswitch.py nic_name should be optional
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
cloud/vmware/vmware_vswitch.py

##### ANSIBLE VERSION
```
ansible 2.3.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609]

```

##### CONFIGURATION
n/a
##### OS / ENVIRONMENT
n/a
##### SUMMARY
The vmware_vswitch module erroneously assumes that 'nic_name' is required.  It is valid (and sometimes desired) to make a vmware virtual switch that does not have any uplink nics at all - the use case is multiple isolated port-groups for isolated networking. 

After the vswitch is created, we create a port-group with VLAN 4095 (all vlans), with network policy permitting mac changes, forged transmit, and promiscuous all enabled.

In /ansible/modules/cloud/vmware/vmware_vswitch.py , we can omit this line if nic_name is not specified and the port-group is created as desired.

```python
if self.nic_name:
    vss_spec.bridge = vim.host.VirtualSwitch.BondBridge(nicDevice=[self.nic_name])
```

##### STEPS TO REPRODUCE

Run ansible-playbook against a task using the vmware_vswitch module, omitting nic_name.
```
    - name: add test_switch
      local_action:
        module: vmware_vswitch
        hostname: esxi_host
        username: esxi_username
        password: esxi_password
        switch_name: item
        mtu: 9000
        validate_certs: no
        number_of_ports: 8
        #nic_name: 'null'

```

##### EXPECTED RESULTS
I expect the vmware vswitch to be created, but without any uplink nics.

##### ACTUAL RESULTS
```
fatal: [localhost -> localhost]: FAILED! => {"changed": false, "failed": true, "msg": "missing required arguments: nic_name"}
```


Discussion:

Resolving patch:
diff --git a/lib/ansible/modules/cloud/vmware/vmware_vswitch.py b/lib/ansible/modules/cloud/vmware/vmware_vswitch.py
--- a/lib/ansible/modules/cloud/vmware/vmware_vswitch.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_vswitch.py
@@ -44,7 +44,7 @@
     nic_name:
         description:
             - vmnic name to attach to vswitch
-        required: True
+        required: False
     number_of_ports:
         description:
             - Number of port to configure on vswitch
@@ -66,17 +66,24 @@
 '''
 
 EXAMPLES = '''
-# Example from Ansible playbook
-
-    - name: Add a VMware vSwitch
-      local_action:
-        module: vmware_vswitch
-        hostname: esxi_hostname
-        username: esxi_username
-        password: esxi_password
-        switch_name: vswitch_name
-        nic_name: vmnic_name
-        mtu: 9000
+- name: Add a VMware vSwitch
+  local_action:
+    module: vmware_vswitch
+    hostname: esxi_hostname
+    username: esxi_username
+    password: esxi_password
+    switch_name: vswitch_name
+    nic_name: vmnic_name
+    mtu: 9000
+
+- name: Add a VMWare vSwitch without any physical NIC attached
+  vmware_vswitch:
+    hostname: 192.168.10.1
+    username: admin
+    password: password123
+    switch_name: vswitch_0001
+    mtu: 9000
+
 '''
 
 try:
@@ -138,7 +145,8 @@ def state_create_vswitch(self):
         vss_spec = vim.host.VirtualSwitch.Specification()
         vss_spec.numPorts = self.number_of_ports
         vss_spec.mtu = self.mtu
-        vss_spec.bridge = vim.host.VirtualSwitch.BondBridge(nicDevice=[self.nic_name])
+        if self.nic_name:
+            vss_spec.bridge = vim.host.VirtualSwitch.BondBridge(nicDevice=[self.nic_name])
         self.host_system.configManager.networkSystem.AddVirtualSwitch(vswitchName=self.switch_name, spec=vss_spec)
         self.module.exit_json(changed=True)
 
@@ -184,7 +192,7 @@ def check_vswitch_configuration(self):
 def main():
     argument_spec = vmware_argument_spec()
     argument_spec.update(dict(switch_name=dict(required=True, type='str'),
-                         nic_name=dict(required=True, type='str'),
+                         nic_name=dict(required=False, type='str'),
                          number_of_ports=dict(required=False, type='int', default=128),
                          mtu=dict(required=False, type='int', default=1500),
                          state=dict(default='present', choices=['present', 'absent'], type='str')))


Test patch: