#!/usr/bin/env python # $Id: vsphere-vm-tags,v 1.11 2019/02/13 03:21:36 friedman Exp $ # This uses the vSphere Automation SDK for Python as well as pyVmomi. from __future__ import print_function import requests import ssl import simplejson as json import com.vmware.cis_client as cis_client import com.vmware.cis.tagging_client as tagging_client import com.vmware.vapi.std.errors_client as errors_client import com.vmware.vapi.std_client as std_client import com.vmware.vapi.metadata.metamodel.resource_client as resource_client from vmware.vapi.lib.connect import get_requests_connector from vmware.vapi.security.session import create_session_security_context from vmware.vapi.security.user_password import create_user_password_security_context from vmware.vapi.stdlib.client.factories import StubConfigurationFactory from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings( InsecureRequestWarning ) import vspherelib as vsl from pyVmomi import vim import pprint _pp_printer = pprint.PrettyPrinter( indent=2, width=40 ) def _print( *args, **kwargs ): for arg in args: _pp_printer.pprint( arg, **kwargs ) class vapiConnect(): def __init__( self, host=None, user=None, passwd=None, vmlist=None ): self.vmlist = vmlist self.host = host self.user = user self.passwd = passwd self.connect() self.cat_svc = tagging_client.Category( self.stub_config ) self.tag_svc = tagging_client.Tag( self.stub_config ) self.tag_assoc = tagging_client.TagAssociation( self.stub_config ) self.cat_tbl = {} self.tag_tbl = {} def connect( self ): host_url = "https://{}/api".format( self.host ) self.session = requests.Session() self.session.verify = False self.connector = get_requests_connector( session=self.session, url=host_url ) self.stub_config = StubConfigurationFactory.new_std_configuration( self.connector ) self.login() def login( self ): # Pass user credentials (user/password) in the security context to authenticate. self.userpass_ctx = create_user_password_security_context( self.user, self.passwd ) self.stub_config.connector.set_security_context( self.userpass_ctx ) # Create the stub for the session service and login by creating a session. self.session_id = cis_client.Session( self.stub_config ).create() # Successful authentication. Store the session identifier in the security # context of the stub and use that for all subsequent remote requests self.session_ctx = create_session_security_context( self.session_id ) self.stub_config.connector.set_security_context( self.session_ctx ) def logout( self ): if self.stub_config: session_svc = cis_client.Session( self.stub_config ) session_svc.delete() self.stub_config = None def __del__( self ): self.logout() def category_name( self, cat_id ): try: return self.cat_tbl[ cat_id ] except KeyError: t = vsl.Timer( 'cat_svc.get:' + cat_id ) cat = self.cat_svc.get( cat_id ) t.report() self.cat_tbl[ cat_id ] = cat.name return cat.name def _tag_id_data( self, tag_id ): try: return self.tag_tbl[ tag_id ] except KeyError: t = vsl.Timer( 'tag_svc.get:' + tag_id ) tag = self.tag_svc.get( tag_id ) t.report() self.tag_tbl[ tag_id ] = { 'cat_id' : tag.category_id, 'name' : tag.name } return self.tag_tbl[ tag_id ] def tag_name( self, tag_id ): return self._tag_id_data( tag_id )[ 'name' ] def tag_category( self, tag_id ): cat_id = self._tag_id_data( tag_id )[ 'cat_id' ] return self.category_name( cat_id ) def vmid_tags( self ): vm_ids = [ std_client.DynamicID( type = 'VirtualMachine', id = str( vm['obj'].id ) ) for vm in self.vmlist ] t = vsl.Timer( 'vmid_tags_legacy: list_attached_tags_on_objects' ) tagged_objects = self.tag_assoc.list_attached_tags_on_objects( vm_ids ) t.report() result = {} for elt in tagged_objects: tbl = {} for tag_id in elt.tag_ids: tag_name = self.tag_name( tag_id ) tag_cat = self.tag_category( tag_id ) try: tbl[ tag_cat ].append( tag_name ) except KeyError: tbl[ tag_cat ] = [ tag_name ] result[ elt.object_id.id ] = tbl return result # This is slower but appears to be all that works with vSphere 6.0 def vmid_tags_legacy( self ): result = {} for tag_id in self.tag_svc.list(): t = vsl.Timer( 'vmid_tags_legacy: list_attached_objects: ' + tag_id ) vm_ids = [ obj.id for obj in filter( lambda obj: obj.type == 'VirtualMachine', self.tag_assoc.list_attached_objects( tag_id )) ] t.report() if not vm_ids: continue tag_name = self.tag_name( tag_id ) tag_cat = self.tag_category( tag_id ) for vm_id in vm_ids: try: vm_result = result[ vm_id ] except KeyError: vm_result = result[ vm_id ] = {} try: vm_result[ tag_cat ].append( tag_name ) except KeyError: vm_result[ tag_cat ] = [ tag_name ] return result def main(): args = vsl.ArgumentParser( loadrc=True ).parse_args() vsi = vsl.vmomiConnect( args ) obj_props = [ 'name', #'config.template', #'runtime.powerState', 'guest.guestState', 'guest.hostName', 'guest.ipAddress', ] t = vsl.Timer( 'get_obj_props' ) vmlist = vsi.get_obj_props( [vim.VirtualMachine], obj_props ) t.report() t = vsl.Timer( 'vapiConnect' ) vpi = vapiConnect( vmlist = vmlist, host = args.host, user = args.user, passwd = args.password ) t.report() try: vm_tags = vpi.vmid_tags() except errors_client.Unauthenticated: # The fact that this exception is Unauthenticated rather than # Unauthorized (which is the documented exception) against vSphere # 6.0 leads me to suspect that the faster methods just aren't # supported there. vm_tags = vpi.vmid_tags_legacy() t = vsl.Timer( 'make vmtbl' ) vmtbl = {} for vm in vmlist: vmtbl[ vm.pop( 'name' ) ] = vm vmid = vm.pop( 'obj' )._moId try: vm.update( vm_tags[ vmid ] ) except KeyError: pass try: vm[ 'hostname' ] = vm.pop( 'guest.hostName' ) except KeyError: pass try: vm[ 'ip' ] = vm.pop( 'guest.ipAddress' ) except KeyError: pass t.report() t = vsl.Timer( 'generate json' ) out = json.dumps( vmtbl, sort_keys = True, #indent = None, indent = 4, separators = (',', ' : '), check_circular = False ) t.report() print( out ) if __name__ == '__main__': main() # eof