# 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 marvin.cloudstackTestCase import cloudstackTestCase, unittest from marvin.lib.utils import (cleanup_resources, validateList, get_hypervisor_type, get_process_status) from marvin.lib.base import (Account, Cluster, Configurations, Host, VPC, VirtualMachine, Network, Router, ServiceOffering, NetworkOffering) from marvin.lib.common import (get_zone, get_template, verifyNetworkState, wait_for_cleanup, list_routers, list_hosts) from nose.plugins.attrib import attr from marvin.sshClient import SshClient from distutils.util import strtobool from pyVmomi import vim, vmodl from marvin.lib.vcenter import Vcenter import logging logger = logging.getLogger('TestPesistentNetwork') stream_handler = logging.StreamHandler() logger.setLevel(logging.DEBUG) logger.addHandler(stream_handler) class TestL2PersistentNetworks(cloudstackTestCase): @classmethod def setUpClass(cls): cls.testClient = super(TestL2PersistentNetworks, cls).getClsTestClient() cls.api_client = cls.testClient.getApiClient() cls.hypervisor = cls.testClient.getHypervisorInfo() isKVM = cls.hypervisor.lower() in ["kvm"] isOVSEnabled = False hostConfig = cls.config.__dict__["zones"][0].__dict__["pods"][0].__dict__["clusters"][0].__dict__["hosts"][0].__dict__ if isKVM : # Test only if all the hosts use OVS grepCmd = 'grep "network.bridge.type=openvswitch" /etc/cloudstack/agent/agent.properties' hosts = list_hosts(cls.api_client, type='Routing', hypervisor='kvm') for host in hosts : if len(SshClient(host.ipaddress, port=22, user=hostConfig["username"], passwd=hostConfig["password"]).execute(grepCmd)) != 0 : isOVSEnabled = True break if isKVM and isOVSEnabled : cls.skipTest(cls, "KVM with OVS doesn't support persistent networks, skipping") # Fill services from the external config file cls.services = cls.testClient.getParsedTestDataConfig() cls.hostConfig = cls.config.__dict__["zones"][0].__dict__["pods"][0].__dict__["clusters"][0].__dict__["hosts"][ 0].__dict__ # Get Zone and templates cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) cls.template = get_template( cls.api_client, cls.zone.id, cls.services["ostype"] ) cls.services["virtual_machine"]["zoneid"] = cls.zone.id cls.services["virtual_machine"]["template"] = cls.template.id cls.service_offering = ServiceOffering.create( cls.api_client, cls.services["service_offering"] ) cls.l2_persistent_network_offering = cls.create_network_offering("nw_off_L2_persistent") cls.isolated_persistent_network_offering = cls.create_network_offering("nw_off_isolated_persistent") # network will be deleted as part of account cleanup cls._cleanup = [ cls.service_offering, cls.isolated_persistent_network_offering, cls.l2_persistent_network_offering] return @classmethod def tearDownClass(cls): try: # Cleanup resources used cleanup_resources(cls.api_client, cls._cleanup) except Exception as e: raise Exception("Warning: Exception during cleanup : %s" % e) return def setUp(self): self.apiclient = self.testClient.getApiClient() self.dbclient = self.testClient.getDbConnection() self.hypervisor = self.testClient.getHypervisorInfo() self.cleanup = [] return def tearDown(self): try: # Clean up, terminate the resources created cleanup_resources(self.apiclient, self.cleanup) self.cleanup[:] = [] except Exception as e: raise Exception("Warning: Exception during cleanup : %s" % e) return @classmethod def is_ssh_enabled(cls): conf = Configurations.list(cls.apiclient, name="kvm.ssh.to.agent") if not conf: return False else: return bool(strtobool(conf[0].value)) if conf[0].value else False @classmethod def create_network_offering(cls, network_offering_type): network_offering = NetworkOffering.create( cls.api_client, cls.services[network_offering_type], conservemode=False ) # Update network offering state from disabled to enabled. NetworkOffering.update( network_offering, cls.api_client, id=network_offering.id, state="enabled") return network_offering def get_ssh_client(self, ip, username, password, retries=10): """ Setup ssh client connection and return connection """ try: ssh_client = SshClient(ip, 22, username, password, retries) except Exception as e: raise unittest.SkipTest("Unable to create ssh connection: " % e) self.assertIsNotNone( ssh_client, "Failed to setup ssh connection to ip=%s" % ip) return ssh_client def list_all_hosts_in_zone(self, zone_id): hosts = Host.list( self.apiclient, type='Routing', resourcestate='Enabled', state='Up', zoneid=zone_id ) return hosts ''' Verifies creation of bridge on KVM host ''' def verify_bridge_creation(self, host, vlan_id): username = self.hostConfig["username"] password = self.hostConfig["password"] try: ssh_client = self.get_ssh_client(host.ipaddress, username, password) res = ssh_client.execute("ip addr | grep breth1-" + str(vlan_id) + " > /dev/null 2>&1; echo $?") return res[0] except Exception as e: self.fail(e) ''' Gets all port groups on the host ''' def capture_host_portgroups(self, host): host_portgroups = [] for portgroup in host.config.network.portgroup: host_portgroups.append(portgroup.spec.name) return host_portgroups ''' Fetches port group names based on VMware switch type - Distributed Virtual Switch(DVS) and Standard Virtual Switch(SVS) ''' def get_port_group_name(self, switch_type, vlan_id, network_rate): if switch_type == 'DVS': return 'cloud.guest.' + str(vlan_id) + '.' + str(network_rate) + '.1-dvSwitch1' elif switch_type == 'SVS': return 'cloud.guest.' + str(vlan_id) + '.' + str(network_rate) + '.1-vSwitch1' else: return None ''' Verifies creation of port group on the Distributed vSwitch or a host in a cluster connected to a Standard vSwitch ''' def verify_port_group_creation(self, vlan_id): config = self.get_vmware_dc_config(self.zone.id) vc_object = Vcenter(config[0][0], config[0][1], 'P@ssword123') dvs = vc_object.get_dvswitches() port_group_present = False if dvs is not None: port_group_name = self.get_port_group_name('DVS', vlan_id, self.isolated_persistent_network_offering.networkrate) port_group_present = port_group_name in dvs[0]['dvswitch']['portgroupNameList'] else: port_group_name = self.get_port_group_name('SVS', vlan_id, self.isolated_persistent_network_offering.networkrate) hosts = vc_object._get_obj([vim.HostSystem]) host = hosts[0]['host'] host_pg = self.capture_host_portgroups(host) port_group_present = port_group_name in host_pg return port_group_present ''' Fetch vmware datacenter login details ''' def get_vmware_dc_config(self, zone_id): zid = self.dbclient.execute("select id from data_center where uuid='%s';" % zone_id) vmware_dc_id = self.dbclient.execute( "select vmware_data_center_id from vmware_data_center_zone_map where zone_id='%s';" % zid[0]) vmware_dc_config = self.dbclient.execute( "select vcenter_host, username, password from vmware_data_center where id = '%s';" % vmware_dc_id[0]) return vmware_dc_config ''' Verify VLAN creation on specific host in a cluster ''' def verify_vlan_network_creation(self, host, vlan_id): username = self.hostConfig["username"] password = self.hostConfig["password"] try: ssh_client = self.get_ssh_client(host.ipaddress, username, password) res = ssh_client.execute( "xe vlan-list | grep -x \"^\s*tag ( RO): \"" + str(vlan_id) + "> /dev/null 2>&1; echo $?") return res[0] except Exception as e: self.fail(e) def verify_network_setup_on_host_per_cluster(self, hypervisor, vlan_id): clusters = Cluster.list( self.apiclient, zoneid=self.zone.id, allocationstate="Enabled", listall=True ) for cluster in clusters: hosts = Host.list(self.apiclient, clusterid=cluster.id, type="Routing", state="Up", resourcestate="Enabled") host = hosts[0] if hypervisor == "xenserver": result = self.verify_vlan_network_creation(host, vlan_id) self.assertEqual( int(result), 0, "Failed to find vlan on host: " + host.name + " in cluster: " + cluster.name) if hypervisor == "vmware": result = self.verify_port_group_creation(vlan_id) self.assertEqual( result, True, "Failed to find port group on hosts of cluster: " + cluster.name) ''' This test verifies that on creation of an Isolated network with network offering with isPersistent flag set to true the corresponding network resources are created without having to deploy a VM - VR created ''' @attr(tags=["advanced", "isolated", "persistent", "network"], required_hardware="false") def test_01_isolated_persistent_network(self): network = Network.create( self.apiclient, self.services["isolated_network"], networkofferingid=self.isolated_persistent_network_offering.id, zoneid=self.zone.id) self.cleanup.append(network) networkVlan = network.vlan response = verifyNetworkState( self.apiclient, network.id, "implemented") exceptionOccurred = response[0] isNetworkInDesiredState = response[1] exceptionMessage = response[2] if (exceptionOccurred or (not isNetworkInDesiredState)): self.fail(exceptionMessage) self.assertIsNotNone( networkVlan, "vlan must not be null for persistent network") router = Router.list(self.apiclient, networkid=network.id)[0] router_host_id = router.hostid host = Host.list(self.apiclient, id=router_host_id)[0] if host.hypervisor.lower() in "kvm": result = self.verify_bridge_creation(host, networkVlan) self.assertEqual( int(result), 0, "Failed to find bridge on the breth1$-{networkVlan}") elif host.hypervisor.lower() in ["xenserver", "vmware"]: self.verify_network_setup_on_host_per_cluster(host.hypervisor.lower(), networkVlan) ''' This test verifies that on creation of an L2 network with network offering with isPersistent flag set to true the corresponding network resources are created without having to deploy a VM - VR created ''' @attr(tags=["advanced", "l2", "persistent", "network"], required_hardware="false") def test_02_L2_persistent_network(self): network_vlan = 90 network = Network.create( self.apiclient, self.services["l2_network"], networkofferingid=self.l2_persistent_network_offering.id, zoneid=self.zone.id, vlan=network_vlan) self.cleanup.append(network) response = verifyNetworkState( self.apiclient, network.id, "implemented") exceptionOccurred = response[0] isNetworkInDesiredState = response[1] exceptionMessage = response[2] if (exceptionOccurred or (not isNetworkInDesiredState)): self.fail(exceptionMessage) self.assertIsNotNone( network_vlan, "vlan must not be null for persistent network") self.validate_persistent_network_resources_created_on_host(network_vlan) @attr(tags=["advanced", "l2", "persistent", "network"], required_hardware="false") def test_03_deploy_and_destroy_VM_and_verify_network_resources_persist(self): network_vlan = 99 network = Network.create( self.apiclient, self.services["l2_network"], networkofferingid=self.l2_persistent_network_offering.id, zoneid=self.zone.id, vlan=network_vlan) self.cleanup.append(network) response = verifyNetworkState( self.apiclient, network.id, "implemented") logger.debug(response) exceptionOccurred = response[0] isNetworkInDesiredState = response[1] exceptionMessage = response[2] if (exceptionOccurred or (not isNetworkInDesiredState)): self.fail(exceptionMessage) self.assertIsNotNone( network_vlan, "vlan must not be null for persistent network") try: virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], networkids=[ network.id], serviceofferingid=self.service_offering.id) VirtualMachine.delete(virtual_machine, self.apiclient, expunge=True) self.validate_persistent_network_resources_created_on_host(network_vlan) except Exception as e: self.fail("Exception occurred: %s" % e) return def validate_persistent_network_resources_created_on_host(self, network_vlan): hosts = self.list_all_hosts_in_zone(self.zone.id) if self.hypervisor.lower() in "kvm": for host in hosts: result = self.verify_bridge_creation(host, network_vlan) self.assertEqual( int(result), 0, "Failed to find bridge on the breth1-" + str(network_vlan)) elif self.hypervisor.lower() in ["xenserver", "vmware"]: self.verify_network_setup_on_host_per_cluster(self.hypervisor.lower(), network_vlan)