summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/inventory/vmware.ini50
-rwxr-xr-xcontrib/inventory/vmware.py472
-rw-r--r--contrib/inventory/vmware_inventory.ini127
-rwxr-xr-xcontrib/inventory/vmware_inventory.py793
4 files changed, 0 insertions, 1442 deletions
diff --git a/contrib/inventory/vmware.ini b/contrib/inventory/vmware.ini
deleted file mode 100644
index 93de5d67b4..0000000000
--- a/contrib/inventory/vmware.ini
+++ /dev/null
@@ -1,50 +0,0 @@
-# Ansible VMware external inventory script settings
-
-[defaults]
-
-# If true (the default), return only guest VMs. If false, also return host
-# systems in the results.
-guests_only = True
-
-# Specify an alternate group name for guest VMs. If not defined, defaults to
-# the basename of the inventory script + "_vm", e.g. "vmware_vm".
-#vm_group = vm_group_name
-
-# Specify an alternate group name for host systems when guests_only=false.
-# If not defined, defaults to the basename of the inventory script + "_hw",
-# e.g. "vmware_hw".
-#hw_group = hw_group_name
-
-# Specify the number of seconds to use the inventory cache before it is
-# considered stale. If not defined, defaults to 0 seconds.
-#cache_max_age = 3600
-
-# Specify the directory used for storing the inventory cache. If not defined,
-# caching will be disabled.
-#cache_dir = ~/.cache/ansible
-
-# Specify a prefix filter. Any VMs with names beginning with this string will
-# not be returned.
-# prefix_filter = test_
-
-# Specify a cluster filter list (colon delimited). Only clusters matching by
-# name will be scanned for virtualmachines
-#clusters = cluster1,cluster2
-
-[auth]
-
-# Specify hostname or IP address of vCenter/ESXi server. A port may be
-# included with the hostname, e.g.: vcenter.example.com:8443. This setting
-# may also be defined via the VMWARE_HOST environment variable.
-host = vcenter.example.com
-
-# Specify a username to access the vCenter host. This setting may also be
-# defined with the VMWARE_USER environment variable.
-user = ihasaccess
-
-# Specify a password to access the vCenter host. This setting may also be
-# defined with the VMWARE_PASSWORD environment variable.
-password = ssshverysecret
-
-# Force SSL certificate checking by default or ignore self-signed certs.
-#sslcheck=True
diff --git a/contrib/inventory/vmware.py b/contrib/inventory/vmware.py
deleted file mode 100755
index 483fd42318..0000000000
--- a/contrib/inventory/vmware.py
+++ /dev/null
@@ -1,472 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-'''
-VMware Inventory Script
-=======================
-
-Retrieve information about virtual machines from a vCenter server or
-standalone ESX host. When `group_by=false` (in the INI file), host systems
-are also returned in addition to VMs.
-
-This script will attempt to read configuration from an INI file with the same
-base filename if present, or `vmware.ini` if not. It is possible to create
-symlinks to the inventory script to support multiple configurations, e.g.:
-
-* `vmware.py` (this script)
-* `vmware.ini` (default configuration, will be read by `vmware.py`)
-* `vmware_test.py` (symlink to `vmware.py`)
-* `vmware_test.ini` (test configuration, will be read by `vmware_test.py`)
-* `vmware_other.py` (symlink to `vmware.py`, will read `vmware.ini` since no
- `vmware_other.ini` exists)
-
-The path to an INI file may also be specified via the `VMWARE_INI` environment
-variable, in which case the filename matching rules above will not apply.
-
-Host and authentication parameters may be specified via the `VMWARE_HOST`,
-`VMWARE_USER` and `VMWARE_PASSWORD` environment variables; these options will
-take precedence over options present in the INI file. An INI file is not
-required if these options are specified using environment variables.
-'''
-
-from __future__ import print_function
-
-import json
-import logging
-import optparse
-import os
-import ssl
-import sys
-import time
-
-from ansible.module_utils.common._collections_compat import MutableMapping
-from ansible.module_utils.six import integer_types, text_type, string_types
-from ansible.module_utils.six.moves import configparser
-
-# Disable logging message trigged by pSphere/suds.
-try:
- from logging import NullHandler
-except ImportError:
- from logging import Handler
-
- class NullHandler(Handler):
- def emit(self, record):
- pass
-
-logging.getLogger('psphere').addHandler(NullHandler())
-logging.getLogger('suds').addHandler(NullHandler())
-
-from psphere.client import Client
-from psphere.errors import ObjectNotFoundError
-from psphere.managedobjects import HostSystem, VirtualMachine, ManagedObject, Network, ClusterComputeResource
-from suds.sudsobject import Object as SudsObject
-
-
-class VMwareInventory(object):
-
- def __init__(self, guests_only=None):
- self.config = configparser.SafeConfigParser()
- if os.environ.get('VMWARE_INI', ''):
- config_files = [os.environ['VMWARE_INI']]
- else:
- config_files = [os.path.abspath(sys.argv[0]).rstrip('.py') + '.ini', 'vmware.ini']
- for config_file in config_files:
- if os.path.exists(config_file):
- self.config.read(config_file)
- break
-
- # Retrieve only guest VMs, or include host systems?
- if guests_only is not None:
- self.guests_only = guests_only
- elif self.config.has_option('defaults', 'guests_only'):
- self.guests_only = self.config.getboolean('defaults', 'guests_only')
- else:
- self.guests_only = True
-
- # Read authentication information from VMware environment variables
- # (if set), otherwise from INI file.
- auth_host = os.environ.get('VMWARE_HOST')
- if not auth_host and self.config.has_option('auth', 'host'):
- auth_host = self.config.get('auth', 'host')
- auth_user = os.environ.get('VMWARE_USER')
- if not auth_user and self.config.has_option('auth', 'user'):
- auth_user = self.config.get('auth', 'user')
- auth_password = os.environ.get('VMWARE_PASSWORD')
- if not auth_password and self.config.has_option('auth', 'password'):
- auth_password = self.config.get('auth', 'password')
- sslcheck = os.environ.get('VMWARE_SSLCHECK')
- if not sslcheck and self.config.has_option('auth', 'sslcheck'):
- sslcheck = self.config.get('auth', 'sslcheck')
- if not sslcheck:
- sslcheck = True
- else:
- if sslcheck.lower() in ['no', 'false']:
- sslcheck = False
- else:
- sslcheck = True
-
- # Limit the clusters being scanned
- self.filter_clusters = os.environ.get('VMWARE_CLUSTERS')
- if not self.filter_clusters and self.config.has_option('defaults', 'clusters'):
- self.filter_clusters = self.config.get('defaults', 'clusters')
- if self.filter_clusters:
- self.filter_clusters = [x.strip() for x in self.filter_clusters.split(',') if x.strip()]
-
- # Override certificate checks
- if not sslcheck:
- if hasattr(ssl, '_create_unverified_context'):
- ssl._create_default_https_context = ssl._create_unverified_context
-
- # Create the VMware client connection.
- self.client = Client(auth_host, auth_user, auth_password)
-
- def _put_cache(self, name, value):
- '''
- Saves the value to cache with the name given.
- '''
- if self.config.has_option('defaults', 'cache_dir'):
- cache_dir = os.path.expanduser(self.config.get('defaults', 'cache_dir'))
- if not os.path.exists(cache_dir):
- os.makedirs(cache_dir)
- cache_file = os.path.join(cache_dir, name)
- with open(cache_file, 'w') as cache:
- json.dump(value, cache)
-
- def _get_cache(self, name, default=None):
- '''
- Retrieves the value from cache for the given name.
- '''
- if self.config.has_option('defaults', 'cache_dir'):
- cache_dir = self.config.get('defaults', 'cache_dir')
- cache_file = os.path.join(cache_dir, name)
- if os.path.exists(cache_file):
- if self.config.has_option('defaults', 'cache_max_age'):
- cache_max_age = self.config.getint('defaults', 'cache_max_age')
- else:
- cache_max_age = 0
- cache_stat = os.stat(cache_file)
- if (cache_stat.st_mtime + cache_max_age) >= time.time():
- with open(cache_file) as cache:
- return json.load(cache)
- return default
-
- def _flatten_dict(self, d, parent_key='', sep='_'):
- '''
- Flatten nested dicts by combining keys with a separator. Lists with
- only string items are included as is; any other lists are discarded.
- '''
- items = []
- for k, v in d.items():
- if k.startswith('_'):
- continue
- new_key = parent_key + sep + k if parent_key else k
- if isinstance(v, MutableMapping):
- items.extend(self._flatten_dict(v, new_key, sep).items())
- elif isinstance(v, (list, tuple)):
- if all([isinstance(x, string_types) for x in v]):
- items.append((new_key, v))
- else:
- items.append((new_key, v))
- return dict(items)
-
- def _get_obj_info(self, obj, depth=99, seen=None):
- '''
- Recursively build a data structure for the given pSphere object (depth
- only applies to ManagedObject instances).
- '''
- seen = seen or set()
- if isinstance(obj, ManagedObject):
- try:
- obj_unicode = text_type(getattr(obj, 'name'))
- except AttributeError:
- obj_unicode = ()
- if obj in seen:
- return obj_unicode
- seen.add(obj)
- if depth <= 0:
- return obj_unicode
- d = {}
- for attr in dir(obj):
- if attr.startswith('_'):
- continue
- try:
- val = getattr(obj, attr)
- obj_info = self._get_obj_info(val, depth - 1, seen)
- if obj_info != ():
- d[attr] = obj_info
- except Exception as e:
- pass
- return d
- elif isinstance(obj, SudsObject):
- d = {}
- for key, val in iter(obj):
- obj_info = self._get_obj_info(val, depth, seen)
- if obj_info != ():
- d[key] = obj_info
- return d
- elif isinstance(obj, (list, tuple)):
- l = []
- for val in iter(obj):
- obj_info = self._get_obj_info(val, depth, seen)
- if obj_info != ():
- l.append(obj_info)
- return l
- elif isinstance(obj, (type(None), bool, float) + string_types + integer_types):
- return obj
- else:
- return ()
-
- def _get_host_info(self, host, prefix='vmware'):
- '''
- Return a flattened dict with info about the given host system.
- '''
- host_info = {
- 'name': host.name,
- }
- for attr in ('datastore', 'network', 'vm'):
- try:
- value = getattr(host, attr)
- host_info['%ss' % attr] = self._get_obj_info(value, depth=0)
- except AttributeError:
- host_info['%ss' % attr] = []
- for k, v in self._get_obj_info(host.summary, depth=0).items():
- if isinstance(v, MutableMapping):
- for k2, v2 in v.items():
- host_info[k2] = v2
- elif k != 'host':
- host_info[k] = v
- try:
- host_info['ipAddress'] = host.config.network.vnic[0].spec.ip.ipAddress
- except Exception as e:
- print(e, file=sys.stderr)
- host_info = self._flatten_dict(host_info, prefix)
- if ('%s_ipAddress' % prefix) in host_info:
- host_info['ansible_ssh_host'] = host_info['%s_ipAddress' % prefix]
- return host_info
-
- def _get_vm_info(self, vm, prefix='vmware'):
- '''
- Return a flattened dict with info about the given virtual machine.
- '''
- vm_info = {
- 'name': vm.name,
- }
- for attr in ('datastore', 'network'):
- try:
- value = getattr(vm, attr)
- vm_info['%ss' % attr] = self._get_obj_info(value, depth=0)
- except AttributeError:
- vm_info['%ss' % attr] = []
- try:
- vm_info['resourcePool'] = self._get_obj_info(vm.resourcePool, depth=0)
- except AttributeError:
- vm_info['resourcePool'] = ''
- try:
- vm_info['guestState'] = vm.guest.guestState
- except AttributeError:
- vm_info['guestState'] = ''
- for k, v in self._get_obj_info(vm.summary, depth=0).items():
- if isinstance(v, MutableMapping):
- for k2, v2 in v.items():
- if k2 == 'host':
- k2 = 'hostSystem'
- vm_info[k2] = v2
- elif k != 'vm':
- vm_info[k] = v
- vm_info = self._flatten_dict(vm_info, prefix)
- if ('%s_ipAddress' % prefix) in vm_info:
- vm_info['ansible_ssh_host'] = vm_info['%s_ipAddress' % prefix]
- return vm_info
-
- def _add_host(self, inv, parent_group, host_name):
- '''
- Add the host to the parent group in the given inventory.
- '''
- p_group = inv.setdefault(parent_group, [])
- if isinstance(p_group, dict):
- group_hosts = p_group.setdefault('hosts', [])
- else:
- group_hosts = p_group
- if host_name not in group_hosts:
- group_hosts.append(host_name)
-
- def _add_child(self, inv, parent_group, child_group):
- '''
- Add a child group to a parent group in the given inventory.
- '''
- if parent_group != 'all':
- p_group = inv.setdefault(parent_group, {})
- if not isinstance(p_group, dict):
- inv[parent_group] = {'hosts': p_group}
- p_group = inv[parent_group]
- group_children = p_group.setdefault('children', [])
- if child_group not in group_children:
- group_children.append(child_group)
- inv.setdefault(child_group, [])
-
- def get_inventory(self, meta_hostvars=True):
- '''
- Reads the inventory from cache or VMware API via pSphere.
- '''
- # Use different cache names for guests only vs. all hosts.
- if self.guests_only:
- cache_name = '__inventory_guests__'
- else:
- cache_name = '__inventory_all__'
-
- inv = self._get_cache(cache_name, None)
- if inv is not None:
- return inv
-
- inv = {'all': {'hosts': []}}
- if meta_hostvars:
- inv['_meta'] = {'hostvars': {}}
-
- default_group = os.path.basename(sys.argv[0]).rstrip('.py')
-
- if not self.guests_only:
- if self.config.has_option('defaults', 'hw_group'):
- hw_group = self.config.get('defaults', 'hw_group')
- else:
- hw_group = default_group + '_hw'
-
- if self.config.has_option('defaults', 'vm_group'):
- vm_group = self.config.get('defaults', 'vm_group')
- else:
- vm_group = default_group + '_vm'
-
- if self.config.has_option('defaults', 'prefix_filter'):
- prefix_filter = self.config.get('defaults', 'prefix_filter')
- else:
- prefix_filter = None
-
- if self.filter_clusters:
- # Loop through clusters and find hosts:
- hosts = []
- for cluster in ClusterComputeResource.all(self.client):
- if cluster.name in self.filter_clusters:
- for host in cluster.host:
- hosts.append(host)
- else:
- # Get list of all physical hosts
- hosts = HostSystem.all(self.client)
-
- # Loop through physical hosts:
- for host in hosts:
-
- if not self.guests_only:
- self._add_host(inv, 'all', host.name)
- self._add_host(inv, hw_group, host.name)
- host_info = self._get_host_info(host)
- if meta_hostvars:
- inv['_meta']['hostvars'][host.name] = host_info
- self._put_cache(host.name, host_info)
-
- # Loop through all VMs on physical host.
- for vm in host.vm:
- if prefix_filter:
- if vm.name.startswith(prefix_filter):
- continue
- self._add_host(inv, 'all', vm.name)
- self._add_host(inv, vm_group, vm.name)
- vm_info = self._get_vm_info(vm)
- if meta_hostvars:
- inv['_meta']['hostvars'][vm.name] = vm_info
- self._put_cache(vm.name, vm_info)
-
- # Group by resource pool.
- vm_resourcePool = vm_info.get('vmware_resourcePool', None)
- if vm_resourcePool:
- self._add_child(inv, vm_group, 'resource_pools')
- self._add_child(inv, 'resource_pools', vm_resourcePool)
- self._add_host(inv, vm_resourcePool, vm.name)
-
- # Group by datastore.
- for vm_datastore in vm_info.get('vmware_datastores', []):
- self._add_child(inv, vm_group, 'datastores')
- self._add_child(inv, 'datastores', vm_datastore)
- self._add_host(inv, vm_datastore, vm.name)
-
- # Group by network.
- for vm_network in vm_info.get('vmware_networks', []):
- self._add_child(inv, vm_group, 'networks')
- self._add_child(inv, 'networks', vm_network)
- self._add_host(inv, vm_network, vm.name)
-
- # Group by guest OS.
- vm_guestId = vm_info.get('vmware_guestId', None)
- if vm_guestId:
- self._add_child(inv, vm_group, 'guests')
- self._add_child(inv, 'guests', vm_guestId)
- self._add_host(inv, vm_guestId, vm.name)
-
- # Group all VM templates.
- vm_template = vm_info.get('vmware_template', False)
- if vm_template:
- self._add_child(inv, vm_group, 'templates')
- self._add_host(inv, 'templates', vm.name)
-
- self._put_cache(cache_name, inv)
- return inv
-
- def get_host(self, hostname):
- '''
- Read info about a specific host or VM from cache or VMware API.
- '''
- inv = self._get_cache(hostname, None)
- if inv is not None:
- return inv
-
- if not self.guests_only:
- try:
- host = HostSystem.get(self.client, name=hostname)
- inv = self._get_host_info(host)
- except ObjectNotFoundError:
- pass
-
- if inv is None:
- try:
- vm = VirtualMachine.get(self.client, name=hostname)
- inv = self._get_vm_info(vm)
- except ObjectNotFoundError:
- pass
-
- if inv is not None:
- self._put_cache(hostname, inv)
- return inv or {}
-
-
-def main():
- parser = optparse.OptionParser()
- parser.add_option('--list', action='store_true', dest='list',
- default=False, help='Output inventory groups and hosts')
- parser.add_option('--host', dest='host', default=None, metavar='HOST',
- help='Output variables only for the given hostname')
- # Additional options for use when running the script standalone, but never
- # used by Ansible.
- parser.add_option('--pretty', action='store_true', dest='pretty',
- default=False, help='Output nicely-formatted JSON')
- parser.add_option('--include-host-systems', action='store_true',
- dest='include_host_systems', default=False,
- help='Include host systems in addition to VMs')
- parser.add_option('--no-meta-hostvars', action='store_false',
- dest='meta_hostvars', default=True,
- help='Exclude [\'_meta\'][\'hostvars\'] with --list')
- options, args = parser.parse_args()
-
- if options.include_host_systems:
- vmware_inventory = VMwareInventory(guests_only=False)
- else:
- vmware_inventory = VMwareInventory()
- if options.host is not None:
- inventory = vmware_inventory.get_host(options.host)
- else:
- inventory = vmware_inventory.get_inventory(options.meta_hostvars)
-
- json_kwargs = {}
- if options.pretty:
- json_kwargs.update({'indent': 4, 'sort_keys': True})
- json.dump(inventory, sys.stdout, **json_kwargs)
-
-
-if __name__ == '__main__':
- main()
diff --git a/contrib/inventory/vmware_inventory.ini b/contrib/inventory/vmware_inventory.ini
deleted file mode 100644
index f94570f891..0000000000
--- a/contrib/inventory/vmware_inventory.ini
+++ /dev/null
@@ -1,127 +0,0 @@
-# Ansible VMware external inventory script settings
-
-[vmware]
-
-# The resolvable hostname or ip address of the vsphere
-server=vcenter
-
-# The port for the vsphere API
-#port=443
-
-# The username with access to the vsphere API. This setting
-# may also be defined via the VMWARE_USERNAME environment variable.
-username=administrator@vsphere.local
-
-# The password for the vsphere API. This setting
-# may also be defined via the VMWARE_PASSWORD environment variable.
-password=vmware
-
-# Verify the server's SSL certificate
-#validate_certs = True
-
-# Specify the number of seconds to use the inventory cache before it is
-# considered stale. If not defined, defaults to 0 seconds.
-#cache_max_age = 3600
-
-
-# Specify the directory used for storing the inventory cache. If not defined,
-# caching will be disabled.
-#cache_path = ~/.cache/ansible
-
-
-# Max object level refers to the level of recursion the script will delve into
-# the objects returned from pyvomi to find serializable facts. The default
-# level of 0 is sufficient for most tasks and will be the most performant.
-# Beware that the recursion can exceed python's limit (causing traceback),
-# cause sluggish script performance and return huge blobs of facts.
-# If you do not know what you are doing, leave this set to 1.
-#max_object_level=1
-
-
-# Lower the keynames for facts to make addressing them easier.
-#lower_var_keys=True
-
-
-# Don't retrieve and process some VMware attribute keys
-# Default values permit to sanitize inventory meta and to improve a little bit
-# performance by removing non-common group attributes.
-#skip_keys = declaredalarmstate,disabledmethod,dynamicproperty,dynamictype,environmentbrowser,managedby,parent,childtype,resourceconfig
-
-
-# Host alias for objects in the inventory. VMware allows duplicate VM names
-# so they can not be considered unique. Use this setting to alter the alias
-# returned for the hosts. Any atributes for the guest can be used to build
-# this alias. The default combines the config name and the config uuid and
-# expects that the ansible_host will be set by the host_pattern.
-#alias_pattern={{ config.name + '_' + config.uuid }}
-
-
-# Host pattern is the value set for ansible_host and ansible_ssh_host, which
-# needs to be a hostname or ipaddress the ansible controlhost can reach.
-#host_pattern={{ guest.ipaddress }}
-
-
-# Host filters are a comma separated list of jinja patterns to remove
-# non-matching hosts from the final result.
-# EXAMPLES:
-# host_filters={{ config.guestid == 'rhel7_64Guest' }}
-# host_filters={{ config.cpuhotremoveenabled != False }},{{ runtime.maxmemoryusage >= 512 }}
-# host_filters={{ config.cpuhotremoveenabled != False }},{{ runtime.maxmemoryusage >= 512 }}
-# host_filters={{ runtime.powerstate == "poweredOn" }}
-# host_filters={{ guest.gueststate == "notRunning" }}
-# The default value is powerstate of virtual machine equal to "poweredOn". (Changed in version 2.5)
-# Runtime state does not require to have vmware tools installed as compared to "guest.gueststate"
-#host_filters={{ runtime.powerstate == "poweredOn" }}
-
-
-
-# Groupby patterns enable the user to create groups via any possible jinja
-# expression. The resulting value will the groupname and the host will be added
-# to that group. Be careful to not make expressions that simply return True/False
-# because those values will become the literal group name. The patterns can be
-# comma delimited to create as many groups as necessary
-#groupby_patterns={{ guest.guestid }},{{ 'templates' if config.template else 'guests'}}
-
-# Group by custom fields will use VMware custom fields to generate hostgroups
-# based on {{ custom_field_group_prefix }} + field_name + _ + field_value
-# Set groupby_custom_field to True will enable this feature
-# If custom field value is comma separated, multiple groups are created.
-# Warning: This required max_object_level to be set to 2 or greater.
-#groupby_custom_field = False
-
-# You can customize prefix used by custom field hostgroups generation here.
-# vmware_tag_ prefix is the default and consistent with ec2_tag_
-#custom_field_group_prefix = vmware_tag_
-
-# You can blacklist custom fields so that they are not included in the
-# groupby_custom_field option. This is useful when you have custom fields that
-# have values that are unique to individual hosts. Timestamps for example.
-# The groupby_custom_field_excludes option should be a comma separated list of custom
-# field keys to be blacklisted.
-#groupby_custom_field_excludes=<custom_field_1>,<custom_field_2>,<custom_field_3>
-
-# The script attempts to recurse into virtualmachine objects and serialize
-# all available data. The serialization is comprehensive but slow. If the
-# vcenter environment is large and the desired properties are known, create
-# a 'properties' section in this config and make an arbitrary list of
-# key=value settings where the value is a path to a specific property. If
-# If this feature is enabled, be sure to fetch every property that is used
-# in the jinja expressions defined above. For performance tuning, reduce
-# the number of properties to the smallest amount possible and limit the
-# use of properties that are not direct attributes of vim.VirtualMachine
-#[properties]
-#prop01=name
-#prop02=config.cpuHotAddEnabled
-#prop03=config.cpuHotRemoveEnabled
-#prop04=config.instanceUuid
-#prop05=config.hardware.numCPU
-#prop06=config.template
-#prop07=config.name
-#prop08=guest.hostName
-#prop09=guest.ipAddress
-#prop10=guest.guestId
-#prop11=guest.guestState
-#prop12=runtime.maxMemoryUsage
-# In order to populate `customValue` (virtual machine's custom attributes) inside hostvars,
-# uncomment following property. Please see - https://github.com/ansible/ansible/issues/41395
-#prop13=customValue
diff --git a/contrib/inventory/vmware_inventory.py b/contrib/inventory/vmware_inventory.py
deleted file mode 100755
index 0271110c96..0000000000
--- a/contrib/inventory/vmware_inventory.py
+++ /dev/null
@@ -1,793 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright (C): 2017, Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-# Requirements
-# - pyvmomi >= 6.0.0.2016.4
-
-# TODO:
-# * more jq examples
-# * optional folder hierarchy
-
-"""
-$ jq '._meta.hostvars[].config' data.json | head
-{
- "alternateguestname": "",
- "instanceuuid": "5035a5cd-b8e8-d717-e133-2d383eb0d675",
- "memoryhotaddenabled": false,
- "guestfullname": "Red Hat Enterprise Linux 7 (64-bit)",
- "changeversion": "2016-05-16T18:43:14.977925Z",
- "uuid": "4235fc97-5ddb-7a17-193b-9a3ac97dc7b4",
- "cpuhotremoveenabled": false,
- "vpmcenabled": false,
- "firmware": "bios",
-"""
-
-from __future__ import print_function
-
-import atexit
-import datetime
-import itertools
-import json
-import os
-import re
-import ssl
-import sys
-import uuid
-from time import time
-
-from jinja2 import Environment
-
-from ansible.module_utils.six import integer_types, PY3
-from ansible.module_utils.six.moves import configparser
-
-try:
- import argparse
-except ImportError:
- sys.exit('Error: This inventory script required "argparse" python module. Please install it or upgrade to python-2.7')
-
-try:
- from pyVmomi import vim, vmodl
- from pyVim.connect import SmartConnect, Disconnect
-except ImportError:
- sys.exit("ERROR: This inventory script required 'pyVmomi' Python module, it was not able to load it")
-
-
-def regex_match(s, pattern):
- '''Custom filter for regex matching'''
- reg = re.compile(pattern)
- if reg.match(s):
- return True
- else:
- return False
-
-
-def select_chain_match(inlist, key, pattern):
- '''Get a key from a list of dicts, squash values to a single list, then filter'''
- outlist = [x[key] for x in inlist]
- outlist = list(itertools.chain(*outlist))
- outlist = [x for x in outlist if regex_match(x, pattern)]
- return outlist
-
-
-class VMwareMissingHostException(Exception):
- pass
-
-
-class VMWareInventory(object):
- __name__ = 'VMWareInventory'
-
- guest_props = False
- instances = []
- debug = False
- load_dumpfile = None
- write_dumpfile = None
- maxlevel = 1
- lowerkeys = True
- config = None
- 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 = []
- groupby_custom_field_excludes = []
-
- safe_types = [bool, str, float, None] + list(integer_types)
- iter_types = [dict, list]
-
- bad_types = ['Array', 'disabledMethod', 'declaredAlarmState']
-
- vimTableMaxDepth = {
- "vim.HostSystem": 2,
- "vim.VirtualMachine": 2,
- }
-
- custom_fields = {}
-
- # use jinja environments to allow for custom filters
- env = Environment()
- env.filters['regex_match'] = regex_match
- env.filters['select_chain_match'] = select_chain_match
-
- # translation table for attributes to fetch for known vim types
-
- vimTable = {
- vim.Datastore: ['_moId', 'name'],
- vim.ResourcePool: ['_moId', 'name'],
- vim.HostSystem: ['_moId', 'name'],
- }
-
- @staticmethod
- def _empty_inventory():
- return {"_meta": {"hostvars": {}}}
-
- def __init__(self, load=True):
- self.inventory = VMWareInventory._empty_inventory()
-
- if load:
- # Read settings and parse CLI arguments
- self.parse_cli_args()
- self.read_settings()
-
- # Check the cache
- cache_valid = self.is_cache_valid()
-
- # Handle Cache
- if self.args.refresh_cache or not cache_valid:
- self.do_api_calls_update_cache()
- else:
- self.debugl('loading inventory from cache')
- self.inventory = self.get_inventory_from_cache()
-
- def debugl(self, text):
- if self.args.debug:
- try:
- text = str(text)
- except UnicodeEncodeError:
- text = text.encode('utf-8')
- print('%s %s' % (datetime.datetime.now(), text))
-
- def show(self):
- # Data to print
- self.debugl('dumping results')
- data_to_print = None
- if self.args.host:
- data_to_print = self.get_host_info(self.args.host)
- elif self.args.list:
- # Display list of instances for inventory
- 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 '''
-
- valid = False
-
- if os.path.isfile(self.cache_path_cache):
- mod_time = os.path.getmtime(self.cache_path_cache)
- current_time = time()
- if (mod_time + self.cache_max_age) > current_time:
- valid = True
-
- return valid
-
- def do_api_calls_update_cache(self):
- ''' Get instances and cache the data '''
- self.inventory = self.instances_to_inventory(self.get_instances())
- self.write_to_cache(self.inventory)
-
- def write_to_cache(self, data):
- ''' Dump inventory to json file '''
- with open(self.cache_path_cache, 'w') as f:
- f.write(json.dumps(data, indent=2))
-
- def get_inventory_from_cache(self):
- ''' Read in jsonified inventory '''
-
- jdata = None
- with open(self.cache_path_cache, 'r') as f:
- jdata = f.read()
- return json.loads(jdata)
-
- def read_settings(self):
- ''' Reads the settings from the vmware_inventory.ini file '''
-
- scriptbasename = __file__
- scriptbasename = os.path.basename(scriptbasename)
- scriptbasename = scriptbasename.replace('.py', '')
-
- defaults = {'vmware': {
- 'server': '',
- 'port': 443,
- 'username': '',
- 'password': '',
- 'validate_certs': True,
- 'ini_path': os.path.join(os.path.dirname(__file__), '%s.ini' % scriptbasename),
- 'cache_name': 'ansible-vmware',
- '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': '{{ runtime.powerstate == "poweredOn" }}',
- 'groupby_patterns': '{{ guest.guestid }},{{ "templates" if config.template else "guests"}}',
- 'lower_var_keys': True,
- 'custom_field_group_prefix': 'vmware_tag_',
- 'groupby_custom_field_excludes': '',
- 'groupby_custom_field': False}
- }
-
- if PY3:
- config = configparser.ConfigParser()
- else:
- config = configparser.SafeConfigParser()
-
- # where is the config?
- vmware_ini_path = os.environ.get('VMWARE_INI_PATH', defaults['vmware']['ini_path'])
- vmware_ini_path = os.path.expanduser(os.path.expandvars(vmware_ini_path))
- config.read(vmware_ini_path)
-
- if 'vmware' not in config.sections():
- config.add_section('vmware')
-
- # apply defaults
- for k, v in defaults['vmware'].items():
- if not config.has_option('vmware', k):
- config.set('vmware', k, str(v))
-
- # where is the cache?
- self.cache_dir = os.path.expanduser(config.get('vmware', 'cache_path'))
- if self.cache_dir and not os.path.exists(self.cache_dir):
- os.makedirs(self.cache_dir)
-
- # set the cache filename and max age
- cache_name = config.get('vmware', 'cache_name')
- self.cache_path_cache = self.cache_dir + "/%s.cache" % cache_name
- self.debugl('cache path is %s' % self.cache_path_cache)
- self.cache_max_age = int(config.getint('vmware', 'cache_max_age'))
-
- # mark the connection info
- self.server = os.environ.get('VMWARE_SERVER', config.get('vmware', 'server'))
- self.debugl('server is %s' % self.server)
- self.port = int(os.environ.get('VMWARE_PORT', config.get('vmware', 'port')))
- self.username = os.environ.get('VMWARE_USERNAME', config.get('vmware', 'username'))
- self.debugl('username is %s' % self.username)
- self.password = os.environ.get('VMWARE_PASSWORD', config.get('vmware', 'password', raw=True))
- 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
-
- self.debugl('cert validation is %s' % self.validate_certs)
-
- # behavior control
- self.maxlevel = int(config.get('vmware', 'max_object_level'))
- self.debugl('max object level is %s' % self.maxlevel)
- self.lowerkeys = config.get('vmware', 'lower_var_keys')
- if type(self.lowerkeys) != bool:
- if str(self.lowerkeys).lower() in ['yes', 'true', '1']:
- self.lowerkeys = True
- 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)
- temp_host_filters = list(config.get('vmware', 'host_filters').split('}},'))
- for host_filter in temp_host_filters:
- host_filter = host_filter.rstrip()
- if host_filter != "":
- if not host_filter.endswith("}}"):
- host_filter += "}}"
- self.host_filters.append(host_filter)
- self.debugl('host filters are %s' % self.host_filters)
-
- temp_groupby_patterns = list(config.get('vmware', 'groupby_patterns').split('}},'))
- for groupby_pattern in temp_groupby_patterns:
- groupby_pattern = groupby_pattern.rstrip()
- if groupby_pattern != "":
- if not groupby_pattern.endswith("}}"):
- groupby_pattern += "}}"
- self.groupby_patterns.append(groupby_pattern)
- self.debugl('groupby patterns are %s' % self.groupby_patterns)
- temp_groupby_custom_field_excludes = config.get('vmware', 'groupby_custom_field_excludes')
- self.groupby_custom_field_excludes = [x.strip('"') for x in [y.strip("'") for y in temp_groupby_custom_field_excludes.split(",")]]
- self.debugl('groupby exclude strings are %s' % self.groupby_custom_field_excludes)
-
- # Special feature to disable the brute force serialization of the
- # virtual machine objects. The key name for these properties does not
- # matter because the values are just items for a larger list.
- if config.has_section('properties'):
- self.guest_props = []
- for prop in config.items('properties'):
- self.guest_props.append(prop[1])
-
- # save the config
- self.config = config
-
- def parse_cli_args(self):
- ''' Command line argument processing '''
-
- parser = argparse.ArgumentParser(description='Produce an Ansible Inventory file based on PyVmomi')
- parser.add_argument('--debug', action='store_true', default=False,
- help='show debug info')
- parser.add_argument('--list', action='store_true', default=True,
- help='List instances (default: True)')
- parser.add_argument('--host', action='store',
- help='Get all the variables about a specific instance')
- parser.add_argument('--refresh-cache', action='store_true', default=False,
- help='Force refresh of cache by making API requests to VSphere (default: False - use cache files)')
- parser.add_argument('--max-instances', default=None, type=int,
- help='maximum number of instances to retrieve')
- self.args = parser.parse_args()
-
- def get_instances(self):
- ''' Get a list of vm instances with pyvmomi '''
- kwargs = {'host': self.server,
- 'user': self.username,
- 'pwd': self.password,
- 'port': int(self.port)}
-
- if self.validate_certs and hasattr(ssl, 'SSLContext'):
- context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- context.verify_mode = ssl.CERT_REQUIRED
- context.check_hostname = True
- kwargs['sslContext'] = context
- elif self.validate_certs and not hasattr(ssl, 'SSLContext'):
- sys.exit('pyVim does not support changing verification mode with python < 2.7.9. Either update '
- 'python or use validate_certs=false.')
- elif not self.validate_certs and hasattr(ssl, 'SSLContext'):
- context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- context.verify_mode = ssl.CERT_NONE
- context.check_hostname = False
- kwargs['sslContext'] = context
- elif not self.validate_certs and not hasattr(ssl, 'SSLContext'):
- # Python 2.7.9 < or RHEL/CentOS 7.4 <
- pass
-
- return self._get_instances(kwargs)
-
- def _get_instances(self, inkwargs):
- ''' Make API calls '''
- instances = []
- si = None
- try:
- si = SmartConnect(**inkwargs)
- except ssl.SSLError as connection_error:
- if '[SSL: CERTIFICATE_VERIFY_FAILED]' in str(connection_error) and self.validate_certs:
- sys.exit("Unable to connect to ESXi server due to %s, "
- "please specify validate_certs=False and try again" % connection_error)
-
- except Exception as exc:
- self.debugl("Unable to connect to ESXi server due to %s" % exc)
- sys.exit("Unable to connect to ESXi server due to %s" % exc)
-
- self.debugl('retrieving all instances')
- if not si:
- sys.exit("Could not connect to the specified host using specified "
- "username and password")
- atexit.register(Disconnect, si)
- content = si.RetrieveContent()
-
- # Create a search container for virtualmachines
- self.debugl('creating containerview for virtualmachines')
- container = content.rootFolder
- viewType = [vim.VirtualMachine]
- 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("%s total instances in container view" % len(instances))
-
- if self.args.host:
- instances = [x for x in instances if x.name == self.args.host]
-
- instance_tuples = []
- for instance in instances:
- 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')
-
- try:
- cfm = content.customFieldsManager
- if cfm is not None and cfm.field:
- for f in cfm.field:
- if not f.managedObjectType or f.managedObjectType == vim.VirtualMachine:
- self.custom_fields[f.key] = f.name
- self.debugl('%d custom fields collected' % len(self.custom_fields))
- except vmodl.RuntimeFault as exc:
- self.debugl("Unable to gather custom fields due to %s" % exc.msg)
- except IndexError as exc:
- self.debugl("Unable to gather custom fields due to %s" % exc)
-
- 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 = VMWareInventory._empty_inventory()
- inventory['all'] = {}
- inventory['all']['hosts'] = []
- 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())
- idata = instance[1]
-
- # Put it in the inventory
- inventory['all']['hosts'].append(thisid)
- inventory['_meta']['hostvars'][thisid] = idata.copy()
- 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')
- )
-
- # 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')
- )
-
- # Reset the inventory keys
- for k, v in name_mapping.items():
-
- if not host_mapping or k not in host_mapping:
- continue
-
- # set ansible_host (2.x)
- try:
- 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:
- continue
-
- if k == v:
- continue
-
- # add new key
- inventory['all']['hosts'].append(v)
- inventory['_meta']['hostvars'][v] = inventory['_meta']['hostvars'][k]
-
- # cleanup old key
- inventory['all']['hosts'].remove(k)
- inventory['_meta']['hostvars'].pop(k, None)
-
- self.debugl('pre-filtered hosts:')
- for i in inventory['all']['hosts']:
- self.debugl(' * %s' % i)
- # Apply host filters
- for hf in self.host_filters:
- if not hf:
- continue
- self.debugl('filter: %s' % hf)
- filter_map = self.create_template_mapping(inventory, hf, dtype='boolean')
- for k, v in filter_map.items():
- if not v:
- # delete this host
- inventory['all']['hosts'].remove(k)
- inventory['_meta']['hostvars'].pop(k, None)
-
- self.debugl('post-filter hosts:')
- for i in inventory['all']['hosts']:
- self.debugl(' * %s' % i)
-
- # Create groups
- for gbp in self.groupby_patterns:
- groupby_map = self.create_template_mapping(inventory, gbp)
- for k, v in groupby_map.items():
- if v not in inventory:
- inventory[v] = {}
- inventory[v]['hosts'] = []
- if k not in inventory[v]['hosts']:
- inventory[v]['hosts'].append(k)
-
- 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']:
- newkey = None
- field_name = self.custom_fields[tv['key']] if tv['key'] in self.custom_fields else tv['key']
- if field_name in self.groupby_custom_field_excludes:
- continue
- values = []
- keylist = map(lambda x: x.strip(), tv['value'].split(','))
- for kl in keylist:
- try:
- newkey = "%s%s_%s" % (self.config.get('vmware', 'custom_field_group_prefix'), str(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'):
- ''' Return a hash of uuid to templated string from pattern '''
- mapping = {}
- for k, v in inventory['_meta']['hostvars'].items():
- t = self.env.from_string(pattern)
- newkey = None
- try:
- newkey = t.render(v)
- newkey = newkey.strip()
- except Exception as e:
- self.debugl(e)
- if not newkey:
- continue
- elif dtype == 'integer':
- newkey = int(newkey)
- elif dtype == 'boolean':
- if newkey.lower() == 'false':
- newkey = False
- elif newkey.lower() == 'true':
- newkey = True
- elif dtype == 'string':
- pass
- mapping[k] = newkey
- return mapping
-
- def facts_from_proplist(self, vm):
- '''Get specific properties instead of serializing everything'''
-
- rdata = {}
- for prop in self.guest_props:
- self.debugl('getting %s property for %s' % (prop, vm.name))
- key = prop
- if self.lowerkeys:
- key = key.lower()
-
- if '.' not in prop:
- # props without periods are direct attributes of the parent
- vm_property = getattr(vm, prop)
- if isinstance(vm_property, vim.CustomFieldsManager.Value.Array):
- temp_vm_property = []
- for vm_prop in vm_property:
- temp_vm_property.append({'key': vm_prop.key,
- 'value': vm_prop.value})
- rdata[key] = temp_vm_property
- else:
- rdata[key] = vm_property
- else:
- # props with periods are subkeys of parent attributes
- parts = prop.split('.')
- total = len(parts) - 1
-
- # pointer to the current object
- val = None
- # pointer to the current result key
- lastref = rdata
-
- for idx, x in enumerate(parts):
-
- if isinstance(val, dict):
- if x in val:
- val = val.get(x)
- elif x.lower() in val:
- val = val.get(x.lower())
- else:
- # if the val wasn't set yet, get it from the parent
- if not val:
- try:
- val = getattr(vm, x)
- except AttributeError as e:
- self.debugl(e)
- else:
- # in a subkey, get the subprop from the previous attrib
- try:
- val = getattr(val, x)
- except AttributeError as e:
- self.debugl(e)
-
- # make sure it serializes
- val = self._process_object_types(val)
-
- # lowercase keys if requested
- if self.lowerkeys:
- x = x.lower()
-
- # change the pointer or set the final value
- if idx != total:
- if x not in lastref:
- lastref[x] = {}
- lastref = lastref[x]
- else:
- lastref[x] = val
- if self.args.debug:
- self.debugl("For %s" % vm.name)
- for key in list(rdata.keys()):
- if isinstance(rdata[key], dict):
- for ikey in list(rdata[key].keys()):
- self.debugl("Property '%s.%s' has value '%s'" % (key, ikey, rdata[key][ikey]))
- else:
- self.debugl("Property '%s' has value '%s'" % (key, rdata[key]))
- return rdata
-
- def facts_from_vobj(self, vobj, level=0):
- ''' Traverse a VM object and return a json compliant data structure '''
-
- # pyvmomi objects are not yet serializable, but may be one day ...
- # https://github.com/vmware/pyvmomi/issues/21
-
- # WARNING:
- # Accessing an object attribute will trigger a SOAP call to the remote.
- # Increasing the attributes collected or the depth of recursion greatly
- # increases runtime duration and potentially memory+network utilization.
-
- if level == 0:
- try:
- self.debugl("get facts for %s" % vobj.name)
- except Exception as e:
- self.debugl(e)
-
- rdata = {}
-
- methods = dir(vobj)
- methods = [str(x) for x in methods if not x.startswith('_')]
- 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)
-
- for method in methods:
- # 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,
- thisvm=vobj,
- inkey=method,
- )
-
- return rdata
-
- def _process_object_types(self, vobj, thisvm=None, inkey='', 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)]:
- try:
- rdata[key] = getattr(vobj, key)
- except Exception as e:
- self.debugl(e)
-
- elif issubclass(type(vobj), str) or isinstance(vobj, str):
- if vobj.isalnum():
- rdata = vobj
- else:
- rdata = vobj.encode('utf-8').decode('utf-8')
- elif issubclass(type(vobj), bool) or isinstance(vobj, bool):
- rdata = vobj
- elif issubclass(type(vobj), integer_types) or isinstance(vobj, integer_types):
- rdata = vobj
- elif issubclass(type(vobj), float) or isinstance(vobj, float):
- rdata = vobj
- elif issubclass(type(vobj), list) or issubclass(type(vobj), tuple):
- rdata = []
- try:
- vobj = sorted(vobj)
- except Exception:
- pass
-
- for idv, vii in enumerate(vobj):
- if level + 1 <= self.maxlevel:
- vid = self._process_object_types(
- vii,
- thisvm=thisvm,
- inkey=inkey + '[' + str(idv) + ']',
- level=(level + 1)
- )
-
- if vid:
- rdata.append(vid)
-
- elif issubclass(type(vobj), dict):
- pass
-
- 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 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:
- # Attempt to get the method, skip on fail
- try:
- methodToCall = getattr(vobj, method)
- except Exception as e:
- continue
-
- if callable(methodToCall):
- continue
-
- if self.lowerkeys:
- method = method.lower()
- if level + 1 <= self.maxlevel:
- try:
- rdata[method] = self._process_object_types(
- methodToCall,
- thisvm=thisvm,
- inkey=inkey + '.' + method,
- level=(level + 1)
- )
- except vim.fault.NoPermission:
- self.debugl("Skipping method %s (NoPermission)" % method)
- else:
- pass
-
- return rdata
-
- def get_host_info(self, host):
- ''' Return hostvars for a single host '''
-
- if host in self.inventory['_meta']['hostvars']:
- return self.inventory['_meta']['hostvars'][host]
- elif self.args.host and self.inventory['_meta']['hostvars']:
- match = None
- for k, v in self.inventory['_meta']['hostvars'].items():
- if self.inventory['_meta']['hostvars'][k]['name'] == self.args.host:
- match = k
- break
- if match:
- return self.inventory['_meta']['hostvars'][match]
- else:
- raise VMwareMissingHostException('%s not found' % host)
- else:
- raise VMwareMissingHostException('%s not found' % host)
-
-
-if __name__ == "__main__":
- # Run the script
- print(VMWareInventory().show())