cloudstack/scripts/vm/hypervisor/vmware/discover_networks.py
John Bampton 182899d0b5
Add Python flake8 linting for W291 trailing whitespace with Super-Linter (#4687)
* refactor: remove trailing whitespace from Python files

* Add the GitHub Super-Linter

Add Python flake8 linting for W291 trailing whitespace

* Add licenses
2022-03-28 11:40:26 -03:00

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())