# 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. """ NIC tests for VM """ from marvin.codes import FAILED from marvin.cloudstackTestCase import cloudstackTestCase from marvin.lib.base import (Account, ServiceOffering, Network, VirtualMachine, NetworkOffering) from marvin.lib.common import (get_zone, get_suitable_test_template, get_domain) from marvin.lib.utils import validateList from marvin.codes import PASS from nose.plugins.attrib import attr import signal import sys import logging import time import threading from queue import Queue class TestNic(cloudstackTestCase): def setUp(self): self.cleanup = [] self.logger = logging.getLogger('TestNIC') self.stream_handler = logging.StreamHandler() self.logger.setLevel(logging.DEBUG) self.logger.addHandler(self.stream_handler) def signal_handler(signal, frame): self.tearDown() sys.exit(0) # assign the signal handler immediately signal.signal(signal.SIGINT, signal_handler) self.hypervisor = self.testClient.getHypervisorInfo() if self.hypervisor.lower() == "hyperv": self.skipTest("Not supported on Hyper-V") try: self.apiclient = self.testClient.getApiClient() self.dbclient = self.testClient.getDbConnection() self.services = self.testClient.getParsedTestDataConfig() # Get Zone, Domain and templates domain = get_domain(self.apiclient) self.zone = get_zone( self.apiclient, self.testClient.getZoneForTests() ) # if local storage is enabled, alter the offerings to use # localstorage # this step is needed for devcloud if self.zone.localstorageenabled: self.services["service_offerings"][ "tiny"]["storagetype"] = 'local' template = get_suitable_test_template( self.apiclient, self.zone.id, self.services["ostype"], self.hypervisor ) if template == FAILED: assert False, "get_suitable_test_template() failed to return template with description %s" % self.services["ostype"] # Set Zones and disk offerings self.services["small"]["zoneid"] = self.zone.id self.services["small"]["template"] = template.id self.services["iso1"]["zoneid"] = self.zone.id self.services["network"]["zoneid"] = self.zone.id # Create Account, VMs, NAT Rules etc self.account = Account.create( self.apiclient, self.services["account"], domainid=domain.id ) self.cleanup.insert(0, self.account) self.service_offering = ServiceOffering.create( self.apiclient, self.services["service_offerings"]["tiny"] ) self.cleanup.insert(0, self.service_offering) #################### # Network offering self.network_offering = NetworkOffering.create( self.apiclient, self.services["network_offering"], ) self.cleanup.insert(0, self.network_offering) self.network_offering.update( self.apiclient, state='Enabled') # Enable Network offering self.services["network"][ "networkoffering"] = self.network_offering.id self.network_offering_shared = NetworkOffering.create( self.apiclient, self.services["network_offering_shared"], ) self.cleanup.insert(0, self.network_offering_shared) self.network_offering_shared.update( self.apiclient, state='Enabled') # Enable Network offering self.services["network2"][ "networkoffering"] = self.network_offering_shared.id ################ # Test Network self.test_network = Network.create( self.apiclient, self.services["network"], self.account.name, self.account.domainid, ) self.cleanup.insert(0, self.test_network) self.test_network2 = Network.create( self.apiclient, self.services["network2"], self.account.name, self.account.domainid, zoneid=self.services["network"]["zoneid"] ) self.cleanup.insert(0, self.test_network2) except Exception as ex: self.debug("Exception during NIC test SETUP!: " + str(ex)) @attr( tags=[ "devcloud", "smoke", "advanced", "advancedns"], required_hardware="true") def test_01_nic(self): # TODO: SIMENH: add validation """Test to add and update added nic to a virtual machine""" hypervisorIsVmware = False isVmwareToolInstalled = False if self.hypervisor.lower() == "vmware": hypervisorIsVmware = True self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["small"], accountid=self.account.name, domainid=self.account.domainid, serviceofferingid=self.service_offering.id, networkids=[self.test_network.id], mode=self.zone.networktype if hypervisorIsVmware else "default" ) self.cleanup.insert(0, self.virtual_machine) vms = VirtualMachine.list( self.apiclient, id=self.virtual_machine.id ) self.assertEqual( validateList(vms)[0], PASS, "vms list validation failed") vm_response = vms[0] self.assertEqual( len(vm_response.nic), 1, "Verify we only start with one nic" ) self.assertEqual( vm_response.nic[0].isdefault, True, "Verify initial adapter is set to default" ) existing_nic_ip = vm_response.nic[0].ipaddress existing_nic_id = vm_response.nic[0].id self.virtual_machine.add_nic( self.apiclient, self.test_network2.id) list_vm_response = VirtualMachine.list( self.apiclient, id=self.virtual_machine.id ) self.assertEqual( len(list_vm_response[0].nic), 2, "Verify we have 2 NIC's now" ) # If hypervisor is Vmware, then check if # the vmware tools are installed and the process is running # Vmware tools are necessary for remove nic operations (vmware 5.5+) if hypervisorIsVmware: sshClient = self.virtual_machine.get_ssh_client() result = str( sshClient.execute("service vmware-tools status")).lower() self.debug("and result is: %s" % result) if "running" in result: isVmwareToolInstalled = True goForUnplugOperation = True # If Vmware tools are not installed in case of vmware hypervisor # then don't go further for unplug operation (remove nic) as it won't # be supported if hypervisorIsVmware and not isVmwareToolInstalled: goForUnplugOperation = False if goForUnplugOperation: new_nic_id = "" for nc in list_vm_response[0].nic: if nc.ipaddress != existing_nic_ip: new_nic_id = nc.id self.virtual_machine.update_default_nic(self.apiclient, new_nic_id) time.sleep(5) list_vm_response = VirtualMachine.list( self.apiclient, id=self.virtual_machine.id ) # iterate as we don't know for sure what order our NIC's will be # returned to us. for nc in list_vm_response[0].nic: if nc.ipaddress == existing_nic_ip: self.assertEqual( nc.isdefault, False, "Verify initial adapter is NOT set to default" ) else: self.assertEqual( nc.isdefault, True, "Verify second adapter is set to default" ) with self.assertRaises(Exception): self.virtual_machine.remove_nic(self.apiclient, new_nic_id) self.virtual_machine.update_default_nic( self.apiclient, existing_nic_id) time.sleep(5) self.virtual_machine.remove_nic(self.apiclient, new_nic_id) time.sleep(5) list_vm_response = VirtualMachine.list( self.apiclient, id=self.virtual_machine.id ) self.assertEqual( len(list_vm_response[0].nic), 1, "Verify we are back to a signle NIC" ) return def test_02_nic_with_mac(self): """Test to add and update added nic to a virtual machine with specific mac""" hypervisorIsVmware = False isVmwareToolInstalled = False if self.hypervisor.lower() == "vmware": hypervisorIsVmware = True self.virtual_machine2 = VirtualMachine.create( self.apiclient, self.services["small"], accountid=self.account.name, domainid=self.account.domainid, serviceofferingid=self.service_offering.id, networkids=[self.test_network.id], macaddress="aa:bb:cc:dd:ee:ff", mode=self.zone.networktype if hypervisorIsVmware else "default" ) self.cleanup.insert(0, self.virtual_machine2) self.assertEqual(self.virtual_machine2.nic[0].macaddress, "aa:bb:cc:dd:ee:ff", "Mac address not honored") vmdata = self.virtual_machine2.add_nic( self.apiclient, self.test_network2.id, macaddress="ee:ee:dd:cc:bb:aa") found = False for n in vmdata.nic: if n.macaddress == "ee:ee:dd:cc:bb:aa": found = True break self.assertTrue(found, "Nic not successfully added with specified mac address") @attr(tags = ["devcloud", "advanced", "advancedns", "smoke"], required_hardware="true") def test_03_nic_multiple_vmware(self): """Test to adding multiple nics to a VMware VM and restarting VM Refer to CLOUDSTACK-10107 for details, in this test we add 8 nics to a VM and stop, start it to show that VMware VMs are not limited to having up to 7 nics. """ if self.hypervisor.lower() != "vmware": self.skipTest("Skipping test applicable for VMware") network_offering = NetworkOffering.create( self.apiclient, self.services["nw_off_isolated_persistent"] ) self.cleanup.insert(0, network_offering) network_offering.update(self.apiclient, state='Enabled') offering = dict(self.services["network"]) offering["networkoffering"] = network_offering.id networks = [] def createNetwork(idx): offering["name"] = "Test Network%s" % idx network = Network.create( self.apiclient, offering, self.account.name, self.account.domainid, zoneid=self.services["network"]["zoneid"] ) networks.append(network) self.cleanup.insert(0, network) class NetworkMaker(threading.Thread): def __init__(self, queue=None, createNetwork=None): threading.Thread.__init__(self) self.queue = queue self.createNetwork = createNetwork def run(self): while True: idx = self.queue.get() if idx is not None: self.createNetwork(idx) self.queue.task_done() # Start multiple networks tsize = 8 queue = Queue() for _ in range(tsize): worker = NetworkMaker(queue, createNetwork) worker.setDaemon(True) worker.start() for idx in range(tsize): queue.put(idx) queue.join() # Deploy a VM vm = VirtualMachine.create( self.apiclient, self.services["small"], accountid=self.account.name, domainid=self.account.domainid, serviceofferingid=self.service_offering.id, networkids=[networks[0].id], mode=self.zone.networktype ) self.cleanup.insert(0, vm) # Add nics to networks for network in networks[1:]: response = vm.add_nic(self.apiclient, network.id) found = False for nic in response.nic: if nic.networkid == network.id: found = True break self.assertTrue(found, "Nic not successfully added for the specific network") # Stop VM vm.stop(self.apiclient, forced=True) vms = VirtualMachine.list( self.apiclient, id=vm.id ) self.assertEqual( validateList(vms)[0], PASS, "vms list validation failed") vm_response = vms[0] self.assertEqual( vm_response.state, "Stopped", "Verify the VM is stopped" ) # Start VM vm.start(self.apiclient) vms = VirtualMachine.list( self.apiclient, id=vm.id ) self.assertEqual( validateList(vms)[0], PASS, "vms list validation failed") vm_response = vms[0] self.assertEqual( vm_response.state, "Running", "Verify the VM is running" ) self.assertTrue(len(vm_response.nic) == len(networks), "Number of nics on VM not 8") # Validate nics exist on each of the network for network in networks: found = False for nic in vm_response.nic: if nic.networkid == network.id: found = True break self.assertTrue(found, "Nic not found for the specific network") def tearDown(self): try: for obj in self.cleanup: try: obj.delete(self.apiclient) time.sleep(10) except Exception as ex: self.debug( "Error deleting: " + str(obj) + ", exception: " + str(ex)) except Exception as e: self.debug("Warning! Exception in tearDown: %s" % e)