Skip to content

Commit 799a033

Browse files
Gaurav AradhyeSrikanteswaraRao Talluri
authored andcommitted
CLOUDSTACK-8361: Adding functionality in marvin to check the port groups in VCenter corresponding to configuration of traffics in physical networks
Signed-off-by: SrikanteswaraRao Talluri <talluri@apache.org> This closes #144
1 parent 3f89cd6 commit 799a033

File tree

3 files changed

+293
-4
lines changed

3 files changed

+293
-4
lines changed

tools/marvin/marvin/codes.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,19 @@
111111
Network states
112112
'''
113113
ALLOCATED = "Allocated"
114+
114115
'''
115116
Storage Tags
116117
'''
117118
ZONETAG1 = "zwps1"
118119
ZONETAG2 = "zwps2"
119120
CLUSTERTAG1 = "cwps1"
120121
CLUSTERTAG2 = "cwps2"
122+
123+
'''
124+
Traffic Types
125+
'''
126+
PUBLIC_TRAFFIC = "public"
127+
GUEST_TRAFFIC = "guest"
128+
MANAGEMENT_TRAFFIC = "management"
129+
STORAGE_TRAFFIC = "storage"

tools/marvin/marvin/lib/base.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4795,4 +4795,32 @@ def generateRecords(cls, apiclient, **kwargs):
47954795
[setattr(cmd, k, v) for k, v in kwargs.items()]
47964796
return(apiclient.generateUsageRecords(cmd))
47974797

4798+
class TrafficType:
4799+
"""Manage different traffic types in the setup"""
4800+
4801+
def __init__(self, items):
4802+
self.__dict__.update(items)
4803+
4804+
@classmethod
4805+
def list(cls, apiclient, **kwargs):
4806+
"""Lists traffic types"""
4807+
4808+
cmd = listTrafficTypes.listTrafficTypesCmd()
4809+
[setattr(cmd, k, v) for k, v in kwargs.items()]
4810+
return(apiclient.listTrafficTypes(cmd))
4811+
4812+
class StorageNetworkIpRange:
4813+
"""Manage Storage Network Ip Range"""
4814+
4815+
def __init__(self, items):
4816+
self.__dict__.update(items)
4817+
4818+
@classmethod
4819+
def list(cls, apiclient, **kwargs):
4820+
"""Lists Storage Network IP Ranges"""
4821+
4822+
cmd = listStorageNetworkIpRange.listStorageNetworkIpRangeCmd()
4823+
[setattr(cmd, k, v) for k, v in kwargs.items()]
4824+
return(apiclient.listStorageNetworkIpRange(cmd))
4825+
47984826

tools/marvin/marvin/lib/common.py

Lines changed: 256 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@
6161
from marvin.codes import (PASS, FAILED, ISOLATED_NETWORK, VPC_NETWORK,
6262
BASIC_ZONE, FAIL, NAT_RULE, STATIC_NAT_RULE,
6363
RESOURCE_PRIMARY_STORAGE, RESOURCE_SECONDARY_STORAGE,
64-
RESOURCE_CPU, RESOURCE_MEMORY)
64+
RESOURCE_CPU, RESOURCE_MEMORY, PUBLIC_TRAFFIC,
65+
GUEST_TRAFFIC, MANAGEMENT_TRAFFIC, STORAGE_TRAFFIC)
6566
from marvin.lib.utils import (validateList, xsplit, get_process_status)
6667
from marvin.lib.base import (PhysicalNetwork,
6768
PublicIPAddress,
@@ -80,10 +81,13 @@
8081
Host,
8182
Resources,
8283
Configurations,
83-
Router)
84+
Router,
85+
PublicIpRange,
86+
StorageNetworkIpRange,
87+
TrafficType)
8488
import random
85-
86-
89+
import re
90+
import itertools
8791
# Import System modules
8892
import time
8993

@@ -1417,3 +1421,251 @@ def verifyRouterState(apiclient, routerid, state, listall=True):
14171421
exceptionMessage = e
14181422
return [exceptionOccured, isRouterInDesiredState, exceptionMessage]
14191423
return [exceptionOccured, isRouterInDesiredState, exceptionMessage]
1424+
1425+
def analyzeTrafficType(trafficTypes, trafficTypeToFilter):
1426+
""" Analyze traffic types for given type and return
1427+
switch name and vlan Id from the
1428+
vmwarenetworklabel string of trafficTypeToFilter
1429+
"""
1430+
1431+
try:
1432+
filteredList = [trafficType for trafficType in trafficTypes
1433+
if trafficType.traffictype.lower() ==
1434+
trafficTypeToFilter]
1435+
1436+
if not filteredList:
1437+
return [PASS, filteredList, None, None]
1438+
1439+
# Split string with , so as to extract the switch Name and
1440+
# vlan ID
1441+
splitString = str(
1442+
filteredList[0].vmwarenetworklabel).split(",")
1443+
switchName = splitString[0]
1444+
vlanSpecified = splitString[1]
1445+
1446+
return [PASS, filteredList, switchName, vlanSpecified]
1447+
except Exception as e:
1448+
return [FAIL, e, None, None]
1449+
1450+
1451+
def getExpectedPortGroupNames(
1452+
api_client,
1453+
physical_network,
1454+
network_rate,
1455+
switch_name,
1456+
traffic_types,
1457+
switch_dict,
1458+
vcenter_conn,
1459+
specified_vlan,
1460+
traffic_type):
1461+
""" Return names of expected port groups that should be
1462+
present in vcenter
1463+
1464+
Parameters:
1465+
@physical_network: Physical Network of the @traffic_type
1466+
@network_rate: as defined by network.throttling.rate
1467+
@switch_name: Name of the switch used by the traffic in
1468+
vcenter
1469+
@traffic_types: List of all traffic types present in the physical
1470+
network
1471+
@switch_dict: Dictionary containing switch information in vcenter
1472+
@vcenter_conn: vcenter connection object used to fetch information
1473+
from vcenter
1474+
@specified_vlan: The vlan for @traffic_type
1475+
@traffic_type: Traffic type for which the port names are to be
1476+
returned
1477+
1478+
Return value:
1479+
[PASS/FAIL, exception object if FAIL else expected port group names
1480+
for @traffic_type]
1481+
"""
1482+
1483+
try:
1484+
expectedDVPortGroupNames = []
1485+
1486+
if traffic_type == PUBLIC_TRAFFIC:
1487+
publicIpRanges = PublicIpRange.list(
1488+
api_client,
1489+
physicalnetworkid=physical_network.id
1490+
)
1491+
if publicIpRanges is not None:
1492+
for publicIpRange in publicIpRanges:
1493+
vlanInIpRange = re.findall(
1494+
'\d+',
1495+
str(publicIpRange.vlan))
1496+
if len(vlanInIpRange) > 0:
1497+
vlanId = vlanInIpRange[0]
1498+
expectedDVPortGroupName = "cloud" + "." + \
1499+
PUBLIC_TRAFFIC + "." + vlanId + "." + \
1500+
network_rate + "." + "1" + "-" + \
1501+
switch_name
1502+
expectedDVPortGroupNames.append(
1503+
expectedDVPortGroupName)
1504+
1505+
expectedDVPortGroupName = "cloud" + "." + PUBLIC_TRAFFIC + "." + \
1506+
vlanId + "." + "0" + "." + "1" + "-" + switch_name
1507+
expectedDVPortGroupNames.append(expectedDVPortGroupName)
1508+
1509+
if traffic_type == GUEST_TRAFFIC:
1510+
1511+
networks = Network.list(
1512+
api_client,
1513+
physicalnetworkid=physical_network.id,
1514+
listall=True
1515+
)
1516+
if networks is not None:
1517+
for network in networks:
1518+
networkVlan = re.findall(
1519+
'\d+', str(network.vlan))
1520+
if len(networkVlan) > 0:
1521+
vlanId = networkVlan[0]
1522+
expectedDVPortGroupName = "cloud" + "." + GUEST_TRAFFIC + "." + \
1523+
vlanId + "." + network_rate + "." + "1" + "-" + \
1524+
switch_name
1525+
expectedDVPortGroupNames.append(
1526+
expectedDVPortGroupName)
1527+
1528+
if traffic_type == STORAGE_TRAFFIC:
1529+
vlanId = ""
1530+
storageIpRanges = StorageNetworkIpRange.list(
1531+
api_client,
1532+
zoneid=physical_network.zoneid
1533+
)
1534+
if storageIpRanges is not None:
1535+
for storageIpRange in storageIpRanges:
1536+
vlanInIpRange = re.findall(
1537+
'\d+',
1538+
str(storageIpRange.vlan))
1539+
if len(vlanInIpRange) > 0:
1540+
vlanId = vlanInIpRange[0]
1541+
else:
1542+
vlanId = "untagged"
1543+
expectedDVPortGroupName = "cloud" + "." + STORAGE_TRAFFIC + \
1544+
"." + vlanId + "." + "0" + "." + "1" + "-" + \
1545+
switch_name
1546+
expectedDVPortGroupNames.append(
1547+
expectedDVPortGroupName)
1548+
1549+
else:
1550+
response = analyzeTrafficType(
1551+
traffic_types, MANAGEMENT_TRAFFIC)
1552+
assert response[0] == PASS, response[1]
1553+
filteredList, switchName, vlanSpecified =\
1554+
response[1], response[2], response[3]
1555+
1556+
if not filteredList:
1557+
raise Exception("No Management traffic present and\
1558+
Storage traffic does not have any IP range,\
1559+
Invalid zone setting")
1560+
1561+
if switchName not in switch_dict:
1562+
dvswitches = vcenter_conn.get_dvswitches(
1563+
name=switchName)
1564+
switch_dict[switchName] = dvswitches[0][
1565+
'dvswitch']['portgroupNameList']
1566+
1567+
if vlanSpecified:
1568+
vlanId = vlanSpecified
1569+
else:
1570+
vlanId = "untagged"
1571+
expectedDVPortGroupName = "cloud" + "." + STORAGE_TRAFFIC + \
1572+
"." + vlanId + "." + "0" + "." + "1" + "-" + switchName
1573+
expectedDVPortGroupNames.append(expectedDVPortGroupName)
1574+
1575+
if traffic_type == MANAGEMENT_TRAFFIC:
1576+
vlanId = "untagged"
1577+
if specified_vlan:
1578+
vlanId = specified_vlan
1579+
expectedDVPortGroupName = "cloud" + "." + "private" + "." + \
1580+
vlanId + "." + "0" + "." + "1" + "-" + switch_name
1581+
expectedDVPortGroupNames.append(expectedDVPortGroupName)
1582+
1583+
except Exception as e:
1584+
return [FAIL, e]
1585+
return [PASS, expectedDVPortGroupNames]
1586+
1587+
1588+
def verifyVCenterPortGroups(
1589+
api_client,
1590+
vcenter_conn,
1591+
zone_list,
1592+
traffic_types_to_validate):
1593+
1594+
""" Generate expected port groups for given traffic types and
1595+
verify they are present in the vcenter
1596+
1597+
Parameters:
1598+
@api_client: API client of root admin account
1599+
@vcenter_conn: connection object for vcenter used to fetch data
1600+
using vcenterAPI
1601+
@zone_list: List of zones for which port groups are to be verified
1602+
traffic_types: Traffic types (public, guest, management, storage) for
1603+
which verification is to be done
1604+
1605+
Return value:
1606+
[PASS/FAIL, exception message if FAIL else None]
1607+
"""
1608+
try:
1609+
expectedDVPortGroupNames = []
1610+
vcenterPortGroups = []
1611+
config = Configurations.list(
1612+
api_client,
1613+
name="network.throttling.rate"
1614+
)
1615+
networkRate = config[0].value
1616+
switchDict = {}
1617+
for zone in zone_list:
1618+
# Verify that there should be at least one physical
1619+
# network present in zone.
1620+
physicalNetworks = PhysicalNetwork.list(
1621+
api_client,
1622+
zoneid=zone.id
1623+
)
1624+
assert validateList(physicalNetworks)[0] == PASS,\
1625+
"listPhysicalNetworks returned invalid object in response."
1626+
1627+
for physicalNetwork in physicalNetworks:
1628+
trafficTypes = TrafficType.list(
1629+
api_client,
1630+
physicalnetworkid=physicalNetwork.id)
1631+
1632+
for trafficType in traffic_types_to_validate:
1633+
response = analyzeTrafficType(
1634+
trafficTypes, trafficType)
1635+
assert response[0] == PASS, response[1]
1636+
filteredList, switchName, vlanSpecified =\
1637+
response[1], response[2], response[3]
1638+
1639+
if not filteredList:
1640+
continue
1641+
1642+
if switchName not in switchDict:
1643+
dvswitches = vcenter_conn.get_dvswitches(
1644+
name=switchName)
1645+
switchDict[switchName] = dvswitches[0][
1646+
'dvswitch']['portgroupNameList']
1647+
1648+
response = getExpectedPortGroupNames(
1649+
api_client,
1650+
physicalNetwork,
1651+
networkRate,
1652+
switchName,
1653+
trafficTypes,
1654+
switchDict,
1655+
vcenter_conn,
1656+
vlanSpecified,
1657+
trafficType)
1658+
assert response[0] == PASS, response[1]
1659+
dvPortGroups = response[1]
1660+
expectedDVPortGroupNames.extend(dvPortGroups)
1661+
1662+
vcenterPortGroups = list(itertools.chain(*(switchDict.values())))
1663+
1664+
for expectedDVPortGroupName in expectedDVPortGroupNames:
1665+
assert expectedDVPortGroupName in vcenterPortGroups,\
1666+
"Port group %s not present in VCenter DataCenter" %\
1667+
expectedDVPortGroupName
1668+
1669+
except Exception as e:
1670+
return [FAIL, e]
1671+
return [PASS, None]

0 commit comments

Comments
 (0)