@ -1,23 +1,26 @@
#!/usr/bin/python
#!/usr/bin/python
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# (c) 2015, Joseph Callen <jcallen () csc.com>
# Copyright: (c) 2015, Joseph Callen <jcallen () csc.com>
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import , division , print_function
from __future__ import absolute_import , division , print_function
__metaclass__ = type
__metaclass__ = type
ANSIBLE_METADATA = { ' metadata_version ' : ' 1.1 ' ,
ANSIBLE_METADATA = {
' status ' : [ ' preview ' ] ,
' metadata_version ' : ' 1.1 ' ,
' supported_by ' : ' community ' }
' status ' : [ ' preview ' ] ,
' supported_by ' : ' community '
}
DOCUMENTATION = r '''
DOCUMENTATION = r '''
- - -
- - -
module : vmware_host
module : vmware_host
short_description : Add / remove ESXi host to / from vCenter
short_description : Add / Remove ESXi host to / from vCenter
description :
description :
- This module can be used to add / remove / reconnect 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 '
version_added : ' 2.0 '
author :
author :
- Joseph Callen ( @jcpowermac )
- Joseph Callen ( @jcpowermac )
@ -36,7 +39,7 @@ options:
cluster_name :
cluster_name :
description :
description :
- Name of the cluster to add the host .
- Name of the cluster to add the host .
- Required from version 2.5 .
- Required parameter from version 2.5 .
required : yes
required : yes
esxi_hostname :
esxi_hostname :
description :
description :
@ -48,14 +51,14 @@ options:
- Required for adding a host .
- Required for adding a host .
- Optional for reconnect .
- Optional for reconnect .
- Unused for removing .
- Unused for removing .
- No longer required from version 2.5 .
- No longer required parameter from version 2.5 .
esxi_password :
esxi_password :
description :
description :
- ESXi password .
- ESXi password .
- Required for adding a host .
- Required for adding a host .
- Optional for reconnect .
- Optional for reconnect .
- Unused for removing .
- Unused for removing .
- No longer required from version 2.5 .
- No longer required parameter from version 2.5 .
state :
state :
description :
description :
- " present: add the host if it ' s absent else do nothing. "
- " present: add the host if it ' s absent else do nothing. "
@ -68,6 +71,12 @@ options:
- absent
- absent
- add_or_reconnect
- add_or_reconnect
- reconnect
- reconnect
esxi_ssl_thumbprint :
description :
- " Specifying the hostsystem ' s certificate ' s thumbprint. "
- " Use following command to get hostsystem ' s certificate ' s thumbprint - "
- " # openssl x509 -in /etc/vmware/ssl/rui.crt -fingerprint -sha1 -noout "
version_added : 2.5
extends_documentation_fragment : vmware . documentation
extends_documentation_fragment : vmware . documentation
'''
'''
@ -83,7 +92,6 @@ EXAMPLES = r'''
esxi_username : ' {{ esxi_username }} '
esxi_username : ' {{ esxi_username }} '
esxi_password : ' {{ esxi_password }} '
esxi_password : ' {{ esxi_password }} '
state : present
state : present
delegate_to : localhost
- name : Reconnect ESXi Host ( with username / password set )
- name : Reconnect ESXi Host ( with username / password set )
vmware_host :
vmware_host :
@ -96,7 +104,6 @@ EXAMPLES = r'''
esxi_username : ' {{ esxi_username }} '
esxi_username : ' {{ esxi_username }} '
esxi_password : ' {{ esxi_password }} '
esxi_password : ' {{ esxi_password }} '
state : reconnect
state : reconnect
delegate_to : localhost
- name : Reconnect ESXi Host ( with default username / password )
- name : Reconnect ESXi Host ( with default username / password )
vmware_host :
vmware_host :
@ -107,7 +114,20 @@ EXAMPLES = r'''
cluster_name : cluster_name
cluster_name : cluster_name
esxi_hostname : ' {{ esxi_hostname }} '
esxi_hostname : ' {{ esxi_hostname }} '
state : reconnect
state : reconnect
delegate_to : localhost
- name : Add ESXi Host with SSL Thumbprint 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 }} '
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 '''
RETURN = r '''
@ -115,95 +135,84 @@ RETURN = r'''
try :
try :
from pyVmomi import vim , vmodl
from pyVmomi import vim , vmodl
HAS_PYVMOMI = True
except ImportError :
except ImportError :
HAS_PYVMOMI = False
pass
from ansible . module_utils . basic import AnsibleModule
from ansible . module_utils . basic import AnsibleModule
from ansible . module_utils . vmware import (
from ansible . module_utils . _text import to_native
TaskError ,
from ansible . module_utils . vmware import ( PyVmomi , TaskError , vmware_argument_spec ,
connect_to_api ,
wait_for_task , find_host_by_cluster_datacenter )
vmware_argument_spec ,
wait_for_task ,
find_host_by_cluster_datacenter ,
)
class VMwareHost ( object ) :
class VMwareHost ( PyVmomi ) :
def __init__ ( self , module ) :
def __init__ ( self , module ) :
self . module = module
super ( VMwareHost , self ) . __init__ ( module )
self . datacenter_name = module . params [ ' datacenter_name ' ]
self . datacenter_name = module . params [ ' datacenter_name ' ]
self . cluster_name = module . params [ ' cluster_name ' ]
self . cluster_name = module . params [ ' cluster_name ' ]
self . esxi_hostname = module . params [ ' esxi_hostname ' ]
self . esxi_hostname = module . params [ ' esxi_hostname ' ]
self . esxi_username = module . params [ ' esxi_username ' ]
self . esxi_username = module . params [ ' esxi_username ' ]
self . esxi_password = module . params [ ' esxi_password ' ]
self . esxi_password = module . params [ ' esxi_password ' ]
self . state = module . params [ ' state ' ]
self . state = module . params [ ' state ' ]
self . esxi_ssl_thumbprint = module . params . get ( ' esxi_ssl_thumbprint ' , ' ' )
self . cluster = None
self . cluster = None
self . host = None
self . host = None
self . content = connect_to_api ( module )
def process_state ( self ) :
def process_state ( self ) :
try :
# Currently state_update_host is not implemented.
# Currently state_update_dvs is not implemented.
host_states = {
host_states = {
' absent ' : {
' absent ' : {
' present ' : self . state_remove_host ,
' present ' : self . state_remove_host ,
' absent ' : self . state_exit_unchanged ,
' absent ' : self . state_exit_unchanged ,
} ,
} ,
' present ' : {
' present ' : {
' present ' : self . state_exit_unchanged ,
' present ' : self . state_exit_unchanged ,
' absent ' : self . state_add_host ,
' absent ' : self . state_add_host ,
} ,
} ,
' add_or_reconnect ' : {
' add_or_reconnect ' : {
' present ' : self . state_reconnect_host ,
' present ' : self . state_reconnect_host ,
' absent ' : self . state_add_host ,
' absent ' : self . state_add_host ,
} ,
} ,
' reconnect ' : {
' reconnect ' : {
' present ' : self . state_reconnect_host ,
' present ' : self . state_reconnect_host ,
}
}
}
}
try :
host_states [ self . state ] [ self . check_host_state ( ) ] ( )
host_states [ self . state ] [ self . check_host_state ( ) ] ( )
except vmodl . RuntimeFault as runtime_fault :
except vmodl . RuntimeFault as runtime_fault :
self . module . fail_json ( msg = runtime_fault. msg )
self . module . fail_json ( msg = to_native( runtime_fault. msg ) )
except vmodl . MethodFault as method_fault :
except vmodl . MethodFault as method_fault :
self . module . fail_json ( msg = method_fault. msg )
self . module . fail_json ( msg = to_native( method_fault. msg ) )
except Exception as e :
except Exception as e :
self . module . fail_json ( msg = str ( e ) )
self . module . fail_json ( msg = to_native ( e ) )
def add_host_to_vcenter ( self ) :
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 = vim . host . ConnectSpec ( )
host_connect_spec . hostName = self . esxi_hostname
host_connect_spec . hostName = self . esxi_hostname
host_connect_spec . userName = self . esxi_username
host_connect_spec . userName = self . esxi_username
host_connect_spec . password = self . esxi_password
host_connect_spec . password = self . esxi_password
host_connect_spec . force = True
host_connect_spec . force = True
host_connect_spec . sslThumbprint = " "
host_connect_spec . sslThumbprint = self . esxi_ssl_thumbprint
as_connected = True
as_connected = True
esxi_license = None
esxi_license = None
resource_pool = None
resource_pool = None
try :
for count in range ( 0 , 2 ) :
task = self . cluster . AddHost_Task ( host_connect_spec , as_connected , resource_pool , esxi_license )
try :
success , result = wait_for_task ( task )
task = self . cluster . AddHost_Task ( host_connect_spec , as_connected , resource_pool , esxi_license )
return success , result
success , result = wait_for_task ( task )
except TaskError as add_task_error :
return success , result
# This is almost certain to fail the first time.
except TaskError as task_error_exception :
# In order to get the sslThumbprint we first connect
task_error = task_error_exception . args [ 0 ]
# get the vim.fault.SSLVerifyFault then grab the sslThumbprint
if self . esxi_ssl_thumbprint == ' ' and isinstance ( task_error , vim . fault . SSLVerifyFault ) :
# from that object.
# User has not specified SSL Thumbprint for ESXi host,
#
# try to grab it using SSLVerifyFault exception
# args is a tuple, selecting the first tuple
host_connect_spec . sslThumbprint = task_error . thumbprint
ssl_verify_fault = add_task_error . args [ 0 ]
else :
host_connect_spec . sslThumbprint = ssl_verify_fault . thumbprint
self . module . fail_json ( msg = " Failed to add host %s to vCenter: %s " % ( self . esxi_hostname ,
to_native ( task_error . msg ) ) )
task = self . cluster . AddHost_Task ( host_connect_spec , as_connected , resource_pool , esxi_license )
success , result = wait_for_task ( task )
self . module . fail_json ( msg = " Failed to add host %s to vCenter " % self . esxi_hostname )
return success , result
def reconnect_host_to_vcenter ( self ) :
def reconnect_host_to_vcenter ( self ) :
reconnecthost_args = { }
reconnecthost_args = { }
@ -216,20 +225,32 @@ class VMwareHost(object):
reconnecthost_args [ ' cnxSpec ' ] . userName = self . esxi_username
reconnecthost_args [ ' cnxSpec ' ] . userName = self . esxi_username
reconnecthost_args [ ' cnxSpec ' ] . password = self . esxi_password
reconnecthost_args [ ' cnxSpec ' ] . password = self . esxi_password
reconnecthost_args [ ' cnxSpec ' ] . force = True
reconnecthost_args [ ' cnxSpec ' ] . force = True
reconnecthost_args [ ' cnxSpec ' ] . sslThumbprint = " "
reconnecthost_args [ ' cnxSpec ' ] . sslThumbprint = self . esxi_ssl_thumbprint
for count in range ( 0 , 2 ) :
try :
task = self . host . ReconnectHost_Task ( * * reconnecthost_args )
success , result = wait_for_task ( task )
return success , result
except TaskError as task_error_exception :
task_error = task_error_exception . args [ 0 ]
if self . esxi_ssl_thumbprint == ' ' and isinstance ( task_error , vim . fault . SSLVerifyFault ) :
# User has not specified SSL Thumbprint for ESXi host,
# try to grab it using SSLVerifyFault exception
reconnecthost_args [ ' cnxSpec ' ] . sslThumbprint = task_error . thumbprint
else :
self . module . fail_json ( msg = " Failed to reconnect host %s to vCenter: %s " % ( self . esxi_hostname ,
to_native ( task_error . msg ) ) )
self . module . fail_json ( msg = " Failed to reconnect host %s to vCenter " % self . esxi_hostname )
else :
try :
try :
task = self . host . ReconnectHost_Task ( * * reconnecthost_args )
task = self . host . ReconnectHost_Task ( * * reconnecthost_args )
success , result = wait_for_task ( task )
success , result = wait_for_task ( task )
return success , result
return success , result
except TaskError as add_task_error :
except TaskError as task_error_exception :
# See add_host_to_vcenter
task_error = task_error_exception . args [ 0 ]
ssl_verify_fault = add_task_error . args [ 0 ]
self . module . fail_json ( msg = " Failed to reconnect host %s to vCenter due to %s " % ( self . esxi_hostname ,
reconnecthost_args [ ' cnxSpec ' ] . sslThumbprint = ssl_verify_fault . thumbprint
to_native ( task_error . msg ) ) )
task = self . host . ReconnectHost_Task ( * * reconnecthost_args )
success , result = wait_for_task ( task )
return success , result
def state_exit_unchanged ( self ) :
def state_exit_unchanged ( self ) :
self . module . exit_json ( changed = False )
self . module . exit_json ( changed = False )
@ -286,19 +307,20 @@ def main():
esxi_hostname = dict ( type = ' str ' , required = True ) ,
esxi_hostname = dict ( type = ' str ' , required = True ) ,
esxi_username = dict ( type = ' str ' , required = False ) ,
esxi_username = dict ( type = ' str ' , required = False ) ,
esxi_password = dict ( type = ' str ' , required = False , no_log = True ) ,
esxi_password = dict ( type = ' str ' , required = False , no_log = True ) ,
esxi_ssl_thumbprint = dict ( type = ' str ' , default = ' ' ) ,
state = dict ( default = ' present ' ,
state = dict ( default = ' present ' ,
choices = [ ' present ' , ' absent ' , ' add_or_reconnect ' , ' reconnect ' ] ,
choices = [ ' present ' , ' absent ' , ' add_or_reconnect ' , ' reconnect ' ] ,
type = ' str ' ) )
type = ' str ' )
)
module = AnsibleModule (
module = AnsibleModule (
argument_spec = argument_spec ,
argument_spec = argument_spec ,
supports_check_mode = True ,
supports_check_mode = True ,
required_if = [
required_if = [
[ ' state ' , ' present ' , [ ' esxi_username ' , ' esxi_password ' ] ] ,
[ ' state ' , ' present ' , [ ' esxi_username ' , ' esxi_password ' ] ] ,
[ ' state ' , ' add_or_reconnect ' , [ ' 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 ' )
vmware_host = VMwareHost ( module )
vmware_host = VMwareHost ( module )
vmware_host . process_state ( )
vmware_host . process_state ( )