mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	* refactor: remove trailing whitespace from Python files * Add the GitHub Super-Linter Add Python flake8 linting for W291 trailing whitespace * Add licenses
		
			
				
	
	
		
			288 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			288 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env python3
 | |
| # Licensed to the Apache Software Foundation (ASF) under one
 | |
| # or more contributor license agreements.  See the NOTICE file
 | |
| # distributed with this work for additional information
 | |
| # regarding copyright ownership.  The ASF licenses this file
 | |
| # to you under the Apache License, Version 2.0 (the
 | |
| # "License"); you may not use this file except in compliance
 | |
| # with the License.  You may obtain a copy of the License at
 | |
| #
 | |
| #   http://www.apache.org/licenses/LICENSE-2.0
 | |
| #
 | |
| # Unless required by applicable law or agreed to in writing,
 | |
| # software distributed under the License is distributed on an
 | |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | |
| # KIND, either express or implied.  See the License for the
 | |
| # specific language governing permissions and limitations
 | |
| # under the License.
 | |
| 
 | |
| from pyVim.connect import SmartConnect, SmartConnectNoSSL, Disconnect
 | |
| from pyVmomi import vim
 | |
| import atexit
 | |
| import sys
 | |
| import argparse
 | |
| import json
 | |
| 
 | |
| isDebugLogs = False
 | |
| hostClusterNameDict = {}
 | |
| pgHostNameDict = {}
 | |
| networksDict = {}
 | |
| 
 | |
| def log_message(msg):
 | |
|     if isDebugLogs == True:
 | |
|         print(msg)
 | |
| 
 | |
| def get_clusters(content, cluster=None):
 | |
|     if cluster is not None:
 | |
|         log_message("Getting clusters (name=" + cluster + ") ...")
 | |
|     else:
 | |
|         log_message("Getting clusters ...")
 | |
|     cluster_view = content.viewManager.CreateContainerView(content.rootFolder,
 | |
|                                                         [vim.ClusterComputeResource],
 | |
|                                                         True)
 | |
|     clusters = []
 | |
|     if cluster is not None:
 | |
|         for c in cluster_view.view:
 | |
|             if c.name == cluster:
 | |
|                 clusters.append(c)
 | |
|                 hosts = c.host
 | |
|                 for host in hosts:
 | |
|                     hostClusterNameDict[host.name] = c.name
 | |
|                 break
 | |
|     else:
 | |
|         for c in cluster_view.view:
 | |
|             clusters.append(c)
 | |
|             hosts = c.host
 | |
|             for host in hosts:
 | |
|                 hostClusterNameDict[host.name] = c.name
 | |
|     cluster_view.Destroy()
 | |
|     log_message('\t{} cluster(s) found'.format(len(clusters)))
 | |
|     for c in clusters:
 | |
|         log_message('\t' + c.name)
 | |
|     return clusters
 | |
| 
 | |
| 
 | |
| def get_vm_hosts(clusters):
 | |
|     log_message("Getting ESX hosts ...")
 | |
|     hosts = []
 | |
|     for cluster in clusters:
 | |
|         hosts.extend(cluster.host)
 | |
|     log_message('\t{} host(s) found'.format(len(hosts)))
 | |
|     for host in hosts:
 | |
|         log_message('\t' + host.name)
 | |
|     return hosts
 | |
| 
 | |
| 
 | |
| def get_vms(content):
 | |
|     log_message("Getting VMs ...")
 | |
|     vm_view = content.viewManager.CreateContainerView(content.rootFolder,
 | |
|                                                       [vim.VirtualMachine],
 | |
|                                                       True)
 | |
|     obj = [vm for vm in vm_view.view]
 | |
|     vm_view.Destroy()
 | |
|     return obj
 | |
| 
 | |
| 
 | |
| def get_hosts_port_groups(hosts):
 | |
|     log_message("Collecting portGroups on hosts. This may take a while ...")
 | |
|     hostPgDict = {}
 | |
|     for host in hosts:
 | |
|         pgs = host.config.network.portgroup
 | |
|         hostPgDict[host] = pgs
 | |
|         for pg in pgs:
 | |
|             pgHostNameDict[pg.spec.name] = host.name
 | |
|         log_message("\tHost {} done.".format(host.name))
 | |
|     log_message("\tPortgroup collection complete.")
 | |
|     return hostPgDict
 | |
| 
 | |
| 
 | |
| def get_vm_info(vm, hostPgDict):
 | |
|     vmPowerState = vm.runtime.powerState
 | |
|     log_message('\tVM: ' + vm.name + '(' + vmPowerState + ')')
 | |
|     get_vm_nics(vm, hostPgDict)
 | |
| 
 | |
| 
 | |
| def get_vm_nics(vm, hostPgDict):
 | |
|     try:
 | |
|         for dev in vm.config.hardware.device:
 | |
|             if isinstance(dev, vim.vm.device.VirtualEthernetCard):
 | |
|                 dev_backing = dev.backing
 | |
|                 portGroup = None
 | |
|                 vlanId = None
 | |
|                 isolatedPvlan = None
 | |
|                 isolatedPvlanType = None
 | |
|                 vSwitch = None
 | |
|                 if hasattr(dev_backing, 'port'):
 | |
|                     portGroupKey = dev.backing.port.portgroupKey
 | |
|                     dvsUuid = dev.backing.port.switchUuid
 | |
|                     try:
 | |
|                         dvs = content.dvSwitchManager.QueryDvsByUuid(dvsUuid)
 | |
|                     except:
 | |
|                         log_message('\tError: Unable retrieve details for distributed vSwitch ' + dvsUuid)
 | |
|                         portGroup = ''
 | |
|                         vlanId = ''
 | |
|                         vSwitch = ''
 | |
|                     else:
 | |
|                         pgObj = dvs.LookupDvPortGroup(portGroupKey)
 | |
|                         portGroup = pgObj.config.name
 | |
|                         try:
 | |
|                             if isinstance(pgObj.config.defaultPortConfig.vlan, vim.dvs.VmwareDistributedVirtualSwitch.PvlanSpec):
 | |
|                                 for pvlanConfig in dvs.config.pvlanConfig:
 | |
|                                     if pvlanConfig.secondaryVlanId == pgObj.config.defaultPortConfig.vlan.pvlanId:
 | |
|                                         vlanId = str(pvlanConfig.primaryVlanId)
 | |
|                                         isolatedPvlanType = pvlanConfig.pvlanType
 | |
|                                         isolatedPvlan = str(pgObj.config.defaultPortConfig.vlan.pvlanId)
 | |
|                                         break
 | |
|                             else:
 | |
|                                 vlanId = str(pgObj.config.defaultPortConfig.vlan.vlanId)
 | |
|                         except AttributeError:
 | |
|                             log_message('\tError: Unable retrieve details for portgroup ' + portGroup)
 | |
|                             vlanId = ''
 | |
|                         vSwitch = str(dvs.name)
 | |
|                 else:
 | |
|                     portGroup = dev.backing.network.name
 | |
|                     vmHost = vm.runtime.host
 | |
|                     # global variable hostPgDict stores portGroups per host
 | |
|                     pgs = hostPgDict[vmHost]
 | |
|                     for p in pgs:
 | |
|                         if portGroup in p.key:
 | |
|                             vlanId = str(p.spec.vlanId)
 | |
|                             vSwitch = str(p.spec.vswitchName)
 | |
|                 if portGroup is None:
 | |
|                     portGroup = ''
 | |
|                 if vlanId is None:
 | |
|                     vlanId = ''
 | |
|                 vmHostName = None
 | |
|                 vmClusterName = None
 | |
|                 try:
 | |
|                     vmHostName = vm.runtime.host.name
 | |
|                 except AttributeError:
 | |
|                     vmHostName = ''
 | |
|                 try:
 | |
|                     vmClusterName = vm.runtime.host.parent.name
 | |
|                 except AttributeError:
 | |
|                     vmClusterName = ''
 | |
|                 add_network(portGroup, vlanId, isolatedPvlanType, isolatedPvlan, vSwitch, vm.name, dev.deviceInfo.label, dev.macAddress, vmClusterName, vmHostName)
 | |
|                 log_message('\t\t' + dev.deviceInfo.label + '->' + dev.macAddress +
 | |
|                       ' @ ' + vSwitch + '->' + portGroup +
 | |
|                       ' (VLAN ' + vlanId + ')')
 | |
|     except AttributeError:
 | |
|         log_message('\tError: Unable retrieve details for ' + vm.name)
 | |
| 
 | |
| def add_network(portGroup, vlanId, isolatedPvlanType, isolatedPvlan, vSwitch, vmName, vmDeviceLabel, vmMacAddress, vmClusterName, vmHostName):
 | |
|     key = vSwitch + '->' + portGroup + ' (VLAN ' + vlanId + ')'
 | |
|     device = {"label": vmDeviceLabel, "macaddress": vmMacAddress}
 | |
|     vm = {"name":vmName, "device": device}
 | |
|     if key in networksDict:
 | |
|         network = networksDict[key]
 | |
|         network["virtualmachines"].append(vm)
 | |
|         networksDict[key] = network
 | |
|     else:
 | |
|         vms = [vm]
 | |
|         try:
 | |
|             host = pgHostNameDict[portGroup]
 | |
|         except KeyError:
 | |
|             host = vmHostName
 | |
|         try:
 | |
|             cluster = hostClusterNameDict[host]
 | |
|         except KeyError:
 | |
|             cluster = vmClusterName
 | |
| 
 | |
|         network = {"portgroup": portGroup, "cluster": cluster, "host": host, "switch": vSwitch, "virtualmachines": vms}
 | |
|         if vlanId != '':
 | |
|             network["vlanid"] = vlanId
 | |
|         if isolatedPvlan is not None:
 | |
|             network["isolatedpvlan"] = isolatedPvlan
 | |
|         if isolatedPvlanType is not None:
 | |
|             network["isolatedpvlantype"] = isolatedPvlanType
 | |
|         networksDict[key] = network
 | |
| 
 | |
| 
 | |
| def get_args():
 | |
|     parser = argparse.ArgumentParser(
 | |
|         description='Arguments for talking to vCenter')
 | |
| 
 | |
|     parser.add_argument('-s', '--host',
 | |
|                         required=True,
 | |
|                         action='store',
 | |
|                         help='vSpehre service to connect to')
 | |
| 
 | |
|     parser.add_argument('-o', '--port',
 | |
|                         type=int,
 | |
|                         default=443,
 | |
|                         action='store',
 | |
|                         help='Port to connect on')
 | |
| 
 | |
|     parser.add_argument('-u', '--user',
 | |
|                         required=True,
 | |
|                         action='store',
 | |
|                         help='User name to use')
 | |
| 
 | |
|     parser.add_argument('-p', '--password',
 | |
|                         required=False,
 | |
|                         action='store',
 | |
|                         help='Password to use')
 | |
| 
 | |
|     parser.add_argument('-c', '--cluster',
 | |
|                         required=False,
 | |
|                         action='store',
 | |
|                         help='Cluster for which discover networks')
 | |
| 
 | |
|     parser.add_argument('-S', '--disable_ssl_verification',
 | |
|                         required=False,
 | |
|                         action='store_true',
 | |
|                         help='Disable ssl host certificate verification')
 | |
| 
 | |
|     parser.add_argument('-d', '--debug',
 | |
|                         required=False,
 | |
|                         action='store_true',
 | |
|                         help='Debug log messages')
 | |
| 
 | |
|     args = parser.parse_args()
 | |
|     return args
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     global content, isDebugLogs, hostClusterNameDict, pgHostNameDict, networksDict
 | |
|     args = get_args()
 | |
|     if args.password:
 | |
|         password = args.password
 | |
|     else:
 | |
|         password = getpass.getpass(prompt='Enter password for host %s and '
 | |
|                                    'user %s: ' % (args.host, args.user))
 | |
|     if args.debug:
 | |
|         isDebugLogs = True
 | |
|     if args.disable_ssl_verification:
 | |
|         serviceInstance = SmartConnectNoSSL(host=args.host,
 | |
|                                user=args.user,
 | |
|                                pwd=password,
 | |
|                                port=int(args.port))
 | |
|     else:
 | |
|         serviceInstance = SmartConnect(host=args.host,
 | |
|                           user=args.user,
 | |
|                           pwd=password,
 | |
|                           port=int(args.port))
 | |
| 
 | |
|     atexit.register(Disconnect, serviceInstance)
 | |
|     content = serviceInstance.RetrieveContent()
 | |
|     if args.cluster:
 | |
|         clusters = get_clusters(content, args.cluster)
 | |
|     else:
 | |
|         clusters = get_clusters(content)
 | |
|     hosts = []
 | |
|     if len(clusters) > 0:
 | |
|         hosts = get_vm_hosts(clusters)
 | |
|     if len(hosts) > 0:
 | |
|         hostPgDict = get_hosts_port_groups(hosts)
 | |
|         vms = get_vms(content)
 | |
|         log_message('\t{} VM(s) found'.format(len(vms)))
 | |
|         for vm in vms:
 | |
|             get_vm_info(vm, hostPgDict)
 | |
|     networks = list(networksDict.values())
 | |
|     response = {"count": len(networks), "networks": networks}
 | |
|     print(json.dumps(response, indent=2, sort_keys=True))
 | |
| 
 | |
| # Main section
 | |
| if __name__ == "__main__":
 | |
|     sys.exit(main())
 |