@ -108,6 +108,7 @@ class VMWareInventory(object):
if self . args . refresh_cache or not cache_valid :
if self . args . refresh_cache or not cache_valid :
self . do_api_calls_update_cache ( )
self . do_api_calls_update_cache ( )
else :
else :
self . debugl ( ' # loading inventory from cache ' )
self . inventory = self . get_inventory_from_cache ( )
self . inventory = self . get_inventory_from_cache ( )
def debugl ( self , text ) :
def debugl ( self , text ) :
@ -284,7 +285,6 @@ class VMWareInventory(object):
kwargs [ ' sslContext ' ] = context
kwargs [ ' sslContext ' ] = context
instances = self . _get_instances ( kwargs )
instances = self . _get_instances ( kwargs )
self . debugl ( " ### INSTANCES RETRIEVED " )
return instances
return instances
@ -294,18 +294,29 @@ class VMWareInventory(object):
instances = [ ]
instances = [ ]
si = SmartConnect ( * * inkwargs )
si = SmartConnect ( * * inkwargs )
self . debugl ( ' # retrieving instances ' )
if not si :
if not si :
print ( " Could not connect to the specified host using specified "
print ( " Could not connect to the specified host using specified "
" username and password " )
" username and password " )
return - 1
return - 1
atexit . register ( Disconnect , si )
atexit . register ( Disconnect , si )
content = si . RetrieveContent ( )
content = si . RetrieveContent ( )
for child in content . rootFolder . childEntity :
instances + = self . _get_instances_from_children ( child )
# Create a search container for virtualmachines
if self . args . max_instances :
container = content . rootFolder
if len ( instances ) > = ( self . args . max_instances + 1 ) :
viewType = [ vim . VirtualMachine ]
instances = instances [ 0 : ( self . args . max_instances + 1 ) ]
recursive = True
containerView = content . viewManager . CreateContainerView ( container , viewType , recursive )
children = containerView . view
for child in children :
# If requested, limit the total number of instances
if self . args . max_instances :
if len ( instances ) > = ( self . args . max_instances ) :
break
instances . append ( child )
self . debugl ( " # total instances retrieved %s " % len ( instances ) )
instance_tuples = [ ]
instance_tuples = [ ]
for instance in sorted ( instances ) :
for instance in sorted ( instances ) :
ifacts = self . facts_from_vobj ( instance )
ifacts = self . facts_from_vobj ( instance )
@ -313,38 +324,6 @@ class VMWareInventory(object):
return instance_tuples
return instance_tuples
def _get_instances_from_children ( self , child ) :
instances = [ ]
if hasattr ( child , ' childEntity ' ) :
self . debugl ( " CHILDREN: %s " % child . childEntity )
instances + = self . _get_instances_from_children ( child . childEntity )
elif hasattr ( child , ' vmFolder ' ) :
self . debugl ( " FOLDER: %s " % child )
instances + = self . _get_instances_from_children ( child . vmFolder )
elif hasattr ( child , ' index ' ) :
self . debugl ( " LIST: %s " % child )
for x in sorted ( child ) :
self . debugl ( " LIST_ITEM: %s " % x )
instances + = self . _get_instances_from_children ( x )
elif hasattr ( child , ' guest ' ) :
self . debugl ( " GUEST: %s " % child )
instances . append ( child )
elif hasattr ( child , ' vm ' ) :
# resource pools
self . debugl ( " RESOURCEPOOL: %s " % child . vm )
if child . vm :
instances + = self . _get_instances_from_children ( child . vm )
else :
self . debugl ( " ELSE ... " )
try :
self . debugl ( child . __dict__ )
except Exception as e :
pass
self . debugl ( child )
return instances
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 '''
@ -366,7 +345,7 @@ class VMWareInventory(object):
inventory [ ' _meta ' ] [ ' hostvars ' ] [ thisid ] = idata . copy ( )
inventory [ ' _meta ' ] [ ' hostvars ' ] [ thisid ] = idata . copy ( )
inventory [ ' _meta ' ] [ ' hostvars ' ] [ thisid ] [ ' ansible_uuid ' ] = thisid
inventory [ ' _meta ' ] [ ' hostvars ' ] [ thisid ] [ ' ansible_uuid ' ] = thisid
# Make a map of the uuid to the name 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 ( inventory ,
self . config . get ( ' vmware ' , ' alias_pattern ' ) )
self . config . get ( ' vmware ' , ' alias_pattern ' ) )
@ -374,13 +353,20 @@ class VMWareInventory(object):
host_mapping = self . create_template_mapping ( inventory ,
host_mapping = self . create_template_mapping ( inventory ,
self . config . get ( ' vmware ' , ' host_pattern ' ) )
self . config . get ( ' vmware ' , ' host_pattern ' ) )
# Reset the inventory keys
# Reset the inventory keys
for k , v in name_mapping . iteritems ( ) :
for k , v in name_mapping . iteritems ( ) :
if not host_mapping or not k in host_mapping :
continue
# set ansible_host (2.x)
# set ansible_host (2.x)
inventory [ ' _meta ' ] [ ' hostvars ' ] [ k ] [ ' ansible_host ' ] = host_mapping [ k ]
try :
# 1.9.x backwards compliance
inventory [ ' _meta ' ] [ ' hostvars ' ] [ k ] [ ' ansible_host ' ] = host_mapping [ k ]
inventory [ ' _meta ' ] [ ' hostvars ' ] [ k ] [ ' ansible_ssh_host ' ] = host_mapping [ k ]
# 1.9.x backwards compliance
inventory [ ' _meta ' ] [ ' hostvars ' ] [ k ] [ ' ansible_ssh_host ' ] = host_mapping [ k ]
except Exception as e :
continue
if k == v :
if k == v :
continue
continue
@ -393,14 +379,14 @@ class VMWareInventory(object):
inventory [ ' all ' ] [ ' hosts ' ] . remove ( k )
inventory [ ' all ' ] [ ' hosts ' ] . remove ( k )
inventory [ ' _meta ' ] [ ' hostvars ' ] . pop ( k , None )
inventory [ ' _meta ' ] [ ' hostvars ' ] . pop ( k , None )
self . debugl ( ' PREFILTER_HOSTS :' )
self . debugl ( ' # pre-filtered hosts :' )
for i in inventory [ ' all ' ] [ ' hosts ' ] :
for i in inventory [ ' all ' ] [ ' hosts ' ] :
self . debugl ( i )
self . debugl ( ' # * %s ' % i )
# Apply host filters
# Apply host filters
for hf in self . host_filters :
for hf in self . host_filters :
if not hf :
if not hf :
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 . iteritems ( ) :
for k , v in filter_map . iteritems ( ) :
if not v :
if not v :
@ -408,9 +394,9 @@ class VMWareInventory(object):
inventory [ ' all ' ] [ ' hosts ' ] . remove ( k )
inventory [ ' all ' ] [ ' hosts ' ] . remove ( k )
inventory [ ' _meta ' ] [ ' hostvars ' ] . pop ( k , None )
inventory [ ' _meta ' ] [ ' hostvars ' ] . pop ( k , None )
self . debugl ( ' POSTFILTER_HOSTS :' )
self . debugl ( ' # post-filter hosts :' )
for i in inventory [ ' all ' ] [ ' hosts ' ] :
for i in inventory [ ' all ' ] [ ' hosts ' ] :
self . debugl ( i )
self . debugl ( ' # * %s ' % i )
# Create groups
# Create groups
for gbp in self . groupby_patterns :
for gbp in self . groupby_patterns :
@ -438,7 +424,6 @@ class VMWareInventory(object):
newkey = newkey . strip ( )
newkey = newkey . strip ( )
except Exception as e :
except Exception as e :
self . debugl ( e )
self . debugl ( e )
#import epdb; epdb.st()
if not newkey :
if not newkey :
continue
continue
elif dtype == ' integer ' :
elif dtype == ' integer ' :
@ -461,100 +446,90 @@ class VMWareInventory(object):
# pyvmomi objects are not yet serializable, but may be one day ...
# pyvmomi objects are not yet serializable, but may be one day ...
# https://github.com/vmware/pyvmomi/issues/21
# https://github.com/vmware/pyvmomi/issues/21
rdata = { }
# WARNING:
# Accessing an object attribute will trigger a SOAP call to the remote.
# Do not serialize self
# Increasing the attributes collected or the depth of recursion greatly
if hasattr ( vobj , ' __name__ ' ) :
# increases runtime duration and potentially memory+network utilization.
if vobj . __name__ == ' VMWareInventory ' :
return rdata
# Exit early if maxlevel is reached
if level == 0 :
if level > self . maxlevel :
try :
return rdata
self . debugl ( " # get facts: %s " % vobj . name )
except Exception as e :
self . debugl ( e )
# Objects usually have a dict property
rdata = { }
if hasattr ( vobj , ' __dict__ ' ) and not level == 0 :
keys = sorted ( vobj . __dict__ . keys ( ) )
methods = dir ( vobj )
for k in keys :
methods = [ str ( x ) for x in methods if not x . startswith ( ' _ ' ) ]
v = vobj . __dict__ [ k ]
methods = [ x for x in methods if not x in self . bad_types ]
# Skip private methods
methods = sorted ( methods )
if k . startswith ( ' _ ' ) :
continue
if k . lower ( ) in self . skip_keys :
for method in methods :
continue
# Attempt to get the method, skip on fail
try :
methodToCall = getattr ( vobj , method )
except Exception as e :
continue
# Skip callable methods
if callable ( methodToCall ) :
continue
if self . lowerkeys :
method = method . lower ( )
rdata [ method ] = self . _process_object_types ( methodToCall )
if self . lowerkeys :
return rdata
k = k . lower ( )
rdata [ k ] = self . _process_object_types ( v , level = level )
else :
def _process_object_types ( self , vobj , level = 0 ) :
''' Serialize an object '''
rdata = { }
if vobj is None :
rdata = None
elif issubclass ( type ( vobj ) , str ) or isinstance ( vobj , str ) :
rdata = vobj
elif issubclass ( type ( vobj ) , bool ) or isinstance ( vobj , bool ) :
rdata = vobj
elif issubclass ( type ( vobj ) , int ) or isinstance ( vobj , int ) :
rdata = vobj
elif issubclass ( type ( vobj ) , float ) or isinstance ( vobj , float ) :
rdata = vobj
elif issubclass ( type ( vobj ) , long ) or isinstance ( vobj , long ) :
rdata = vobj
elif issubclass ( type ( vobj ) , list ) or issubclass ( type ( vobj ) , tuple ) :
rdata = [ ]
try :
vobj = sorted ( vobj )
except Exception as e :
pass
for vi in vobj :
if ( level + 1 < = self . maxlevel ) :
#vid = self.facts_from_vobj(vi, level=(level+1))
vid = self . _process_object_types ( vi , level = ( level + 1 ) )
if vid :
rdata . append ( vid )
elif issubclass ( type ( vobj ) , dict ) :
pass
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 not x in self . bad_types ]
methods = sorted ( methods )
methods = sorted ( methods )
for method in methods :
for method in methods :
if method in rdata :
continue
# Attempt to get the method, skip on fail
# Attempt to get the method, skip on fail
try :
try :
methodToCall = getattr ( vobj , method )
methodToCall = getattr ( vobj , method )
except Exception as e :
except Exception as e :
continue
continue
# Skip callable methods
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 ) :
rdata [ method ] = self . _process_object_types ( methodToCall , level = level )
rdata [ method ] = self . _process_object_types ( methodToCall , level = ( level + 1 ) )
return rdata
def _process_object_types ( self , vobj , level = 0 ) :
rdata = { }
self . debugl ( " PROCESSING: %s " % vobj )
if type ( vobj ) in self . safe_types :
try :
rdata = vobj
except Exception as e :
self . debugl ( e )
elif hasattr ( vobj , ' append ' ) :
rdata = [ ]
for vi in sorted ( vobj ) :
if type ( vi ) in self . safe_types :
rdata . append ( vi )
else :
if ( level + 1 < = self . maxlevel ) :
vid = self . facts_from_vobj ( vi , level = ( level + 1 ) )
if vid :
rdata . append ( vid )
elif hasattr ( vobj , ' __dict__ ' ) :
if ( level + 1 < = self . maxlevel ) :
md = None
md = self . facts_from_vobj ( vobj , level = ( level + 1 ) )
if md :
rdata = md
elif not vobj or type ( vobj ) in self . safe_types :
rdata = vobj
elif type ( vobj ) == datetime . datetime :
rdata = str ( vobj )
else :
else :
self . debugl ( " unknown datatype: %s " % type ( vobj ) )
pass
if not rdata :
if not rdata :
rdata = None
rdata = None