You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ta...@apache.org on 2015/04/03 11:59:40 UTC
git commit: updated refs/heads/master to 799a033
Repository: cloudstack
Updated Branches:
refs/heads/master 3f89cd649 -> 799a03398
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 <ta...@apache.org>
This closes #144
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/799a0339
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/799a0339
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/799a0339
Branch: refs/heads/master
Commit: 799a03398c23090818ae832108a12632a2f33ab3
Parents: 3f89cd6
Author: Gaurav Aradhye <ga...@clogeny.com>
Authored: Fri Apr 3 14:56:42 2015 +0530
Committer: SrikanteswaraRao Talluri <ta...@apache.org>
Committed: Fri Apr 3 15:28:48 2015 +0530
----------------------------------------------------------------------
tools/marvin/marvin/codes.py | 9 ++
tools/marvin/marvin/lib/base.py | 28 ++++
tools/marvin/marvin/lib/common.py | 260 ++++++++++++++++++++++++++++++++-
3 files changed, 293 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/799a0339/tools/marvin/marvin/codes.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/codes.py b/tools/marvin/marvin/codes.py
index 877d686..3f9ee2f 100644
--- a/tools/marvin/marvin/codes.py
+++ b/tools/marvin/marvin/codes.py
@@ -111,6 +111,7 @@ CHILD_DOMAIN_ADMIN="child domain admin"
Network states
'''
ALLOCATED = "Allocated"
+
'''
Storage Tags
'''
@@ -118,3 +119,11 @@ ZONETAG1 = "zwps1"
ZONETAG2 = "zwps2"
CLUSTERTAG1 = "cwps1"
CLUSTERTAG2 = "cwps2"
+
+'''
+Traffic Types
+'''
+PUBLIC_TRAFFIC = "public"
+GUEST_TRAFFIC = "guest"
+MANAGEMENT_TRAFFIC = "management"
+STORAGE_TRAFFIC = "storage"
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/799a0339/tools/marvin/marvin/lib/base.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py
index 91a4f60..44be8e8 100755
--- a/tools/marvin/marvin/lib/base.py
+++ b/tools/marvin/marvin/lib/base.py
@@ -4795,4 +4795,32 @@ class Usage:
[setattr(cmd, k, v) for k, v in kwargs.items()]
return(apiclient.generateUsageRecords(cmd))
+class TrafficType:
+ """Manage different traffic types in the setup"""
+
+ def __init__(self, items):
+ self.__dict__.update(items)
+
+ @classmethod
+ def list(cls, apiclient, **kwargs):
+ """Lists traffic types"""
+
+ cmd = listTrafficTypes.listTrafficTypesCmd()
+ [setattr(cmd, k, v) for k, v in kwargs.items()]
+ return(apiclient.listTrafficTypes(cmd))
+
+class StorageNetworkIpRange:
+ """Manage Storage Network Ip Range"""
+
+ def __init__(self, items):
+ self.__dict__.update(items)
+
+ @classmethod
+ def list(cls, apiclient, **kwargs):
+ """Lists Storage Network IP Ranges"""
+
+ cmd = listStorageNetworkIpRange.listStorageNetworkIpRangeCmd()
+ [setattr(cmd, k, v) for k, v in kwargs.items()]
+ return(apiclient.listStorageNetworkIpRange(cmd))
+
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/799a0339/tools/marvin/marvin/lib/common.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/lib/common.py b/tools/marvin/marvin/lib/common.py
index fdbf153..6efd58b 100644
--- a/tools/marvin/marvin/lib/common.py
+++ b/tools/marvin/marvin/lib/common.py
@@ -61,7 +61,8 @@ from marvin.sshClient import SshClient
from marvin.codes import (PASS, FAILED, ISOLATED_NETWORK, VPC_NETWORK,
BASIC_ZONE, FAIL, NAT_RULE, STATIC_NAT_RULE,
RESOURCE_PRIMARY_STORAGE, RESOURCE_SECONDARY_STORAGE,
- RESOURCE_CPU, RESOURCE_MEMORY)
+ RESOURCE_CPU, RESOURCE_MEMORY, PUBLIC_TRAFFIC,
+ GUEST_TRAFFIC, MANAGEMENT_TRAFFIC, STORAGE_TRAFFIC)
from marvin.lib.utils import (validateList, xsplit, get_process_status)
from marvin.lib.base import (PhysicalNetwork,
PublicIPAddress,
@@ -80,10 +81,13 @@ from marvin.lib.base import (PhysicalNetwork,
Host,
Resources,
Configurations,
- Router)
+ Router,
+ PublicIpRange,
+ StorageNetworkIpRange,
+ TrafficType)
import random
-
-
+import re
+import itertools
# Import System modules
import time
@@ -1417,3 +1421,251 @@ def verifyRouterState(apiclient, routerid, state, listall=True):
exceptionMessage = e
return [exceptionOccured, isRouterInDesiredState, exceptionMessage]
return [exceptionOccured, isRouterInDesiredState, exceptionMessage]
+
+def analyzeTrafficType(trafficTypes, trafficTypeToFilter):
+ """ Analyze traffic types for given type and return
+ switch name and vlan Id from the
+ vmwarenetworklabel string of trafficTypeToFilter
+ """
+
+ try:
+ filteredList = [trafficType for trafficType in trafficTypes
+ if trafficType.traffictype.lower() ==
+ trafficTypeToFilter]
+
+ if not filteredList:
+ return [PASS, filteredList, None, None]
+
+ # Split string with , so as to extract the switch Name and
+ # vlan ID
+ splitString = str(
+ filteredList[0].vmwarenetworklabel).split(",")
+ switchName = splitString[0]
+ vlanSpecified = splitString[1]
+
+ return [PASS, filteredList, switchName, vlanSpecified]
+ except Exception as e:
+ return [FAIL, e, None, None]
+
+
+def getExpectedPortGroupNames(
+ api_client,
+ physical_network,
+ network_rate,
+ switch_name,
+ traffic_types,
+ switch_dict,
+ vcenter_conn,
+ specified_vlan,
+ traffic_type):
+ """ Return names of expected port groups that should be
+ present in vcenter
+
+ Parameters:
+ @physical_network: Physical Network of the @traffic_type
+ @network_rate: as defined by network.throttling.rate
+ @switch_name: Name of the switch used by the traffic in
+ vcenter
+ @traffic_types: List of all traffic types present in the physical
+ network
+ @switch_dict: Dictionary containing switch information in vcenter
+ @vcenter_conn: vcenter connection object used to fetch information
+ from vcenter
+ @specified_vlan: The vlan for @traffic_type
+ @traffic_type: Traffic type for which the port names are to be
+ returned
+
+ Return value:
+ [PASS/FAIL, exception object if FAIL else expected port group names
+ for @traffic_type]
+ """
+
+ try:
+ expectedDVPortGroupNames = []
+
+ if traffic_type == PUBLIC_TRAFFIC:
+ publicIpRanges = PublicIpRange.list(
+ api_client,
+ physicalnetworkid=physical_network.id
+ )
+ if publicIpRanges is not None:
+ for publicIpRange in publicIpRanges:
+ vlanInIpRange = re.findall(
+ '\d+',
+ str(publicIpRange.vlan))
+ if len(vlanInIpRange) > 0:
+ vlanId = vlanInIpRange[0]
+ expectedDVPortGroupName = "cloud" + "." + \
+ PUBLIC_TRAFFIC + "." + vlanId + "." + \
+ network_rate + "." + "1" + "-" + \
+ switch_name
+ expectedDVPortGroupNames.append(
+ expectedDVPortGroupName)
+
+ expectedDVPortGroupName = "cloud" + "." + PUBLIC_TRAFFIC + "." + \
+ vlanId + "." + "0" + "." + "1" + "-" + switch_name
+ expectedDVPortGroupNames.append(expectedDVPortGroupName)
+
+ if traffic_type == GUEST_TRAFFIC:
+
+ networks = Network.list(
+ api_client,
+ physicalnetworkid=physical_network.id,
+ listall=True
+ )
+ if networks is not None:
+ for network in networks:
+ networkVlan = re.findall(
+ '\d+', str(network.vlan))
+ if len(networkVlan) > 0:
+ vlanId = networkVlan[0]
+ expectedDVPortGroupName = "cloud" + "." + GUEST_TRAFFIC + "." + \
+ vlanId + "." + network_rate + "." + "1" + "-" + \
+ switch_name
+ expectedDVPortGroupNames.append(
+ expectedDVPortGroupName)
+
+ if traffic_type == STORAGE_TRAFFIC:
+ vlanId = ""
+ storageIpRanges = StorageNetworkIpRange.list(
+ api_client,
+ zoneid=physical_network.zoneid
+ )
+ if storageIpRanges is not None:
+ for storageIpRange in storageIpRanges:
+ vlanInIpRange = re.findall(
+ '\d+',
+ str(storageIpRange.vlan))
+ if len(vlanInIpRange) > 0:
+ vlanId = vlanInIpRange[0]
+ else:
+ vlanId = "untagged"
+ expectedDVPortGroupName = "cloud" + "." + STORAGE_TRAFFIC + \
+ "." + vlanId + "." + "0" + "." + "1" + "-" + \
+ switch_name
+ expectedDVPortGroupNames.append(
+ expectedDVPortGroupName)
+
+ else:
+ response = analyzeTrafficType(
+ traffic_types, MANAGEMENT_TRAFFIC)
+ assert response[0] == PASS, response[1]
+ filteredList, switchName, vlanSpecified =\
+ response[1], response[2], response[3]
+
+ if not filteredList:
+ raise Exception("No Management traffic present and\
+ Storage traffic does not have any IP range,\
+ Invalid zone setting")
+
+ if switchName not in switch_dict:
+ dvswitches = vcenter_conn.get_dvswitches(
+ name=switchName)
+ switch_dict[switchName] = dvswitches[0][
+ 'dvswitch']['portgroupNameList']
+
+ if vlanSpecified:
+ vlanId = vlanSpecified
+ else:
+ vlanId = "untagged"
+ expectedDVPortGroupName = "cloud" + "." + STORAGE_TRAFFIC + \
+ "." + vlanId + "." + "0" + "." + "1" + "-" + switchName
+ expectedDVPortGroupNames.append(expectedDVPortGroupName)
+
+ if traffic_type == MANAGEMENT_TRAFFIC:
+ vlanId = "untagged"
+ if specified_vlan:
+ vlanId = specified_vlan
+ expectedDVPortGroupName = "cloud" + "." + "private" + "." + \
+ vlanId + "." + "0" + "." + "1" + "-" + switch_name
+ expectedDVPortGroupNames.append(expectedDVPortGroupName)
+
+ except Exception as e:
+ return [FAIL, e]
+ return [PASS, expectedDVPortGroupNames]
+
+
+def verifyVCenterPortGroups(
+ api_client,
+ vcenter_conn,
+ zone_list,
+ traffic_types_to_validate):
+
+ """ Generate expected port groups for given traffic types and
+ verify they are present in the vcenter
+
+ Parameters:
+ @api_client: API client of root admin account
+ @vcenter_conn: connection object for vcenter used to fetch data
+ using vcenterAPI
+ @zone_list: List of zones for which port groups are to be verified
+ traffic_types: Traffic types (public, guest, management, storage) for
+ which verification is to be done
+
+ Return value:
+ [PASS/FAIL, exception message if FAIL else None]
+ """
+ try:
+ expectedDVPortGroupNames = []
+ vcenterPortGroups = []
+ config = Configurations.list(
+ api_client,
+ name="network.throttling.rate"
+ )
+ networkRate = config[0].value
+ switchDict = {}
+ for zone in zone_list:
+ # Verify that there should be at least one physical
+ # network present in zone.
+ physicalNetworks = PhysicalNetwork.list(
+ api_client,
+ zoneid=zone.id
+ )
+ assert validateList(physicalNetworks)[0] == PASS,\
+ "listPhysicalNetworks returned invalid object in response."
+
+ for physicalNetwork in physicalNetworks:
+ trafficTypes = TrafficType.list(
+ api_client,
+ physicalnetworkid=physicalNetwork.id)
+
+ for trafficType in traffic_types_to_validate:
+ response = analyzeTrafficType(
+ trafficTypes, trafficType)
+ assert response[0] == PASS, response[1]
+ filteredList, switchName, vlanSpecified =\
+ response[1], response[2], response[3]
+
+ if not filteredList:
+ continue
+
+ if switchName not in switchDict:
+ dvswitches = vcenter_conn.get_dvswitches(
+ name=switchName)
+ switchDict[switchName] = dvswitches[0][
+ 'dvswitch']['portgroupNameList']
+
+ response = getExpectedPortGroupNames(
+ api_client,
+ physicalNetwork,
+ networkRate,
+ switchName,
+ trafficTypes,
+ switchDict,
+ vcenter_conn,
+ vlanSpecified,
+ trafficType)
+ assert response[0] == PASS, response[1]
+ dvPortGroups = response[1]
+ expectedDVPortGroupNames.extend(dvPortGroups)
+
+ vcenterPortGroups = list(itertools.chain(*(switchDict.values())))
+
+ for expectedDVPortGroupName in expectedDVPortGroupNames:
+ assert expectedDVPortGroupName in vcenterPortGroups,\
+ "Port group %s not present in VCenter DataCenter" %\
+ expectedDVPortGroupName
+
+ except Exception as e:
+ return [FAIL, e]
+ return [PASS, None]