VMware: Allow user to add host without cluster (#39490)
This fix allows user to add ESXi host system under folder without requiring to specify cluster name. partially fixes: #38300 Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
This commit is contained in:
parent
2214c747a2
commit
108eac9339
1 changed files with 112 additions and 35 deletions
|
@ -26,7 +26,7 @@ author:
|
|||
- Russell Teague (@mtnbikenc)
|
||||
- Maxime de Roucy (@tchernomax)
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
- Tested on vSphere 5.5, 6.0 and 6.5
|
||||
requirements:
|
||||
- python >= 2.6
|
||||
- PyVmomi
|
||||
|
@ -34,12 +34,34 @@ options:
|
|||
datacenter_name:
|
||||
description:
|
||||
- Name of the datacenter to add the host.
|
||||
- Aliases added in version 2.6.
|
||||
required: yes
|
||||
aliases: ['datacenter']
|
||||
cluster_name:
|
||||
description:
|
||||
- Name of the cluster to add the host.
|
||||
- Required parameter from version 2.5.
|
||||
required: yes
|
||||
- If C(folder) is not set, then this parameter is required.
|
||||
- Aliases added in version 2.6.
|
||||
aliases: ['cluster']
|
||||
folder:
|
||||
description:
|
||||
- Name of the folder under which host to add.
|
||||
- If C(cluster_name) is not set, then this parameter is required.
|
||||
- "For example, if there is a datacenter 'dc1' under folder called 'Site1' then, this value will be '/Site1/dc1/host'."
|
||||
- "Here 'host' is an invisible folder under VMware Web Client."
|
||||
- "Another example, if there is a nested folder structure like '/myhosts/india/pune' under
|
||||
datacenter 'dc2', then C(folder) value will be '/dc2/host/myhosts/india/pune'."
|
||||
- "Other Examples: "
|
||||
- " - '/Site2/dc2/Asia-Cluster/host'"
|
||||
- " - '/dc3/Asia-Cluster/host'"
|
||||
version_added: "2.6"
|
||||
add_connected:
|
||||
description:
|
||||
- If set to C(True), then the host should be connected as soon as it is added.
|
||||
- This parameter is ignored if state is set to a value other than C(present).
|
||||
default: True
|
||||
type: 'bool'
|
||||
version_added: "2.6"
|
||||
esxi_hostname:
|
||||
description:
|
||||
- ESXi hostname to manage.
|
||||
|
@ -50,30 +72,28 @@ options:
|
|||
- Required for adding a host.
|
||||
- Optional for reconnect.
|
||||
- Unused for removing.
|
||||
- No longer required parameter from version 2.5.
|
||||
- No longer a required parameter from version 2.5.
|
||||
esxi_password:
|
||||
description:
|
||||
- ESXi password.
|
||||
- Required for adding a host.
|
||||
- Optional for reconnect.
|
||||
- Unused for removing.
|
||||
- No longer required parameter from version 2.5.
|
||||
- No longer a required parameter from version 2.5.
|
||||
state:
|
||||
description:
|
||||
- "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."
|
||||
- If set to C(present), then add the host if host is absent.
|
||||
- If set to C(present), then do nothing if host already exists.
|
||||
- If set to C(absent), then remove the host if host is present.
|
||||
- If set to C(absent), then do nothing if host already does not exists.
|
||||
- If set to C(add_or_reconnect), then add the host if it's absent else reconnect it.
|
||||
- If set to C(reconnect), then reconnect the host if it's present else fail.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
- add_or_reconnect
|
||||
- reconnect
|
||||
choices: ['present', 'absent', 'add_or_reconnect', 'reconnect']
|
||||
esxi_ssl_thumbprint:
|
||||
description:
|
||||
- "Specifying the hostsystem's certificate's thumbprint."
|
||||
- "Use following command to get hostsystem's certificate's thumbprint - "
|
||||
- "Specifying the hostsystem certificate's thumbprint."
|
||||
- "Use following command to get hostsystem certificate's thumbprint - "
|
||||
- "# openssl x509 -in /etc/vmware/ssl/rui.crt -fingerprint -sha1 -noout"
|
||||
version_added: 2.5
|
||||
default: ''
|
||||
|
@ -93,6 +113,19 @@ EXAMPLES = r'''
|
|||
esxi_password: '{{ esxi_password }}'
|
||||
state: present
|
||||
|
||||
- name: Add ESXi Host to vCenter under a specific folder
|
||||
vmware_host:
|
||||
hostname: '{{ vcenter_hostname }}'
|
||||
username: '{{ vcenter_username }}'
|
||||
password: '{{ vcenter_password }}'
|
||||
datacenter_name: datacenter_name
|
||||
folder: '/Site2/Asia-Cluster/host'
|
||||
esxi_hostname: '{{ esxi_hostname }}'
|
||||
esxi_username: '{{ esxi_username }}'
|
||||
esxi_password: '{{ esxi_password }}'
|
||||
state: present
|
||||
add_connected: True
|
||||
|
||||
- name: Reconnect ESXi Host (with username/password set)
|
||||
vmware_host:
|
||||
hostname: '{{ vcenter_hostname }}'
|
||||
|
@ -127,10 +160,14 @@ EXAMPLES = r'''
|
|||
esxi_password: '{{ esxi_password }}'
|
||||
esxi_ssl_thumbprint: "3C:A5:60:6F:7A:B7:C4:6C:48:28:3D:2F:A5:EC:A3:58:13:88:F6:DD"
|
||||
state: present
|
||||
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
result:
|
||||
description: metadata about the new host system added
|
||||
returned: on successful addition
|
||||
type: str
|
||||
sample: "'vim.ComputeResource:domain-s222'"
|
||||
'''
|
||||
|
||||
try:
|
||||
|
@ -149,13 +186,13 @@ class VMwareHost(PyVmomi):
|
|||
super(VMwareHost, self).__init__(module)
|
||||
self.datacenter_name = module.params['datacenter_name']
|
||||
self.cluster_name = module.params['cluster_name']
|
||||
self.folder_name = module.params['folder']
|
||||
self.esxi_hostname = module.params['esxi_hostname']
|
||||
self.esxi_username = module.params['esxi_username']
|
||||
self.esxi_password = module.params['esxi_password']
|
||||
self.state = module.params['state']
|
||||
self.esxi_ssl_thumbprint = module.params.get('esxi_ssl_thumbprint', '')
|
||||
self.cluster = None
|
||||
self.host = None
|
||||
self.cluster = self.folder = self.host = None
|
||||
|
||||
def process_state(self):
|
||||
# Currently state_update_host is not implemented.
|
||||
|
@ -186,20 +223,33 @@ class VMwareHost(PyVmomi):
|
|||
except Exception as e:
|
||||
self.module.fail_json(msg=to_native(e))
|
||||
|
||||
def add_host_to_vcenter(self):
|
||||
def get_host_connect_spec(self):
|
||||
"""
|
||||
Function to return Host connection specification
|
||||
Returns: host connection specification
|
||||
|
||||
"""
|
||||
host_connect_spec = vim.host.ConnectSpec()
|
||||
host_connect_spec.hostName = self.esxi_hostname
|
||||
host_connect_spec.userName = self.esxi_username
|
||||
host_connect_spec.password = self.esxi_password
|
||||
host_connect_spec.force = True
|
||||
host_connect_spec.sslThumbprint = self.esxi_ssl_thumbprint
|
||||
as_connected = True
|
||||
return host_connect_spec
|
||||
|
||||
def add_host_to_vcenter(self):
|
||||
host_connect_spec = self.get_host_connect_spec()
|
||||
as_connected = self.params.get('add_connected')
|
||||
esxi_license = None
|
||||
resource_pool = None
|
||||
|
||||
for count in range(0, 2):
|
||||
try:
|
||||
task = self.cluster.AddHost_Task(host_connect_spec, as_connected, resource_pool, esxi_license)
|
||||
task = None
|
||||
if self.folder:
|
||||
task = self.folder.AddStandaloneHost(spec=host_connect_spec, addConnected=as_connected)
|
||||
elif self.cluster:
|
||||
task = self.cluster.AddHost_Task(host_connect_spec, as_connected, resource_pool, esxi_license)
|
||||
success, result = wait_for_task(task)
|
||||
return success, result
|
||||
except TaskError as task_error_exception:
|
||||
|
@ -211,6 +261,14 @@ class VMwareHost(PyVmomi):
|
|||
else:
|
||||
self.module.fail_json(msg="Failed to add host %s to vCenter: %s" % (self.esxi_hostname,
|
||||
to_native(task_error.msg)))
|
||||
except vmodl.fault.NotSupported:
|
||||
self.module.fail_json(msg="Failed to add host %s to vCenter as host is"
|
||||
" being added to a folder %s whose childType"
|
||||
" property does not contain"
|
||||
" \"ComputeResource\"." % (self.esxi_hostname, self.folder_name))
|
||||
except Exception as generic_exc:
|
||||
self.module.fail_json(msg="Failed to add host %s to vCenter: %s" % (self.esxi_hostname,
|
||||
to_native(generic_exc)))
|
||||
|
||||
self.module.fail_json(msg="Failed to add host %s to vCenter" % self.esxi_hostname)
|
||||
|
||||
|
@ -220,12 +278,7 @@ class VMwareHost(PyVmomi):
|
|||
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 = self.esxi_ssl_thumbprint
|
||||
reconnecthost_args['cnxSpec'] = self.get_host_connect_spec()
|
||||
|
||||
for count in range(0, 2):
|
||||
try:
|
||||
|
@ -290,8 +343,24 @@ class VMwareHost(PyVmomi):
|
|||
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)
|
||||
if self.cluster_name:
|
||||
self.host, self.cluster = find_host_by_cluster_datacenter(self.module, self.content,
|
||||
self.datacenter_name, self.cluster_name,
|
||||
self.esxi_hostname)
|
||||
elif self.folder_name:
|
||||
si = self.content.searchIndex
|
||||
folder_obj = si.FindByInventoryPath(self.folder_name)
|
||||
if folder_obj and isinstance(folder_obj, vim.Folder):
|
||||
self.folder = folder_obj
|
||||
|
||||
if self.folder is None:
|
||||
self.module.fail_json(msg="Failed to get host system details from"
|
||||
" the given folder %s" % self.folder_name,
|
||||
details="This could either mean that the value of folder is"
|
||||
" invalid or the provided folder does not exists.")
|
||||
for child in self.folder.childEntity:
|
||||
if child and isinstance(child, vim.HostSystem) and child.name == self.esxi_hostname:
|
||||
self.host = child
|
||||
|
||||
if self.host is None:
|
||||
return 'absent'
|
||||
|
@ -302,15 +371,17 @@ class VMwareHost(PyVmomi):
|
|||
def main():
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(
|
||||
datacenter_name=dict(type='str', required=True),
|
||||
cluster_name=dict(type='str', required=True),
|
||||
datacenter_name=dict(type='str', required=True, aliases=['datacenter']),
|
||||
cluster_name=dict(type='str', aliases=['cluster']),
|
||||
esxi_hostname=dict(type='str', required=True),
|
||||
esxi_username=dict(type='str', required=False),
|
||||
esxi_password=dict(type='str', required=False, no_log=True),
|
||||
esxi_username=dict(type='str'),
|
||||
esxi_password=dict(type='str', no_log=True),
|
||||
esxi_ssl_thumbprint=dict(type='str', default=''),
|
||||
state=dict(default='present',
|
||||
choices=['present', 'absent', 'add_or_reconnect', 'reconnect'],
|
||||
type='str')
|
||||
type='str'),
|
||||
folder=dict(type='str'),
|
||||
add_connected=dict(type='bool', default=True),
|
||||
)
|
||||
|
||||
module = AnsibleModule(
|
||||
|
@ -319,6 +390,12 @@ def main():
|
|||
required_if=[
|
||||
['state', 'present', ['esxi_username', 'esxi_password']],
|
||||
['state', 'add_or_reconnect', ['esxi_username', 'esxi_password']]
|
||||
],
|
||||
required_one_of=[
|
||||
['cluster_name', 'folder'],
|
||||
],
|
||||
mutually_exclusive=[
|
||||
['cluster_name', 'folder'],
|
||||
]
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in a new issue