mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
vmware_host: add reconnect and add_or_reconnect states (#30582)
* vmware_host: add reconnect and add_or_reconnect states Add "reconnect" and "add_or_reconnect" choices for "state". * reconnect: reconnect an esxi to a vcenter (imply it is present). * add_or_reconnect: do the same but add the esxi if absent. Also: * tag the cluster_name as required (because it is). * tag esxi_username and esxi_password as not required because they aren't when the esxi isn't added. * vmware_host: add + prepare/document integration tests vmware_host module Add integration test for the add part of "add_or_reconnect" state. Prepare and document integration tests for the reconnect part of "add_or_reconnect" state and "reconnect" and "absent" states. Currently we can't test those states as ReconnectHost_Task (for "reconnect") and EnterMaintenanceMode_Task (for "absent") aren't implemented yet in vcsim (from vmware/govmomi)
This commit is contained in:
parent
d08179593f
commit
29bed12cdd
2 changed files with 208 additions and 24 deletions
|
@ -17,11 +17,12 @@ 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.
|
||||
- This module can be used to add/remove/reconnect an ESXi host to/from vCenter.
|
||||
version_added: '2.0'
|
||||
author:
|
||||
- Joseph Callen (@jcpowermac)
|
||||
- Russell Teague (@mtnbikenc)
|
||||
- Maxime de Roucy (@tchernomax)
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
|
@ -35,6 +36,7 @@ options:
|
|||
cluster_name:
|
||||
description:
|
||||
- Name of the cluster to add the host.
|
||||
- Required from version 2.5.
|
||||
required: yes
|
||||
esxi_hostname:
|
||||
description:
|
||||
|
@ -43,16 +45,29 @@ options:
|
|||
esxi_username:
|
||||
description:
|
||||
- ESXi username.
|
||||
required: yes
|
||||
- Required for adding a host.
|
||||
- Optional for reconnect.
|
||||
- Unused for removing.
|
||||
- No longer required from version 2.5.
|
||||
esxi_password:
|
||||
description:
|
||||
- ESXi password.
|
||||
required: yes
|
||||
- Required for adding a host.
|
||||
- Optional for reconnect.
|
||||
- Unused for removing.
|
||||
- No longer required from version 2.5.
|
||||
state:
|
||||
description:
|
||||
- Add or remove the host.
|
||||
choices: [absent, present]
|
||||
- "present: add the host if it's absent else do nothing."
|
||||
- "absent: remove the host if it's present else do nothing."
|
||||
- "add_or_reconnect: add the host if it's absent else reconnect it."
|
||||
- "reconnect: reconnect the host if it's present else fail."
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
- add_or_reconnect
|
||||
- reconnect
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
|
@ -69,6 +84,30 @@ EXAMPLES = r'''
|
|||
esxi_password: '{{ esxi_password }}'
|
||||
state: present
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Reconnect ESXi Host (with username/password set)
|
||||
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: reconnect
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Reconnect ESXi Host (with default username/password)
|
||||
vmware_host:
|
||||
hostname: '{{ vcenter_hostname }}'
|
||||
username: '{{ vcenter_username }}'
|
||||
password: '{{ vcenter_password }}'
|
||||
datacenter_name: datacenter_name
|
||||
cluster_name: cluster_name
|
||||
esxi_hostname: '{{ esxi_hostname }}'
|
||||
state: reconnect
|
||||
delegate_to: localhost
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
|
@ -99,7 +138,6 @@ class VMwareHost(object):
|
|||
self.esxi_username = module.params['esxi_username']
|
||||
self.esxi_password = module.params['esxi_password']
|
||||
self.state = module.params['state']
|
||||
self.dc = None
|
||||
self.cluster = None
|
||||
self.host = None
|
||||
self.content = connect_to_api(module)
|
||||
|
@ -115,6 +153,13 @@ class VMwareHost(object):
|
|||
'present': {
|
||||
'present': self.state_exit_unchanged,
|
||||
'absent': self.state_add_host,
|
||||
},
|
||||
'add_or_reconnect': {
|
||||
'present': self.state_reconnect_host,
|
||||
'absent': self.state_add_host,
|
||||
},
|
||||
'reconnect': {
|
||||
'present': self.state_reconnect_host,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,6 +173,10 @@ class VMwareHost(object):
|
|||
self.module.fail_json(msg=str(e))
|
||||
|
||||
def add_host_to_vcenter(self):
|
||||
|
||||
if self.esxi_username is None or self.esxi_password is None:
|
||||
self.module.fail_json(msg='esxi_username and esxi_password are required to add a host')
|
||||
|
||||
host_connect_spec = vim.host.ConnectSpec()
|
||||
host_connect_spec.hostName = self.esxi_hostname
|
||||
host_connect_spec.userName = self.esxi_username
|
||||
|
@ -156,6 +205,32 @@ class VMwareHost(object):
|
|||
success, result = wait_for_task(task)
|
||||
return success, result
|
||||
|
||||
def reconnect_host_to_vcenter(self):
|
||||
reconnecthost_args = {}
|
||||
reconnecthost_args['reconnectSpec'] = vim.HostSystem.ReconnectSpec()
|
||||
reconnecthost_args['reconnectSpec'].syncState = True
|
||||
|
||||
if self.esxi_username is not None or self.esxi_password is not None:
|
||||
reconnecthost_args['cnxSpec'] = vim.host.ConnectSpec()
|
||||
reconnecthost_args['cnxSpec'].hostName = self.esxi_hostname
|
||||
reconnecthost_args['cnxSpec'].userName = self.esxi_username
|
||||
reconnecthost_args['cnxSpec'].password = self.esxi_password
|
||||
reconnecthost_args['cnxSpec'].force = True
|
||||
reconnecthost_args['cnxSpec'].sslThumbprint = ""
|
||||
|
||||
try:
|
||||
task = self.host.ReconnectHost_Task(**reconnecthost_args)
|
||||
success, result = wait_for_task(task)
|
||||
return success, result
|
||||
except TaskError as add_task_error:
|
||||
# See add_host_to_vcenter
|
||||
ssl_verify_fault = add_task_error.args[0]
|
||||
reconnecthost_args['cnxSpec'].sslThumbprint = ssl_verify_fault.thumbprint
|
||||
|
||||
task = self.host.ReconnectHost_Task(**reconnecthost_args)
|
||||
success, result = wait_for_task(task)
|
||||
return success, result
|
||||
|
||||
def state_exit_unchanged(self):
|
||||
self.module.exit_json(changed=False)
|
||||
|
||||
|
@ -185,6 +260,14 @@ class VMwareHost(object):
|
|||
changed, result = self.add_host_to_vcenter()
|
||||
self.module.exit_json(changed=changed, result=str(result))
|
||||
|
||||
def state_reconnect_host(self):
|
||||
changed = True
|
||||
result = None
|
||||
|
||||
if not self.module.check_mode:
|
||||
changed, result = self.reconnect_host_to_vcenter()
|
||||
self.module.exit_json(changed=changed, result=str(result))
|
||||
|
||||
def check_host_state(self):
|
||||
self.host, self.cluster = find_host_by_cluster_datacenter(self.module, self.content, self.datacenter_name,
|
||||
self.cluster_name, self.esxi_hostname)
|
||||
|
@ -199,17 +282,20 @@ def main():
|
|||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(
|
||||
datacenter_name=dict(type='str', required=True),
|
||||
cluster_name=dict(type='str'),
|
||||
cluster_name=dict(type='str', required=True),
|
||||
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'])
|
||||
)
|
||||
esxi_username=dict(type='str', required=False),
|
||||
esxi_password=dict(type='str', required=False, no_log=True),
|
||||
state=dict(default='present',
|
||||
choices=['present', 'absent', 'add_or_reconnect', 'reconnect'],
|
||||
type='str'))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
required_if=[
|
||||
['state', 'present', ['esxi_username', 'esxi_password']],
|
||||
['state', 'add_or_reconnect', ['esxi_username', 'esxi_password']]])
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
|
||||
- debug: var=dc1
|
||||
|
||||
|
||||
- name: get a list of Cluster from vcsim
|
||||
uri:
|
||||
url: http://{{ vcsim }}:5000/govc_find?filter=CCR
|
||||
|
@ -61,7 +60,7 @@
|
|||
|
||||
- debug: var=ccr1
|
||||
|
||||
# Testcase 0001: Add Host
|
||||
# Testcase: Add Host
|
||||
- name: add host
|
||||
vmware_host:
|
||||
hostname: "{{ vcsim }}"
|
||||
|
@ -74,23 +73,20 @@
|
|||
datacenter_name: "{{ dc1 }}"
|
||||
cluster_name: "{{ ccr1 }}"
|
||||
state: present
|
||||
register: host_system_result_0001
|
||||
register: add_host_result
|
||||
|
||||
- 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 %}"
|
||||
register: host_list
|
||||
|
||||
- name: ensure host system is present
|
||||
assert:
|
||||
that:
|
||||
- host_system_result_0001.changed == true
|
||||
- "'True' in new_host"
|
||||
- add_host_result | changed
|
||||
- "{% for host in host_list.json if ((host | basename) == 'test_host_system_0001') -%} True {%- else -%} False {%- endfor %}"
|
||||
|
||||
# Testcase 0002: Add Host again
|
||||
# Testcase: Add Host again
|
||||
- name: add host again
|
||||
vmware_host:
|
||||
hostname: "{{ vcsim }}"
|
||||
|
@ -103,9 +99,111 @@
|
|||
datacenter_name: "{{ dc1 }}"
|
||||
cluster_name: "{{ ccr1 }}"
|
||||
state: present
|
||||
register: host_system_result_0002
|
||||
register: readd_host_result
|
||||
|
||||
- name: ensure precend task didn't changed anything
|
||||
assert:
|
||||
that:
|
||||
- not (readd_host_result|changed)
|
||||
|
||||
# Testcase: Add Host via add_or_reconnect state
|
||||
- name: add host via add_or_reconnect
|
||||
vmware_host:
|
||||
hostname: "{{ vcsim }}"
|
||||
username: "{{ vcsim_instance.json.username }}"
|
||||
password: "{{ vcsim_instance.json.password }}"
|
||||
validate_certs: no
|
||||
esxi_hostname: test_host_system_0002
|
||||
esxi_username: "{{ vcsim_instance.json.username }}"
|
||||
esxi_password: "{{ vcsim_instance.json.password }}"
|
||||
datacenter_name: "{{ dc1 }}"
|
||||
cluster_name: "{{ ccr1 }}"
|
||||
state: add_or_reconnect
|
||||
register: add_or_reconnect_host_result
|
||||
|
||||
- name: get a list of host system from vcsim after adding host system
|
||||
uri:
|
||||
url: http://{{ vcsim }}:5000/govc_find?filter=H
|
||||
register: host_list
|
||||
|
||||
- name: ensure host system is present
|
||||
assert:
|
||||
that:
|
||||
- host_system_result_0002.changed == false
|
||||
- add_or_reconnect_host_result | changed
|
||||
- "{% for host in host_list.json if ((host | basename) == 'test_host_system_0002') -%} True {%- else -%} False {%- endfor %}"
|
||||
|
||||
## Testcase: Reconnect Host
|
||||
#
|
||||
# ReconnectHost_Task need to be implemented in vcsim for this test to work
|
||||
# https://github.com/vmware/govmomi/tree/master/vcsim#supported-methods
|
||||
#
|
||||
#- name: reconnect host
|
||||
# vmware_host:
|
||||
# hostname: "{{ vcsim }}"
|
||||
# username: "{{ vcsim_instance.json.username }}"
|
||||
# password: "{{ vcsim_instance.json.password }}"
|
||||
# validate_certs: no
|
||||
# esxi_hostname: test_host_system_0001
|
||||
# datacenter_name: "{{ dc1 }}"
|
||||
# cluster_name: "{{ ccr1 }}"
|
||||
# state: reconnect
|
||||
# register: reconnect_host_result
|
||||
#
|
||||
#- name: ensure host system has been reconnected
|
||||
# assert:
|
||||
# that:
|
||||
# - reconnect_host_result | changed
|
||||
# # it would be a good idea to check the events on the host to see the reconnect
|
||||
# # https://github.com/vmware/govmomi/blob/master/govc/USAGE.md#events
|
||||
# # "govc events ..." need to be callable from
|
||||
# # test/utils/docker/vcenter-simulator/flask_control.py
|
||||
|
||||
## Testcase: Remove Host
|
||||
#
|
||||
# EnterMaintenanceMode_Task need to be implemented in vcsim for this test to work
|
||||
# https://github.com/vmware/govmomi/tree/master/vcsim#supported-methods
|
||||
#
|
||||
#- name: remove host
|
||||
# vmware_host:
|
||||
# hostname: "{{ vcsim }}"
|
||||
# username: "{{ vcsim_instance.json.username }}"
|
||||
# password: "{{ vcsim_instance.json.password }}"
|
||||
# validate_certs: no
|
||||
# esxi_hostname: test_host_system_0001
|
||||
# datacenter_name: "{{ dc1 }}"
|
||||
# cluster_name: "{{ ccr1 }}"
|
||||
# state: absent
|
||||
# register: remove_host_result
|
||||
#
|
||||
#- name: get a list of host system from vcsim after removing host system
|
||||
# uri:
|
||||
# url: http://{{ vcsim }}:5000/govc_find?filter=H
|
||||
# register: host_list
|
||||
#
|
||||
#- name: ensure host system is absent
|
||||
# assert:
|
||||
# that:
|
||||
# - remove_host_result | changed
|
||||
# - "{% for host in host_list.json if ((host | basename) == 'test_host_system_0001') -%} False {%- else -%} True {%- endfor %}"
|
||||
|
||||
## Testcase: Remove Host again
|
||||
#
|
||||
# EnterMaintenanceMode_Task need to be implemented in vcsim for this test to work
|
||||
# https://github.com/vmware/govmomi/tree/master/vcsim#supported-methods
|
||||
#
|
||||
#- name: remove 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
|
||||
# datacenter_name: "{{ dc1 }}"
|
||||
# cluster_name: "{{ ccr1 }}"
|
||||
# state: absent
|
||||
# register: reremove_host_result
|
||||
#
|
||||
#- name: ensure precend task didn't changed anything
|
||||
# assert:
|
||||
# that:
|
||||
# - not (reremove_host_result|changed)
|
||||
|
|
Loading…
Reference in a new issue