bump vmware inventory script

This commit is contained in:
Chris Meyers
2017-01-26 16:01:57 -05:00
parent 7488e09763
commit 608975ff2f

View File

@@ -42,6 +42,7 @@ HAS_PYVMOMI = False
try:
from pyVmomi import vim
from pyVim.connect import SmartConnect, Disconnect
HAS_PYVMOMI = True
except ImportError:
pass
@@ -54,15 +55,17 @@ except ImportError:
hasvcr = False
try:
import vcr
hasvcr = True
except ImportError:
pass
class VMwareMissingHostException(Exception):
pass
class VMWareInventory(object):
class VMWareInventory(object):
__name__ = 'VMWareInventory'
guest_props = False
@@ -76,28 +79,30 @@ class VMWareInventory(object):
cache_max_age = None
cache_path_cache = None
cache_path_index = None
cache_dir = None
server = None
port = None
username = None
password = None
validate_certs = True
host_filters = []
skip_keys = []
groupby_patterns = []
if (sys.version_info > (3, 0)):
if sys.version_info > (3, 0):
safe_types = [int, bool, str, float, None]
else:
safe_types = [int, long, bool, str, float, None]
iter_types = [dict, list]
bad_types = ['Array', 'disabledMethod', 'declaredAlarmState']
skip_keys = ['declaredalarmstate',
'disabledmethod',
'dynamicproperty',
'dynamictype',
'environmentbrowser',
'managedby',
'parent',
'childtype']
vimTableMaxDepth = {
"vim.HostSystem": 2,
"vim.VirtualMachine": 2,
}
custom_fields = {}
# translation table for attributes to fetch for known vim types
if not HAS_PYVMOMI:
@@ -106,14 +111,15 @@ class VMWareInventory(object):
vimTable = {
vim.Datastore: ['_moId', 'name'],
vim.ResourcePool: ['_moId', 'name'],
vim.HostSystem: ['_moId', 'name'],
}
def _empty_inventory(self):
@staticmethod
def _empty_inventory():
return {"_meta": {"hostvars": {}}}
def __init__(self, load=True):
self.inventory = self._empty_inventory()
self.inventory = VMWareInventory._empty_inventory()
if load:
# Read settings and parse CLI arguments
@@ -149,7 +155,6 @@ class VMWareInventory(object):
data_to_print = self.inventory
return json.dumps(data_to_print, indent=2)
def is_cache_valid(self):
''' Determines if the cache files have expired, or if it is still valid '''
@@ -164,25 +169,20 @@ class VMWareInventory(object):
return valid
def do_api_calls_update_cache(self):
''' Get instances and cache the data '''
instances = self.get_instances()
self.instances = instances
self.inventory = self.instances_to_inventory(instances)
self.write_to_cache(self.inventory, self.cache_path_cache)
self.inventory = self.instances_to_inventory(self.get_instances())
self.write_to_cache(self.inventory)
def write_to_cache(self, data, cache_path):
def write_to_cache(self, data):
''' Dump inventory to json file '''
with open(self.cache_path_cache, 'wb') as f:
f.write(json.dumps(data))
def get_inventory_from_cache(self):
''' Read in jsonified inventory '''
@@ -192,7 +192,6 @@ class VMWareInventory(object):
jdata = f.read()
return json.loads(jdata)
def read_settings(self):
''' Reads the settings from the vmware_inventory.ini file '''
@@ -212,11 +211,22 @@ class VMWareInventory(object):
'cache_path': '~/.ansible/tmp',
'cache_max_age': 3600,
'max_object_level': 1,
'skip_keys': 'declaredalarmstate,'
'disabledmethod,'
'dynamicproperty,'
'dynamictype,'
'environmentbrowser,'
'managedby,'
'parent,'
'childtype,'
'resourceconfig',
'alias_pattern': '{{ config.name + "_" + config.uuid }}',
'host_pattern': '{{ guest.ipaddress }}',
'host_filters': '{{ guest.gueststate == "running" }}',
'groupby_patterns': '{{ guest.guestid }},{{ "templates" if config.template else "guests"}}',
'lower_var_keys': True }
'lower_var_keys': True,
'custom_field_group_prefix': 'vmware_tag_',
'groupby_custom_field': False}
}
if six.PY3:
@@ -255,8 +265,7 @@ class VMWareInventory(object):
self.validate_certs = os.environ.get('VMWARE_VALIDATE_CERTS', config.get('vmware', 'validate_certs'))
if self.validate_certs in ['no', 'false', 'False', False]:
self.validate_certs = False
else:
self.validate_certs = True
self.debugl('cert validation is %s' % self.validate_certs)
# behavior control
@@ -269,7 +278,8 @@ class VMWareInventory(object):
else:
self.lowerkeys = False
self.debugl('lower keys is %s' % self.lowerkeys)
self.skip_keys = list(config.get('vmware', 'skip_keys').split(','))
self.debugl('skip keys is %s' % self.skip_keys)
self.host_filters = list(config.get('vmware', 'host_filters').split(','))
self.debugl('host filters are %s' % self.host_filters)
self.groupby_patterns = list(config.get('vmware', 'groupby_patterns').split(','))
@@ -286,7 +296,6 @@ class VMWareInventory(object):
# save the config
self.config = config
def parse_cli_args(self):
''' Command line argument processing '''
@@ -304,13 +313,9 @@ class VMWareInventory(object):
help='maximum number of instances to retrieve')
self.args = parser.parse_args()
def get_instances(self):
''' Get a list of vm instances with pyvmomi '''
instances = []
kwargs = {'host': self.server,
'user': self.username,
'pwd': self.password,
@@ -321,9 +326,7 @@ class VMWareInventory(object):
context.verify_mode = ssl.CERT_NONE
kwargs['sslContext'] = context
instances = self._get_instances(kwargs)
return instances
return self._get_instances(kwargs)
def _get_instances(self, inkwargs):
@@ -350,7 +353,7 @@ class VMWareInventory(object):
for child in children:
# If requested, limit the total number of instances
if self.args.max_instances:
if len(instances) >= (self.args.max_instances):
if len(instances) >= self.args.max_instances:
break
instances.append(child)
self.debugl("%s total instances in container view" % len(instances))
@@ -360,27 +363,30 @@ class VMWareInventory(object):
instance_tuples = []
for instance in sorted(instances):
if self.guest_props != False:
if self.guest_props:
ifacts = self.facts_from_proplist(instance)
else:
ifacts = self.facts_from_vobj(instance)
instance_tuples.append((instance, ifacts))
self.debugl('facts collected for all instances')
return instance_tuples
cfm = content.customFieldsManager
if cfm is not None and cfm.field:
for f in cfm.field:
if f.managedObjectType == vim.VirtualMachine:
self.custom_fields[f.key] = f.name;
self.debugl('%d custom fieds collected' % len(self.custom_fields))
return instance_tuples
def instances_to_inventory(self, instances):
''' Convert a list of vm objects into a json compliant inventory '''
self.debugl('re-indexing instances based on ini settings')
inventory = self._empty_inventory()
inventory = VMWareInventory._empty_inventory()
inventory['all'] = {}
inventory['all']['hosts'] = []
last_idata = None
total = len(instances)
for idx, instance in enumerate(instances):
# make a unique id for this object to avoid vmware's
# numerous uuid's which aren't all unique.
thisid = str(uuid.uuid4())
@@ -392,13 +398,16 @@ class VMWareInventory(object):
inventory['_meta']['hostvars'][thisid]['ansible_uuid'] = thisid
# Make a map of the uuid to the alias the user wants
name_mapping = self.create_template_mapping(inventory,
self.config.get('vmware', 'alias_pattern'))
name_mapping = self.create_template_mapping(
inventory,
self.config.get('vmware', 'alias_pattern')
)
# Make a map of the uuid to the ssh hostname the user wants
host_mapping = self.create_template_mapping(inventory,
self.config.get('vmware', 'host_pattern'))
host_mapping = self.create_template_mapping(
inventory,
self.config.get('vmware', 'host_pattern')
)
# Reset the inventory keys
for k, v in name_mapping.items():
@@ -411,7 +420,7 @@ class VMWareInventory(object):
inventory['_meta']['hostvars'][k]['ansible_host'] = host_mapping[k]
# 1.9.x backwards compliance
inventory['_meta']['hostvars'][k]['ansible_ssh_host'] = host_mapping[k]
except Exception as e:
except Exception:
continue
if k == v:
@@ -454,8 +463,34 @@ class VMWareInventory(object):
if k not in inventory[v]['hosts']:
inventory[v]['hosts'].append(k)
return inventory
if self.config.get('vmware', 'groupby_custom_field'):
for k, v in inventory['_meta']['hostvars'].items():
if 'customvalue' in v:
for tv in v['customvalue']:
if not isinstance(tv['value'], str) and not isinstance(tv['value'], unicode):
continue
newkey = None
field_name = self.custom_fields[tv['key']] if tv['key'] in self.custom_fields else tv['key']
values = []
keylist = map(lambda x: x.strip(), tv['value'].split(','))
for kl in keylist:
try:
newkey = self.config.get('vmware', 'custom_field_group_prefix') + field_name + '_' + kl
newkey = newkey.strip()
except Exception as e:
self.debugl(e)
values.append(newkey)
for tag in values:
if not tag:
continue
if tag not in inventory:
inventory[tag] = {}
inventory[tag]['hosts'] = []
if k not in inventory[tag]['hosts']:
inventory[tag]['hosts'].append(k)
return inventory
def create_template_mapping(self, inventory, pattern, dtype='string'):
@@ -494,7 +529,7 @@ class VMWareInventory(object):
if self.lowerkeys:
key = key.lower()
if not '.' in prop:
if '.' not in prop:
# props without periods are direct attributes of the parent
rdata[key] = getattr(vm, prop)
else:
@@ -533,7 +568,6 @@ class VMWareInventory(object):
return rdata
def facts_from_vobj(self, vobj, level=0):
''' Traverse a VM object and return a json compliant data structure '''
@@ -556,7 +590,7 @@ class VMWareInventory(object):
methods = dir(vobj)
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 = sorted(methods)
@@ -577,19 +611,20 @@ class VMWareInventory(object):
rdata[method] = self._process_object_types(
methodToCall,
thisvm=vobj,
inkey=method
inkey=method,
)
return rdata
def _process_object_types(self, vobj, thisvm=None, inkey=None, level=0):
''' Serialize an object '''
rdata = {}
if type(vobj).__name__ in self.vimTableMaxDepth and level >= self.vimTableMaxDepth[type(vobj).__name__]:
return rdata
if vobj is None:
rdata = None
elif type(vobj) in self.vimTable:
rdata = {}
for key in self.vimTable[type(vobj)]:
@@ -612,13 +647,11 @@ class VMWareInventory(object):
rdata = []
try:
vobj = sorted(vobj)
except Exception as e:
except Exception:
pass
for idv, vii in enumerate(vobj):
if (level+1 <= self.maxlevel):
if level + 1 <= self.maxlevel:
vid = self._process_object_types(
vii,
thisvm=thisvm,
@@ -635,8 +668,8 @@ class VMWareInventory(object):
elif issubclass(type(vobj), object):
methods = dir(vobj)
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.lower() in self.skip_keys]
methods = [x for x in methods if x not in self.bad_types]
methods = [x for x in methods if not inkey + '.' + x.lower() in self.skip_keys]
methods = sorted(methods)
for method in methods:
@@ -645,11 +678,13 @@ class VMWareInventory(object):
methodToCall = getattr(vobj, method)
except Exception as e:
continue
if callable(methodToCall):
continue
if self.lowerkeys:
method = method.lower()
if (level+1 <= self.maxlevel):
if level + 1 <= self.maxlevel:
rdata[method] = self._process_object_types(
methodToCall,
thisvm=thisvm,
@@ -668,10 +703,8 @@ class VMWareInventory(object):
if host in self.inventory['_meta']['hostvars']:
return self.inventory['_meta']['hostvars'][host]
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
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:
match = k
break