Repository: ansible/ansible

Issue:
Update vmware_host
##### SUMMARY
Fix adds following:
* Update logic in vmware_host
* Update example documentation
* Added test case for vmware_host

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>

##### ISSUE TYPE
 - Feature Pull Request

##### COMPONENT NAME
lib/ansible/modules/cloud/vmware/vmware_host.py
test/integration/targets/vmware_host/aliases
test/integration/targets/vmware_host/tasks/main.yml

##### ANSIBLE VERSION
```
2.4devel
```


Discussion:

Resolving patch:
diff --git a/lib/ansible/modules/cloud/vmware/vmware_host.py b/lib/ansible/modules/cloud/vmware/vmware_host.py
--- a/lib/ansible/modules/cloud/vmware/vmware_host.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_host.py
@@ -22,67 +22,66 @@
                     'status': ['preview'],
                     'supported_by': 'community'}
 
-
-DOCUMENTATION = '''
+DOCUMENTATION = r'''
 ---
 module: vmware_host
 short_description: Add/remove ESXi host to/from vCenter
 description:
-    - This module can be used to add/remove an ESXi host to/from vCenter
-version_added: 2.0
-author: "Joseph Callen (@jcpowermac), Russell Teague (@mtnbikenc)"
+- This module can be used to add/remove an ESXi host to/from vCenter.
+version_added: '2.0'
+author:
+- Joseph Callen (@jcpowermac)
+- Russell Teague (@mtnbikenc)
 notes:
-    - Tested on vSphere 5.5
+- Tested on vSphere 5.5
 requirements:
-    - "python >= 2.6"
-    - PyVmomi
+- python >= 2.6
+- PyVmomi
 options:
-    datacenter_name:
-        description:
-            - Name of the datacenter to add the host
-        required: True
-    cluster_name:
-        description:
-            - Name of the cluster to add the host
-        required: True
-    esxi_hostname:
-        description:
-            - ESXi hostname to manage
-        required: True
-    esxi_username:
-        description:
-            - ESXi username
-        required: True
-    esxi_password:
-        description:
-            - ESXi password
-        required: True
-    state:
-        description:
-            - Add or remove the host
-        default: 'present'
-        choices:
-            - 'present'
-            - 'absent'
-        required: False
+  datacenter_name:
+    description:
+    - Name of the datacenter to add the host.
+    required: yes
+  cluster_name:
+    description:
+    - Name of the cluster to add the host.
+    required: yes
+  esxi_hostname:
+    description:
+    - ESXi hostname to manage.
+    required: yes
+  esxi_username:
+    description:
+    - ESXi username.
+    required: yes
+  esxi_password:
+    description:
+    - ESXi password.
+    required: yes
+  state:
+    description:
+    - Add or remove the host.
+    choices: [absent, present]
+    default: present
 extends_documentation_fragment: vmware.documentation
 '''
 
-EXAMPLES = '''
-# Example from Ansible playbook
-
-    - name: Add ESXi Host to VCSA
-      local_action:
-        module: vmware_host
-        hostname: vcsa_host
-        username: vcsa_user
-        password: vcsa_pass
-        datacenter_name: datacenter_name
-        cluster_name: cluster_name
-        esxi_hostname: esxi_hostname
-        esxi_username: esxi_username
-        esxi_password: esxi_password
-        state: present
+EXAMPLES = r'''
+- name: Add ESXi Host to vCenter
+  vmware_host:
+    hostname: '{{ vcenter_hostname }}'
+    username: '{{ vcenter_username }}'
+    password: '{{ vcenter_password }}'
+    datacenter_name: datacenter_name
+    cluster_name: cluster_name
+    esxi_hostname: '{{ esxi_hostname }}'
+    esxi_username: '{{ esxi_username }}'
+    esxi_password: '{{ esxi_password }}'
+    state: present
+  delegate_to: localhost
+'''
+
+RETURN = r'''
 '''
 
 try:
@@ -91,6 +90,16 @@
 except ImportError:
     HAS_PYVMOMI = False
 
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.vmware import (
+    TaskError,
+    connect_to_api,
+    find_cluster_by_name,
+    find_datacenter_by_name,
+    vmware_argument_spec,
+    wait_for_task,
+)
+
 
 class VMwareHost(object):
     def __init__(self, module):
@@ -131,7 +140,10 @@ def process_state(self):
 
     def find_host_by_cluster_datacenter(self):
         self.dc = find_datacenter_by_name(self.content, self.datacenter_name)
-        self.cluster = find_cluster_by_name_datacenter(self.dc, self.cluster_name)
+        self.cluster = find_cluster_by_name(self.content, self.cluster_name, self.dc)
+
+        if self.cluster is None:
+            self.module.fail_json(msg="Unable to find cluster %(cluster_name)s" % self.module.params)
 
         for host in self.cluster.host:
             if host.name == self.esxi_hostname:
@@ -208,14 +220,19 @@ def check_host_state(self):
 
 def main():
     argument_spec = vmware_argument_spec()
-    argument_spec.update(dict(datacenter_name=dict(required=True, type='str'),
-                              cluster_name=dict(required=True, type='str'),
-                              esxi_hostname=dict(required=True, type='str'),
-                              esxi_username=dict(required=True, type='str'),
-                              esxi_password=dict(required=True, type='str', no_log=True),
-                              state=dict(default='present', choices=['present', 'absent'], type='str')))
-
-    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
+    argument_spec.update(
+        datacenter_name=dict(type='str', required=True),
+        cluster_name=dict(type='str'),
+        esxi_hostname=dict(type='str', required=True),
+        esxi_username=dict(type='str', required=True),
+        esxi_password=dict(type='str', required=True, no_log=True),
+        state=dict(type='str', default='present', choices=['absent', 'present'])
+    )
+
+    module = AnsibleModule(
+        argument_spec=argument_spec,
+        supports_check_mode=True,
+    )
 
     if not HAS_PYVMOMI:
         module.fail_json(msg='pyvmomi is required for this module')
@@ -223,8 +240,5 @@ def main():
     vmware_host = VMwareHost(module)
     vmware_host.process_state()
 
-from ansible.module_utils.vmware import *
-from ansible.module_utils.basic import *
-
 if __name__ == '__main__':
     main()


Test patch:
diff --git a/test/integration/targets/vmware_host/aliases b/test/integration/targets/vmware_host/aliases
new file mode 100644
--- /dev/null
+++ b/test/integration/targets/vmware_host/aliases
@@ -0,0 +1,2 @@
+posix/ci/cloud/vcenter
+cloud/vcenter
diff --git a/test/integration/targets/vmware_host/tasks/main.yml b/test/integration/targets/vmware_host/tasks/main.yml
new file mode 100644
--- /dev/null
+++ b/test/integration/targets/vmware_host/tasks/main.yml
@@ -0,0 +1,124 @@
+# Test code for the vmware_host module.
+# (c) 2017, Abhijeet Kasurde <akasurde@redhat.com>
+
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+
+- name: make sure pyvmomi is installed
+  pip:
+    name: pyvmomi
+    state: latest
+
+- name: store the vcenter container ip
+  set_fact:
+    vcsim: "{{ lookup('env', 'vcenter_host') }}"
+
+- debug: var=vcsim
+
+- name: Wait for Flask controller to come up online
+  wait_for:
+    host: "{{ vcsim }}"
+    port: 5000
+    state: started
+
+- name: kill vcsim
+  uri:
+    url: http://{{ vcsim }}:5000/killall
+
+- name: start vcsim
+  uri:
+    url: http://{{ vcsim }}:5000/spawn?cluster=2
+  register: vcsim_instance
+
+- debug:
+    var: vcsim_instance
+
+- name: Wait for vcsim server to come up online
+  wait_for:
+    host: "{{ vcsim }}"
+    port: 443
+    state: started
+
+- name: get a list of Datacenter from vcsim
+  uri:
+    url: http://{{ vcsim }}:5000/govc_find?filter=DC
+  register: datacenters
+
+- name: get a datacenter
+  set_fact:
+    dc1: "{{ datacenters.json[0] | basename }}"
+
+- debug: var=dc1
+
+
+- name: get a list of Cluster from vcsim
+  uri:
+    url: http://{{ vcsim }}:5000/govc_find?filter=CCR
+  register: clusters
+
+- name: get a cluster
+  set_fact:
+    ccr1: "{{ clusters.json[0] | basename }}"
+
+- debug: var=ccr1
+
+# Testcase 0001: Add Host
+- name: add host
+  vmware_host:
+    hostname: "{{ vcsim }}"
+    username: "{{ vcsim_instance.json.username }}"
+    password: "{{ vcsim_instance.json.password }}"
+    validate_certs: no
+    esxi_hostname: test_host_system_0001
+    esxi_username: "{{ vcsim_instance.json.username }}"
+    esxi_password: "{{ vcsim_instance.json.password }}"
+    datacenter_name: "{{ dc1 }}"
+    cluster_name: "{{ ccr1 }}"
+    state: present
+  register: host_system_result_0001
+
+- name: get a list of host system from vcsim after adding host system
+  uri:
+    url: http://{{ vcsim }}:5000/govc_find?filter=H
+  register: new_host_list
+
+- set_fact:
+    new_host: "{% for host in new_host_list.json %} {{ True if (host | basename) == 'test_host_system_0001' else False }} {% endfor %}"
+
+- name: ensure host system is present
+  assert:
+    that:
+        - host_system_result_0001.changed == true
+        - "'True' in new_host"
+
+# Testcase 0002: Add Host again
+- name: add host again
+  vmware_host:
+    hostname: "{{ vcsim }}"
+    username: "{{ vcsim_instance.json.username }}"
+    password: "{{ vcsim_instance.json.password }}"
+    validate_certs: no
+    esxi_hostname: test_host_system_0001
+    esxi_username: "{{ vcsim_instance.json.username }}"
+    esxi_password: "{{ vcsim_instance.json.password }}"
+    datacenter_name: "{{ dc1 }}"
+    cluster_name: "{{ ccr1 }}"
+    state: present
+  register: host_system_result_0002
+
+- name: ensure host system is present
+  assert:
+    that:
+        - host_system_result_0002.changed == false