From 435b3065c41bac727e2298027d03a9d1e5480b31 Mon Sep 17 00:00:00 2001 From: Daniel Dayley Date: Fri, 9 Oct 2020 17:27:39 -0600 Subject: [PATCH] We finally have a vmware plugin! --- config_sample.yml | 10 +++ ifxlookup/plugins/vmware.py | 119 +++++++++++++++++++----------------- setup.py | 4 +- 3 files changed, 76 insertions(+), 57 deletions(-) diff --git a/config_sample.yml b/config_sample.yml index ac2e671..a4ee2e6 100644 --- a/config_sample.yml +++ b/config_sample.yml @@ -115,3 +115,13 @@ ldap : search_base: 'dc=movenetworks,dc=com' scope: 'sub' filter_string: 'uid~=' +vmware : + username: '' + key: '' + verify_ssl_cert: 'False' + hosts: + p-gp2-vmvc-2.imovetv.com: 10.124.137.100 + p-gil1-vmvc-2.imovetv.com: 10.126.12.231 + p-chy4-vmvc-1.imovetv.com: 10.126.144.22 + p-dc2-vmvc-2.imovetv.com: 10.125.136.23 + p-sv1-vmvc-2.imovetv.com: 10.125.8.23 diff --git a/ifxlookup/plugins/vmware.py b/ifxlookup/plugins/vmware.py index d7a13ee..060800d 100644 --- a/ifxlookup/plugins/vmware.py +++ b/ifxlookup/plugins/vmware.py @@ -1,66 +1,75 @@ +import requests +import urllib3 +from vmware.vapi.vsphere.client import create_vsphere_client +from com.vmware.vcenter_client import VM from ifxlookup.servicebase import ServiceBase -import socket - class ServiceDelegate(ServiceBase) : def get_arguments(cls) : """Returns an array of information used to construct an argumentparser argument.""" - return [ '-vm', '--vm', 'store_true', "Return DNS resolution about the subject (dns)" ] + return [ '-vm', '--vm', 'store_true', "Return VMWare information about the subject (vmware)" ] def startup(self) : - self.resolver = dns.resolver.Resolver() - if 'resolver' in self._config : - self.resolver.nameservers.append(self._config['resolver']) - - def lookup(self,subject) : - - # Note : hostname lookups always use system resolver. - try : - subjecttuple = socket.gethostbyname_ex(subject) - # Can't make an IP of the subject - except ValueError : + # Verify config + required_config_options = ['username','key','hosts','verify_ssl_cert'] + for requirement in required_config_options : + if requirement not in self._config : + self._error.append('Missing required config option ' + requirement) + return + self.debug('Looking up VMware information, this may take a minute or more.',1) + self.clients = {} + self.vm_list = {} + # Create a vsphere clinet for each vsphere instance + for hostname in self._config['hosts'].keys() : + url_session = requests.session() + verify = self._config['verify_ssl_cert'].lower() + if len([x for x in ['yes','true','1'] if verify.find(x)>-1]) > 0 : + self.debug('Attempting verified connection to ' + hostname + '...',2) + url_session.verify = True + else : + self.debug('Attempting unverified connection to ' + hostname + '...',2) + url_session.verify = False + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) try : - # Lookup with system - subjecttuple = socket.gethostbyname_ex(subject) - except socket.gaierror : - # Not a valid host or IP - self._error.append("Unable to resolve " + subject) - subjecttuple = [subject,[],['']] - # Can't make IPv4 out of it - except socket.gaierror : - self._error.append("Unable to resolve " + subject) - subjecttuple = [subject,[],['']] - # Get additional records - return_dict = {} - mx = self.get_records(subjecttuple[0],'MX') - ns = self.get_records(subjecttuple[0],'NS') - txt = self.get_records(subjecttuple[0],'TXT') - mx.sort() - ns.sort() - txt.sort() - if mx and len(mx) > 0 : - return_dict.update({'mx':mx}) - if ns and len(ns) > 0 : - return_dict.update({'ns':ns}) - if txt and len(txt) > 0 : - return_dict.update({'txt':txt}) - # Write final dictionary - if len(subjecttuple[2]) > 0 and subjecttuple[2][0] != '': - return_dict['addresses'] = list(subjecttuple[2]) - if subjecttuple[0] and subjecttuple[0] != '' : - return_dict['name'] = subjecttuple[0] - if len(subjecttuple[1]) > 0 : - return_dict['aliases'] = list(subjecttuple[1]) - return return_dict + # Create a client for this vsphere instance + client = create_vsphere_client(server=self._config['hosts'][hostname], username=self._config['username'], password=self._config['key'], session=url_session) + self.debug('Successfully connected to ' + hostname,2) + # Create a list of VMs available for quick lookups + self.vm_list.update({hostname:self.get_all_vms_from_client(client)}) + self.clients.update({hostname:client}) + self.debug('Retrieved VM list from ' + hostname,2) + except Exception as e : + self._error.append('Unable to connect to ' + hostname + ': ' + str(e)) + def lookup(self,subject) : + results = [] + # Get all VM names for each Vcenter, then get VMs whose names match + for client in self.clients : + all_vms = self.vm_list[client] + matches = [x for x in all_vms if subject in x.name] + self.debug('The following hostnames match subject on ' + str(client) + ': ' + str([x.name for x in matches]),3) + for match in matches : + # This is where we gather specific match info. Every call here increases response time. + summary = self.clients[client].vcenter.VM.get(match.vm) + summary = summary.to_dict() + # The SDK documentation supports thsi command, but it appears that our vcenter does not. Leaving it ehre for now +# networking = self.clients[client].vcenter.vm.guest.Networking.get(match.vm) +# summary.update({'networking':networking.to_dict()}) + guest = self.clients[client].vcenter.vm.guest.Identity.get(match.vm) + summary.update({'guest':guest.to_dict()}) + summary.update({'host':match.host}) + summary.update({'vcenter':client}) + results.append(summary) + return results + def get_all_vms_from_client(self,client) : + """From https://github.com/vmware/vsphere-automation-sdk-python/issues/142""" + results_list = [] + hosts = client.vcenter.Host.list() + for host_summary in hosts : + vms = client.vcenter.VM.list(VM.FilterSpec(hosts={host_summary.host})) + for vm in vms: + vm.host = host_summary.name + results_list.append(vm) + return results_list - def get_records(self,subject,recordtype) : - recs = [] - try : - results = self.resolver.query(subject,recordtype) - for result in results : - recs.append(result.to_text()) - return recs - except Exception as exception : - return recs diff --git a/setup.py b/setup.py index c402849..d9c1167 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import glob files = glob.glob('ifxlookup/plugins/*.py') setup(name='ifxlookup', - version='2.1.0', + version='2.1.1', url='https://p-bitbucket.imovetv.com/projects/IFX/repos/ifxlookup/browse', license='Apache2', author='Daniel Dayley', @@ -12,7 +12,7 @@ setup(name='ifxlookup', description='A python lookup module and command-line tool for infrastructure equipment.', packages=find_packages(exclude=['tests']), package_data={"": ['plugins/*.py']}, - install_requires=['dnspython','jsonpath-ng','paramiko','PyYAML','requests','shodan','ldap3'], + install_requires=['dnspython','jsonpath-ng','paramiko','PyYAML','requests','shodan','ldap3','vsphere-automation-sdk @ git+https://github.com/vmware/vsphere-automation-sdk-python.git'], scripts=['bin/ifxlookup'], long_description=open('README').read(), zip_safe=True