@ -42,6 +42,7 @@ HAS_PYVMOMI = False
try :
try :
from pyVmomi import vim
from pyVmomi import vim
from pyVim . connect import SmartConnect , Disconnect
from pyVim . connect import SmartConnect , Disconnect
HAS_PYVMOMI = True
HAS_PYVMOMI = True
except ImportError :
except ImportError :
pass
pass
@ -54,15 +55,17 @@ except ImportError:
hasvcr = False
hasvcr = False
try :
try :
import vcr
import vcr
hasvcr = True
hasvcr = True
except ImportError :
except ImportError :
pass
pass
class VMwareMissingHostException ( Exception ) :
class VMwareMissingHostException ( Exception ) :
pass
pass
class VMWareInventory ( object ) :
class VMWareInventory ( object ) :
__name__ = ' VMWareInventory '
__name__ = ' VMWareInventory '
guest_props = False
guest_props = False
@ -76,14 +79,16 @@ class VMWareInventory(object):
cache_max_age = None
cache_max_age = None
cache_path_cache = None
cache_path_cache = None
cache_path_index = None
cache_path_index = None
cache_dir = None
server = None
server = None
port = None
port = None
username = None
username = None
password = None
password = None
validate_certs = True
host_filters = [ ]
host_filters = [ ]
groupby_patterns = [ ]
groupby_patterns = [ ]
if ( sys . version_info > ( 3 , 0 ) ) :
if sys . version_info > ( 3 , 0 ) :
safe_types = [ int , bool , str , float , None ]
safe_types = [ int , bool , str , float , None ]
else :
else :
safe_types = [ int , long , bool , str , float , None ]
safe_types = [ int , long , bool , str , float , None ]
@ -99,6 +104,11 @@ class VMWareInventory(object):
' parent ' ,
' parent ' ,
' childtype ' ]
' childtype ' ]
vimTableMaxDepth = {
" vim.HostSystem " : 2 ,
" vim.VirtualMachine " : 2 ,
}
# translation table for attributes to fetch for known vim types
# translation table for attributes to fetch for known vim types
if not HAS_PYVMOMI :
if not HAS_PYVMOMI :
vimTable = { }
vimTable = { }
@ -106,14 +116,15 @@ class VMWareInventory(object):
vimTable = {
vimTable = {
vim . Datastore : [ ' _moId ' , ' name ' ] ,
vim . Datastore : [ ' _moId ' , ' name ' ] ,
vim . ResourcePool : [ ' _moId ' , ' name ' ] ,
vim . ResourcePool : [ ' _moId ' , ' name ' ] ,
vim . HostSystem : [ ' _moId ' , ' name ' ] ,
}
}
def _empty_inventory ( self ) :
@staticmethod
return { " _meta " : { " hostvars " : { } } }
def _empty_inventory ( ) :
return { " _meta " : { " hostvars " : { } } }
def __init__ ( self , load = True ) :
def __init__ ( self , load = True ) :
self . inventory = self . _empty_inventory ( )
self . inventory = VMWareInventory . _empty_inventory ( )
if load :
if load :
# Read settings and parse CLI arguments
# Read settings and parse CLI arguments
@ -135,7 +146,7 @@ class VMWareInventory(object):
try :
try :
text = str ( text )
text = str ( text )
except UnicodeEncodeError :
except UnicodeEncodeError :
text = text . encode ( ' ascii ' , ' ignore ' )
text = text . encode ( ' ascii ' , ' ignore ' )
print ( ' %s %s ' % ( datetime . datetime . now ( ) , text ) )
print ( ' %s %s ' % ( datetime . datetime . now ( ) , text ) )
def show ( self ) :
def show ( self ) :
@ -149,7 +160,6 @@ class VMWareInventory(object):
data_to_print = self . inventory
data_to_print = self . inventory
return json . dumps ( data_to_print , indent = 2 )
return json . dumps ( data_to_print , indent = 2 )
def is_cache_valid ( self ) :
def is_cache_valid ( self ) :
''' Determines if the cache files have expired, or if it is still valid '''
''' Determines if the cache files have expired, or if it is still valid '''
@ -164,7 +174,6 @@ class VMWareInventory(object):
return valid
return valid
def do_api_calls_update_cache ( self ) :
def do_api_calls_update_cache ( self ) :
''' Get instances and cache the data '''
''' Get instances and cache the data '''
@ -174,7 +183,6 @@ class VMWareInventory(object):
self . inventory = self . instances_to_inventory ( instances )
self . inventory = self . instances_to_inventory ( instances )
self . write_to_cache ( self . inventory , self . cache_path_cache )
self . write_to_cache ( self . inventory , self . cache_path_cache )
def write_to_cache ( self , data , cache_path ) :
def write_to_cache ( self , data , cache_path ) :
''' Dump inventory to json file '''
''' Dump inventory to json file '''
@ -182,7 +190,6 @@ class VMWareInventory(object):
with open ( self . cache_path_cache , ' wb ' ) as f :
with open ( self . cache_path_cache , ' wb ' ) as f :
f . write ( json . dumps ( data ) )
f . write ( json . dumps ( data ) )
def get_inventory_from_cache ( self ) :
def get_inventory_from_cache ( self ) :
''' Read in jsonified inventory '''
''' Read in jsonified inventory '''
@ -192,7 +199,6 @@ class VMWareInventory(object):
jdata = f . read ( )
jdata = f . read ( )
return json . loads ( jdata )
return json . loads ( jdata )
def read_settings ( self ) :
def read_settings ( self ) :
''' Reads the settings from the vmware_inventory.ini file '''
''' Reads the settings from the vmware_inventory.ini file '''
@ -216,7 +222,7 @@ class VMWareInventory(object):
' host_pattern ' : ' {{ guest.ipaddress }} ' ,
' host_pattern ' : ' {{ guest.ipaddress }} ' ,
' host_filters ' : ' {{ guest.gueststate == " running " }} ' ,
' host_filters ' : ' {{ guest.gueststate == " running " }} ' ,
' groupby_patterns ' : ' {{ guest.guestid }}, {{ " templates " if config.template else " guests " }} ' ,
' groupby_patterns ' : ' {{ guest.guestid }}, {{ " templates " if config.template else " guests " }} ' ,
' lower_var_keys ' : True }
' lower_var_keys ' : True }
}
}
if six . PY3 :
if six . PY3 :
@ -230,7 +236,7 @@ class VMWareInventory(object):
config . read ( vmware_ini_path )
config . read ( vmware_ini_path )
# apply defaults
# apply defaults
for k , v in defaults [ ' vmware ' ] . items ( ) :
for k , v in defaults [ ' vmware ' ] . items ( ) :
if not config . has_option ( ' vmware ' , k ) :
if not config . has_option ( ' vmware ' , k ) :
config . set ( ' vmware ' , k , str ( v ) )
config . set ( ' vmware ' , k , str ( v ) )
@ -255,8 +261,7 @@ class VMWareInventory(object):
self . validate_certs = os . environ . get ( ' VMWARE_VALIDATE_CERTS ' , config . get ( ' vmware ' , ' validate_certs ' ) )
self . validate_certs = os . environ . get ( ' VMWARE_VALIDATE_CERTS ' , config . get ( ' vmware ' , ' validate_certs ' ) )
if self . validate_certs in [ ' no ' , ' false ' , ' False ' , False ] :
if self . validate_certs in [ ' no ' , ' false ' , ' False ' , False ] :
self . validate_certs = False
self . validate_certs = False
else :
self . validate_certs = True
self . debugl ( ' cert validation is %s ' % self . validate_certs )
self . debugl ( ' cert validation is %s ' % self . validate_certs )
# behavior control
# behavior control
@ -286,7 +291,6 @@ class VMWareInventory(object):
# save the config
# save the config
self . config = config
self . config = config
def parse_cli_args ( self ) :
def parse_cli_args ( self ) :
''' Command line argument processing '''
''' Command line argument processing '''
@ -304,17 +308,13 @@ class VMWareInventory(object):
help = ' maximum number of instances to retrieve ' )
help = ' maximum number of instances to retrieve ' )
self . args = parser . parse_args ( )
self . args = parser . parse_args ( )
def get_instances ( self ) :
def get_instances ( self ) :
''' Get a list of vm instances with pyvmomi '''
''' Get a list of vm instances with pyvmomi '''
instances = [ ]
kwargs = { ' host ' : self . server ,
kwargs = { ' host ' : self . server ,
' user ' : self . username ,
' user ' : self . username ,
' pwd ' : self . password ,
' pwd ' : self . password ,
' port ' : int ( self . port ) }
' port ' : int ( self . port ) }
if hasattr ( ssl , ' SSLContext ' ) and not self . validate_certs :
if hasattr ( ssl , ' SSLContext ' ) and not self . validate_certs :
context = ssl . SSLContext ( ssl . PROTOCOL_SSLv23 )
context = ssl . SSLContext ( ssl . PROTOCOL_SSLv23 )
@ -324,7 +324,6 @@ class VMWareInventory(object):
instances = self . _get_instances ( kwargs )
instances = self . _get_instances ( kwargs )
return instances
return instances
def _get_instances ( self , inkwargs ) :
def _get_instances ( self , inkwargs ) :
''' Make API calls '''
''' Make API calls '''
@ -350,7 +349,7 @@ class VMWareInventory(object):
for child in children :
for child in children :
# If requested, limit the total number of instances
# If requested, limit the total number of instances
if self . args . max_instances :
if self . args . max_instances :
if len ( instances ) > = ( self . args . max_instances ) :
if len ( instances ) > = self . args . max_instances :
break
break
instances . append ( child )
instances . append ( child )
self . debugl ( " %s total instances in container view " % len ( instances ) )
self . debugl ( " %s total instances in container view " % len ( instances ) )
@ -360,7 +359,7 @@ class VMWareInventory(object):
instance_tuples = [ ]
instance_tuples = [ ]
for instance in sorted ( instances ) :
for instance in sorted ( instances ) :
if self . guest_props != False :
if self . guest_props :
ifacts = self . facts_from_proplist ( instance )
ifacts = self . facts_from_proplist ( instance )
else :
else :
ifacts = self . facts_from_vobj ( instance )
ifacts = self . facts_from_vobj ( instance )
@ -368,19 +367,15 @@ class VMWareInventory(object):
self . debugl ( ' facts collected for all instances ' )
self . debugl ( ' facts collected for all instances ' )
return instance_tuples
return instance_tuples
def instances_to_inventory ( self , instances ) :
def instances_to_inventory ( self , instances ) :
''' Convert a list of vm objects into a json compliant inventory '''
''' Convert a list of vm objects into a json compliant inventory '''
self . debugl ( ' re-indexing instances based on ini settings ' )
self . debugl ( ' re-indexing instances based on ini settings ' )
inventory = self . _empty_inventory ( )
inventory = VMWareInventory . _empty_inventory ( )
inventory [ ' all ' ] = { }
inventory [ ' all ' ] = { }
inventory [ ' all ' ] [ ' hosts ' ] = [ ]
inventory [ ' all ' ] [ ' hosts ' ] = [ ]
last_idata = None
for idx , instance in enumerate ( instances ) :
total = len ( instances )
for idx , instance in enumerate ( instances ) :
# make a unique id for this object to avoid vmware's
# make a unique id for this object to avoid vmware's
# numerous uuid's which aren't all unique.
# numerous uuid's which aren't all unique.
thisid = str ( uuid . uuid4 ( ) )
thisid = str ( uuid . uuid4 ( ) )
@ -392,16 +387,19 @@ class VMWareInventory(object):
inventory [ ' _meta ' ] [ ' hostvars ' ] [ thisid ] [ ' ansible_uuid ' ] = thisid
inventory [ ' _meta ' ] [ ' hostvars ' ] [ thisid ] [ ' ansible_uuid ' ] = thisid
# Make a map of the uuid to the alias the user wants
# Make a map of the uuid to the alias the user wants
name_mapping = self . create_template_mapping ( inventory ,
name_mapping = self . create_template_mapping (
self . config . get ( ' vmware ' , ' alias_pattern ' ) )
inventory ,
self . config . get ( ' vmware ' , ' alias_pattern ' )
)
# Make a map of the uuid to the ssh hostname the user wants
# Make a map of the uuid to the ssh hostname the user wants
host_mapping = self . create_template_mapping ( inventory ,
host_mapping = self . create_template_mapping (
self . config . get ( ' vmware ' , ' host_pattern ' ) )
inventory ,
self . config . get ( ' vmware ' , ' host_pattern ' )
)
# Reset the inventory keys
# Reset the inventory keys
for k , v in name_mapping . items ( ) :
for k , v in name_mapping . items ( ) :
if not host_mapping or not k in host_mapping :
if not host_mapping or not k in host_mapping :
continue
continue
@ -411,7 +409,7 @@ class VMWareInventory(object):
inventory [ ' _meta ' ] [ ' hostvars ' ] [ k ] [ ' ansible_host ' ] = host_mapping [ k ]
inventory [ ' _meta ' ] [ ' hostvars ' ] [ k ] [ ' ansible_host ' ] = host_mapping [ k ]
# 1.9.x backwards compliance
# 1.9.x backwards compliance
inventory [ ' _meta ' ] [ ' hostvars ' ] [ k ] [ ' ansible_ssh_host ' ] = host_mapping [ k ]
inventory [ ' _meta ' ] [ ' hostvars ' ] [ k ] [ ' ansible_ssh_host ' ] = host_mapping [ k ]
except Exception as e :
except Exception :
continue
continue
if k == v :
if k == v :
@ -434,7 +432,7 @@ class VMWareInventory(object):
continue
continue
self . debugl ( ' filter: %s ' % hf )
self . debugl ( ' filter: %s ' % hf )
filter_map = self . create_template_mapping ( inventory , hf , dtype = ' boolean ' )
filter_map = self . create_template_mapping ( inventory , hf , dtype = ' boolean ' )
for k , v in filter_map . items ( ) :
for k , v in filter_map . items ( ) :
if not v :
if not v :
# delete this host
# delete this host
inventory [ ' all ' ] [ ' hosts ' ] . remove ( k )
inventory [ ' all ' ] [ ' hosts ' ] . remove ( k )
@ -447,7 +445,7 @@ class VMWareInventory(object):
# Create groups
# Create groups
for gbp in self . groupby_patterns :
for gbp in self . groupby_patterns :
groupby_map = self . create_template_mapping ( inventory , gbp )
groupby_map = self . create_template_mapping ( inventory , gbp )
for k , v in groupby_map . items ( ) :
for k , v in groupby_map . items ( ) :
if v not in inventory :
if v not in inventory :
inventory [ v ] = { }
inventory [ v ] = { }
inventory [ v ] [ ' hosts ' ] = [ ]
inventory [ v ] [ ' hosts ' ] = [ ]
@ -456,13 +454,12 @@ class VMWareInventory(object):
return inventory
return inventory
def create_template_mapping ( self , inventory , pattern , dtype = ' string ' ) :
def create_template_mapping ( self , inventory , pattern , dtype = ' string ' ) :
''' Return a hash of uuid to templated string from pattern '''
''' Return a hash of uuid to templated string from pattern '''
mapping = { }
mapping = { }
for k , v in inventory [ ' _meta ' ] [ ' hostvars ' ] . items ( ) :
for k , v in inventory [ ' _meta ' ] [ ' hostvars ' ] . items ( ) :
t = jinja2 . Template ( pattern )
t = jinja2 . Template ( pattern )
newkey = None
newkey = None
try :
try :
@ -494,7 +491,7 @@ class VMWareInventory(object):
if self . lowerkeys :
if self . lowerkeys :
key = key . lower ( )
key = key . lower ( )
if not ' . ' in prop :
if ' . ' not in prop :
# props without periods are direct attributes of the parent
# props without periods are direct attributes of the parent
rdata [ key ] = getattr ( vm , prop )
rdata [ key ] = getattr ( vm , prop )
else :
else :
@ -507,7 +504,7 @@ class VMWareInventory(object):
# pointer to the current result key
# pointer to the current result key
lastref = rdata
lastref = rdata
for idx , x in enumerate ( parts ) :
for idx , x in enumerate ( parts ) :
# if the val wasn't set yet, get it from the parent
# if the val wasn't set yet, get it from the parent
if not val :
if not val :
@ -533,7 +530,6 @@ class VMWareInventory(object):
return rdata
return rdata
def facts_from_vobj ( self , vobj , level = 0 ) :
def facts_from_vobj ( self , vobj , level = 0 ) :
''' Traverse a VM object and return a json compliant data structure '''
''' Traverse a VM object and return a json compliant data structure '''
@ -556,7 +552,7 @@ class VMWareInventory(object):
methods = dir ( vobj )
methods = dir ( vobj )
methods = [ str ( x ) for x in methods if not x . startswith ( ' _ ' ) ]
methods = [ str ( x ) for x in methods if not x . startswith ( ' _ ' ) ]
methods = [ x for x in methods if not x in self . bad_types ]
methods = [ x for x in methods if x not in self . bad_types ]
methods = [ x for x in methods if not x . lower ( ) in self . skip_keys ]
methods = [ x for x in methods if not x . lower ( ) in self . skip_keys ]
methods = sorted ( methods )
methods = sorted ( methods )
@ -577,19 +573,20 @@ class VMWareInventory(object):
rdata [ method ] = self . _process_object_types (
rdata [ method ] = self . _process_object_types (
methodToCall ,
methodToCall ,
thisvm = vobj ,
thisvm = vobj ,
inkey = method
inkey = method ,
)
)
return rdata
return rdata
def _process_object_types ( self , vobj , thisvm = None , inkey = None , level = 0 ) :
def _process_object_types ( self , vobj , thisvm = None , inkey = None , level = 0 ) :
''' Serialize an object '''
''' Serialize an object '''
rdata = { }
rdata = { }
if type ( vobj ) . __name__ in self . vimTableMaxDepth and level > = self . vimTableMaxDepth [ type ( vobj ) . __name__ ] :
return rdata
if vobj is None :
if vobj is None :
rdata = None
rdata = None
elif type ( vobj ) in self . vimTable :
elif type ( vobj ) in self . vimTable :
rdata = { }
rdata = { }
for key in self . vimTable [ type ( vobj ) ] :
for key in self . vimTable [ type ( vobj ) ] :
@ -612,18 +609,16 @@ class VMWareInventory(object):
rdata = [ ]
rdata = [ ]
try :
try :
vobj = sorted ( vobj )
vobj = sorted ( vobj )
except Exception as e :
except Exception :
pass
pass
for idv , vii in enumerate ( vobj ) :
for idv , vii in enumerate ( vobj ) :
if level + 1 < = self . maxlevel :
if ( level + 1 < = self . maxlevel ) :
vid = self . _process_object_types (
vid = self . _process_object_types (
vii ,
vii ,
thisvm = thisvm ,
thisvm = thisvm ,
inkey = inkey + ' [ ' + str ( idv ) + ' ] ' ,
inkey = inkey + ' [ ' + str ( idv ) + ' ] ' ,
level = ( level + 1 )
level = ( level + 1 )
)
)
if vid :
if vid :
@ -635,7 +630,7 @@ class VMWareInventory(object):
elif issubclass ( type ( vobj ) , object ) :
elif issubclass ( type ( vobj ) , object ) :
methods = dir ( vobj )
methods = dir ( vobj )
methods = [ str ( x ) for x in methods if not x . startswith ( ' _ ' ) ]
methods = [ str ( x ) for x in methods if not x . startswith ( ' _ ' ) ]
methods = [ x for x in methods if not x in self . bad_types ]
methods = [ x for x in methods if x not in self . bad_types ]
methods = [ x for x in methods if not x . lower ( ) in self . skip_keys ]
methods = [ x for x in methods if not x . lower ( ) in self . skip_keys ]
methods = sorted ( methods )
methods = sorted ( methods )
@ -645,16 +640,18 @@ class VMWareInventory(object):
methodToCall = getattr ( vobj , method )
methodToCall = getattr ( vobj , method )
except Exception as e :
except Exception as e :
continue
continue
if callable ( methodToCall ) :
if callable ( methodToCall ) :
continue
continue
if self . lowerkeys :
if self . lowerkeys :
method = method . lower ( )
method = method . lower ( )
if ( level + 1 < = self . maxlevel ) :
if level + 1 < = self . maxlevel :
rdata [ method ] = self . _process_object_types (
rdata [ method ] = self . _process_object_types (
methodToCall ,
methodToCall ,
thisvm = thisvm ,
thisvm = thisvm ,
inkey = inkey + ' . ' + method ,
inkey = inkey + ' . ' + method ,
level = ( level + 1 )
level = ( level + 1 )
)
)
else :
else :
pass
pass
@ -668,10 +665,8 @@ class VMWareInventory(object):
if host in self . inventory [ ' _meta ' ] [ ' hostvars ' ] :
if host in self . inventory [ ' _meta ' ] [ ' hostvars ' ] :
return self . inventory [ ' _meta ' ] [ ' hostvars ' ] [ host ]
return self . inventory [ ' _meta ' ] [ ' hostvars ' ] [ host ]
elif self . args . host and self . inventory [ ' _meta ' ] [ ' hostvars ' ] :
elif self . args . host and self . inventory [ ' _meta ' ] [ ' hostvars ' ] :
# check if the machine has the name requested
keys = self . inventory [ ' _meta ' ] [ ' hostvars ' ] . keys ( )
match = None
match = None
for k , v in self . inventory [ ' _meta ' ] [ ' hostvars ' ] . items ( ) :
for k , v in self . inventory [ ' _meta ' ] [ ' hostvars ' ] :
if self . inventory [ ' _meta ' ] [ ' hostvars ' ] [ k ] [ ' name ' ] == self . args . host :
if self . inventory [ ' _meta ' ] [ ' hostvars ' ] [ k ] [ ' name ' ] == self . args . host :
match = k
match = k
break
break