mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-11-04 00:02:37 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			561 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			561 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# 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.
 | 
						|
""" BVT tests for Virtual Machine additional configuration
 | 
						|
"""
 | 
						|
# Import System modules
 | 
						|
import urllib.request, urllib.parse, urllib.error
 | 
						|
import xml.etree.ElementTree as ET
 | 
						|
 | 
						|
from lxml import etree
 | 
						|
from marvin.cloudstackAPI import (updateVirtualMachine,
 | 
						|
                                  deployVirtualMachine,
 | 
						|
                                  destroyVirtualMachine,
 | 
						|
                                  stopVirtualMachine,
 | 
						|
                                  startVirtualMachine,
 | 
						|
                                  updateConfiguration,
 | 
						|
                                  listVirtualMachines)
 | 
						|
# Import Local Modules
 | 
						|
from marvin.cloudstackTestCase import cloudstackTestCase
 | 
						|
from marvin.lib.base import (Account,
 | 
						|
                             ServiceOffering,
 | 
						|
                             Host)
 | 
						|
from marvin.lib.common import (get_domain,
 | 
						|
                               get_zone,
 | 
						|
                               get_template,
 | 
						|
                               list_hosts)
 | 
						|
from marvin.lib.utils import *
 | 
						|
from nose.plugins.attrib import attr
 | 
						|
 | 
						|
class TestAddConfigtoDeployVM(cloudstackTestCase):
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def setUpClass(cls):
 | 
						|
        testClient = super(TestAddConfigtoDeployVM, cls).getClsTestClient()
 | 
						|
        cls.apiclient = testClient.getApiClient()
 | 
						|
        cls.services = testClient.getParsedTestDataConfig()
 | 
						|
 | 
						|
        # Get Zone, Domain and templates
 | 
						|
        cls.domain = get_domain(cls.apiclient)
 | 
						|
        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
 | 
						|
        cls.hypervisor = testClient.getHypervisorInfo()
 | 
						|
        cls.services['mode'] = cls.zone.networktype
 | 
						|
        cls.hostConfig = cls.config.__dict__["zones"][0].__dict__["pods"][0].__dict__["clusters"][0].__dict__["hosts"][
 | 
						|
            0].__dict__
 | 
						|
 | 
						|
        # Set Zones and disk offerings
 | 
						|
        cls.services["small"]["zoneid"] = cls.zone.id
 | 
						|
 | 
						|
        cls.services["iso1"]["zoneid"] = cls.zone.id
 | 
						|
 | 
						|
        cls.services["virtual_machine"]["zoneid"] = cls.zone.id
 | 
						|
 | 
						|
        cls._cleanup = []
 | 
						|
        # Create an account, network, and IP addresses
 | 
						|
        cls.account = Account.create(
 | 
						|
            cls.apiclient,
 | 
						|
            cls.services["account"],
 | 
						|
            domainid=cls.domain.id
 | 
						|
        )
 | 
						|
        cls._cleanup.append(cls.account)
 | 
						|
        cls.service_offering = ServiceOffering.create(
 | 
						|
            cls.apiclient,
 | 
						|
            cls.services["service_offerings"]["small"]
 | 
						|
        )
 | 
						|
        cls._cleanup.append(cls.service_offering)
 | 
						|
 | 
						|
        cls.hosts_hugepages = cls.set_hosts_hugepages()
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def tearDownClass(cls):
 | 
						|
        cls.reset_hosts_hugepages()
 | 
						|
        super(TestAddConfigtoDeployVM, cls).tearDownClass()
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def set_hosts_hugepages(cls):
 | 
						|
        hosts_hugepages = []
 | 
						|
        listHost = Host.list(
 | 
						|
               cls.apiclient,
 | 
						|
               type='Routing',
 | 
						|
               zoneid=cls.zone.id
 | 
						|
           )
 | 
						|
        for host in listHost:
 | 
						|
            if host.hypervisor.lower() == 'kvm':
 | 
						|
                sshClient = SshClient(host.ipaddress, port=22, user=cls.hostConfig["username"], passwd=cls.hostConfig["password"])
 | 
						|
                result = sshClient.execute("sysctl -n vm.nr_hugepages")
 | 
						|
                sshClient.execute("sysctl -w vm.nr_hugepages=1024")
 | 
						|
                if result and len(result) > 0:
 | 
						|
                    hosts_hugepages.append({ "ipaddress": host.ipaddress, "vm.nr_hugepages": result[0].strip()})
 | 
						|
        return hosts_hugepages
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def reset_hosts_hugepages(cls):
 | 
						|
        for host in cls.hosts_hugepages:
 | 
						|
            sshClient = SshClient(host["ipaddress"], port=22, user=cls.hostConfig["username"], passwd=cls.hostConfig["password"])
 | 
						|
            sshClient.execute("sysctl -w vm.nr_hugepages=%s" % host["vm.nr_hugepages"])
 | 
						|
 | 
						|
    def setUp(self):
 | 
						|
        self.apiclient = self.testClient.getApiClient()
 | 
						|
        self.hypervisor = self.testClient.getHypervisorInfo()
 | 
						|
        self.dbclient = self.testClient.getDbConnection()
 | 
						|
 | 
						|
        """
 | 
						|
        Set EnableAdditionalData to true
 | 
						|
        """
 | 
						|
        updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
 | 
						|
        updateConfigurationCmd.name = "enable.additional.vm.configuration"
 | 
						|
        updateConfigurationCmd.value = "true"
 | 
						|
        updateConfigurationCmd.scopename = "account"
 | 
						|
        updateConfigurationResponse = self.apiclient.updateConfiguration(updateConfigurationCmd)
 | 
						|
        self.debug("updated the parameter %s with value %s" % (
 | 
						|
            updateConfigurationResponse.name, updateConfigurationResponse.value))
 | 
						|
 | 
						|
    # Ste Global Config value
 | 
						|
    def add_global_config(self, name, value):
 | 
						|
        self.apiclient = self.testClient.getApiClient()
 | 
						|
        self.hypervisor = self.testClient.getHypervisorInfo()
 | 
						|
        self.dbclient = self.testClient.getDbConnection()
 | 
						|
 | 
						|
        cmd = updateConfiguration.updateConfigurationCmd()
 | 
						|
        cmd.name = name
 | 
						|
        cmd.value = value
 | 
						|
        return self.apiclient.updateConfiguration(cmd)
 | 
						|
 | 
						|
    # Compare XML Element objects
 | 
						|
    def elements_equal(self, e1, e2):
 | 
						|
        if e1.tag != e2.tag:
 | 
						|
            return False
 | 
						|
        if e1.attrib != e2.attrib:
 | 
						|
            return False
 | 
						|
        if len(e1) != len(e2):
 | 
						|
            return False
 | 
						|
        return all(self.elements_equal(c1, c2) for c1, c2 in zip(e1, e2))
 | 
						|
 | 
						|
    def destroy_vm(self, vm_id):
 | 
						|
        cmd = destroyVirtualMachine.destroyVirtualMachineCmd()
 | 
						|
        cmd.expunge = True
 | 
						|
        cmd.id = vm_id
 | 
						|
        return self.apiclient.destroyVirtualMachine(cmd)
 | 
						|
 | 
						|
    def deploy_vm(self, hypervisor, extra_config=None):
 | 
						|
        cmd = deployVirtualMachine.deployVirtualMachineCmd()
 | 
						|
        if extra_config is not None:
 | 
						|
            cmd.extraconfig = extra_config
 | 
						|
 | 
						|
        template = get_template(
 | 
						|
            self.apiclient,
 | 
						|
            self.zone.id,
 | 
						|
            hypervisor=hypervisor
 | 
						|
        )
 | 
						|
        cmd.zoneid = self.zone.id
 | 
						|
        cmd.templateid = template.id
 | 
						|
        cmd.serviceofferingid = self.service_offering.id
 | 
						|
        return self.apiclient.deployVirtualMachine(cmd)
 | 
						|
 | 
						|
    def list_vm(self):
 | 
						|
        cmd = listVirtualMachines.listVirtualMachinesCmd()
 | 
						|
        cmd.hypervisor = self.hypervisor
 | 
						|
        return self.apiclient.listVirtualMachines(cmd)[0]
 | 
						|
 | 
						|
    def update_vm(self, id, extra_config):
 | 
						|
        cmd = updateVirtualMachine.updateVirtualMachineCmd()
 | 
						|
        cmd.id = id
 | 
						|
        cmd.extraconfig = extra_config
 | 
						|
        return self.apiclient.updateVirtualMachine(cmd)
 | 
						|
 | 
						|
    def stop_vm(self, id):
 | 
						|
        cmd = stopVirtualMachine.stopVirtualMachineCmd()
 | 
						|
        cmd.id = id
 | 
						|
        return self.apiclient.stopVirtualMachine(cmd)
 | 
						|
 | 
						|
    def start_vm(self, id):
 | 
						|
        cmd = startVirtualMachine.startVirtualMachineCmd()
 | 
						|
        cmd.id = id
 | 
						|
        return self.apiclient.startVirtualMachine(cmd)
 | 
						|
 | 
						|
    # Parse extraconfig for config with that returned by xe vm-param-get ...
 | 
						|
    def get_xen_param_values(self, config):
 | 
						|
        equal_sign_index = config.index("=")
 | 
						|
        cmd_option = config[:equal_sign_index]
 | 
						|
        cmd_value = config[equal_sign_index + 1:]
 | 
						|
        return cmd_option, cmd_value
 | 
						|
 | 
						|
    # Format vm config such that it equals the one from vmx file
 | 
						|
    def prepare_vmware_config(self, config):
 | 
						|
        equal_sign_index = config.index("=")
 | 
						|
        cmd_option = config[:equal_sign_index]
 | 
						|
        cmd_value = config[equal_sign_index + 1:]
 | 
						|
        return cmd_option + ' = '  '"{}"'.format(cmd_value)
 | 
						|
 | 
						|
    # Get vm uuid from xenserver host
 | 
						|
    def get_vm_uuid(self, instance_name, ssh_client):
 | 
						|
        cmd = 'xe vm-list name-label={} params=uuid '.format(instance_name)
 | 
						|
        result = ssh_client.execute(cmd)
 | 
						|
        uuid_str = result[0]
 | 
						|
        i = uuid_str.index(":")
 | 
						|
        return uuid_str[i + 1:].strip()
 | 
						|
 | 
						|
    @attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="true")
 | 
						|
    def test_01_deploy_vm_with_extraconfig_throws_exception_kvm(self):
 | 
						|
        '''
 | 
						|
        Test that extra config is not added when element tag is not added on the allowed list global config on KVM hosts
 | 
						|
        '''
 | 
						|
 | 
						|
        hypervisor = self.hypervisor.lower()
 | 
						|
        if hypervisor != 'kvm':
 | 
						|
            raise self.skipTest("Skipping test case for non-kvm hypervisor")
 | 
						|
 | 
						|
        '''
 | 
						|
        The following extraconfig is required for enabling hugepages on kvm
 | 
						|
        <memoryBacking>
 | 
						|
            <hugepages/>
 | 
						|
        </memoryBacking>
 | 
						|
        url encoded extra_config = '%3CmemoryBacking%3E%0D%0A++%3Chugepages%2F%3E%0D%0A%3C%2FmemoryBacking%3E'
 | 
						|
        '''
 | 
						|
        extraconfig = "%3CmemoryBacking%3E%0D%0A++%3Chugepages%2F%3E%0D%0A%3C%2FmemoryBacking%3E"
 | 
						|
 | 
						|
        try:
 | 
						|
            # Clear KVM allow list to show that code throws exception when command is not included in the list
 | 
						|
            name = 'allow.additional.vm.configuration.list.kvm'
 | 
						|
 | 
						|
            self.add_global_config(name, "")
 | 
						|
            self.assertRaises(Exception,
 | 
						|
                              self.deploy_vm(hypervisor, extraconfig),
 | 
						|
                              "Exception was not thrown, check kvm global configuration")
 | 
						|
        except Exception as e:
 | 
						|
            logging.debug(e)
 | 
						|
        finally:
 | 
						|
            self.destroy_vm(self.list_vm().id)
 | 
						|
 | 
						|
    @attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="true")
 | 
						|
    def test_02_deploy_vm_with_extraconfig_kvm(self):
 | 
						|
        '''
 | 
						|
        Test that extra config is added on KVM hosts
 | 
						|
        '''
 | 
						|
 | 
						|
        hypervisor = self.hypervisor.lower()
 | 
						|
        if hypervisor != 'kvm':
 | 
						|
            raise self.skipTest("Skipping test case for non-kvm hypervisor")
 | 
						|
 | 
						|
        name = 'allow.additional.vm.configuration.list.kvm'
 | 
						|
        value = 'memoryBacking, hugepages, unsedConfigKey'
 | 
						|
 | 
						|
        add_config_response = self.add_global_config(name, value)
 | 
						|
 | 
						|
        if add_config_response.name:
 | 
						|
            try:
 | 
						|
                '''
 | 
						|
                The following extraconfig is required for enabling hugepages on kvm
 | 
						|
                <memoryBacking>
 | 
						|
                    <hugepages/>
 | 
						|
                </memoryBacking>
 | 
						|
                url encoded extra_config = '%3CmemoryBacking%3E%0D%0A++%3Chugepages%2F%3E%0D%0A%3C%2FmemoryBacking%3E'
 | 
						|
                '''
 | 
						|
                extraconfig = "%3CmemoryBacking%3E%0D%0A++%3Chugepages%2F%3E%0D%0A%3C%2FmemoryBacking%3E"
 | 
						|
 | 
						|
                response = self.deploy_vm(hypervisor, extraconfig)
 | 
						|
 | 
						|
                host_id = response.hostid
 | 
						|
                host = list_hosts(
 | 
						|
                    self.apiclient,
 | 
						|
                    id=host_id,
 | 
						|
                    hypervisor=hypervisor)
 | 
						|
 | 
						|
                instance_name = response.instancename
 | 
						|
                host_ipaddress = host[0].ipaddress
 | 
						|
 | 
						|
                ssh_client = SshClient(host_ipaddress, port=22,
 | 
						|
                                       user=self.hostConfig['username'],
 | 
						|
                                       passwd=self.hostConfig['password'])
 | 
						|
                virsh_cmd = 'virsh dumpxml %s' % instance_name
 | 
						|
                xml_res = ssh_client.execute(virsh_cmd)
 | 
						|
                xml_as_str = ''.join(xml_res)
 | 
						|
 | 
						|
                extraconfig_decoded_xml = '<config>' + urllib.parse.unquote(extraconfig) + '</config>'
 | 
						|
 | 
						|
                # Root XML Elements
 | 
						|
                parser = etree.XMLParser(remove_blank_text=True)
 | 
						|
                domain_xml_root = ET.fromstring(xml_as_str, parser=parser)
 | 
						|
                decoded_xml_root = ET.fromstring(extraconfig_decoded_xml, parser=parser)
 | 
						|
                for child in decoded_xml_root:
 | 
						|
                    find_element_in_domain_xml = domain_xml_root.find(child.tag)
 | 
						|
 | 
						|
                    # Fail if extra config is not found in domain xml
 | 
						|
                    self.assertNotEqual(
 | 
						|
                        0,
 | 
						|
                        len(find_element_in_domain_xml),
 | 
						|
                        'Element tag from extra config not added to VM'
 | 
						|
                    )
 | 
						|
 | 
						|
                    # Compare found XML node with extra config node
 | 
						|
                    is_a_match = self.elements_equal(child, find_element_in_domain_xml)
 | 
						|
                    self.assertEqual(
 | 
						|
                        True,
 | 
						|
                        is_a_match,
 | 
						|
                        'The element from tags from extra config do not match with those found in domain xml'
 | 
						|
                    )
 | 
						|
            finally:
 | 
						|
                self.destroy_vm(response.id)
 | 
						|
                self.add_global_config(name, "")
 | 
						|
 | 
						|
    @attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="true")
 | 
						|
    def test_03_update_vm_with_extraconfig_kvm(self):
 | 
						|
        '''
 | 
						|
        Test that extra config is added on KVM hosts
 | 
						|
        '''
 | 
						|
 | 
						|
        hypervisor = self.hypervisor.lower()
 | 
						|
        if hypervisor != 'kvm':
 | 
						|
            raise self.skipTest("Skipping test case for non-kvm hypervisor")
 | 
						|
 | 
						|
        name = 'allow.additional.vm.configuration.list.kvm'
 | 
						|
        value = 'memoryBacking, hugepages'
 | 
						|
 | 
						|
        add_config_response = self.add_global_config(name, value)
 | 
						|
 | 
						|
        if add_config_response.name:
 | 
						|
            try:
 | 
						|
                '''
 | 
						|
                The following extraconfig is required for enabling hugepages on kvm
 | 
						|
                <memoryBacking>
 | 
						|
                    <hugepages/>
 | 
						|
                </memoryBacking>
 | 
						|
                url encoded extra_config = '%3CmemoryBacking%3E%0D%0A++%3Chugepages%2F%3E%0D%0A%3C%2FmemoryBacking%3E'
 | 
						|
                '''
 | 
						|
                extraconfig = "%3CmemoryBacking%3E%0D%0A++%3Chugepages%2F%3E%0D%0A%3C%2FmemoryBacking%3E"
 | 
						|
 | 
						|
                response = self.deploy_vm(hypervisor)
 | 
						|
                vm_id = response.id
 | 
						|
 | 
						|
                '''
 | 
						|
                For updateVirtualMachineCmd, the VM must be stopped and restarted for changes to take effect
 | 
						|
                '''
 | 
						|
                self.stop_vm(vm_id)
 | 
						|
                self.update_vm(vm_id, extraconfig)
 | 
						|
                start_resp = self.start_vm(vm_id)
 | 
						|
 | 
						|
                host_id = start_resp.hostid
 | 
						|
                host = list_hosts(
 | 
						|
                    self.apiclient,
 | 
						|
                    id=host_id,
 | 
						|
                    hypervisor=hypervisor)
 | 
						|
 | 
						|
                instance_name = response.instancename
 | 
						|
                host_ipaddress = host[0].ipaddress
 | 
						|
 | 
						|
                ssh_client = SshClient(host_ipaddress, port=22,
 | 
						|
                                       user=self.hostConfig['username'],
 | 
						|
                                       passwd=self.hostConfig['password'])
 | 
						|
                virsh_cmd = 'virsh dumpxml %s' % instance_name
 | 
						|
                xml_res = ssh_client.execute(virsh_cmd)
 | 
						|
                xml_as_str = ''.join(xml_res)
 | 
						|
 | 
						|
                extraconfig_decoded_xml = '<config>' + urllib.parse.unquote(extraconfig) + '</config>'
 | 
						|
 | 
						|
                # Root XML Elements
 | 
						|
                parser = etree.XMLParser(remove_blank_text=True)
 | 
						|
                domain_xml_root = ET.fromstring(xml_as_str, parser=parser)
 | 
						|
                decoded_xml_root = ET.fromstring(extraconfig_decoded_xml, parser=parser)
 | 
						|
                for child in decoded_xml_root:
 | 
						|
                    find_element_in_domain_xml = domain_xml_root.find(child.tag)
 | 
						|
 | 
						|
                    # Fail if extra config is not found in domain xml
 | 
						|
                    self.assertNotEqual(
 | 
						|
                        0,
 | 
						|
                        len(find_element_in_domain_xml),
 | 
						|
                        'Element tag from extra config not added to VM'
 | 
						|
                    )
 | 
						|
 | 
						|
                    # Compare found XML node with extra config node
 | 
						|
                    is_a_match = self.elements_equal(child, find_element_in_domain_xml)
 | 
						|
                    self.assertEqual(
 | 
						|
                        True,
 | 
						|
                        is_a_match,
 | 
						|
                        'The element from tags from extra config do not match with those found in domain xml'
 | 
						|
                    )
 | 
						|
            finally:
 | 
						|
                self.destroy_vm(vm_id)
 | 
						|
                self.add_global_config(name, "")
 | 
						|
 | 
						|
    @attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="true")
 | 
						|
    def test_04_deploy_vm_with_extraconfig_throws_exception_vmware(self):
 | 
						|
        '''
 | 
						|
        Test that extra config is not added when configuration key is not added on the allowed list global config for VMWARE hosts
 | 
						|
        '''
 | 
						|
 | 
						|
        hypervisor = self.hypervisor.lower()
 | 
						|
        if hypervisor != 'vmware':
 | 
						|
            raise self.skipTest("Skipping test case for non-vmware hypervisor")
 | 
						|
 | 
						|
        '''
 | 
						|
        The following extra configuration is used to set Hyper-V instance to run on ESXi host
 | 
						|
        hypervisor.cpuid.v0 = FALSE
 | 
						|
        '''
 | 
						|
        extraconfig = 'hypervisor.cpuid.v0%3DFALSE'
 | 
						|
 | 
						|
        try:
 | 
						|
            # Clear VMWARE allow list to show that code throws exception when command is not included in the list
 | 
						|
            name = 'allow.additional.vm.configuration.list.vmware'
 | 
						|
 | 
						|
            self.add_global_config(name, "")
 | 
						|
            self.assertRaises(Exception,
 | 
						|
                              self.deploy_vm(hypervisor, extraconfig),
 | 
						|
                              "Exception was not thrown, check VMWARE global configuration")
 | 
						|
        except Exception as e:
 | 
						|
            logging.debug(e)
 | 
						|
        finally:
 | 
						|
            self.destroy_vm(self.list_vm().id)
 | 
						|
 | 
						|
    @attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="true")
 | 
						|
    def test_05_deploy_vm_with_extraconfig_vmware(self):
 | 
						|
        '''
 | 
						|
        Test that extra config is added on VMware hosts
 | 
						|
        '''
 | 
						|
        hypervisor = self.hypervisor.lower()
 | 
						|
        if hypervisor != 'vmware':
 | 
						|
            raise self.skipTest("Skipping test case for non-vmware hypervisor")
 | 
						|
 | 
						|
        name = 'allow.additional.vm.configuration.list.vmware'
 | 
						|
        value = 'hypervisor.cpuid.v0'
 | 
						|
 | 
						|
        add_config_response = self.add_global_config(name, value)
 | 
						|
 | 
						|
        if add_config_response.name:
 | 
						|
 | 
						|
            '''
 | 
						|
            The following extra configuration is used to set Hyper-V instance to run on ESXi host
 | 
						|
            hypervisor.cpuid.v0 = FALSE
 | 
						|
            '''
 | 
						|
            extraconfig = 'hypervisor.cpuid.v0%3DFALSE'
 | 
						|
            try:
 | 
						|
                response = self.deploy_vm(hypervisor, extraconfig)
 | 
						|
                host_id = response.hostid
 | 
						|
                host = list_hosts(
 | 
						|
                    self.apiclient,
 | 
						|
                    id=host_id)
 | 
						|
 | 
						|
                instance_name = response.instancename
 | 
						|
                host_ipaddress = host[0].ipaddress
 | 
						|
 | 
						|
                ssh_client = SshClient(host_ipaddress, port=22,
 | 
						|
                                       user=self.hostConfig['username'],
 | 
						|
                                       passwd=self.hostConfig['password'])
 | 
						|
 | 
						|
                extraconfig_decoded = urllib.parse.unquote(extraconfig)
 | 
						|
                config_arr = extraconfig_decoded.splitlines()
 | 
						|
 | 
						|
                for config in config_arr:
 | 
						|
                    vmx_config = self.prepare_vmware_config(config)
 | 
						|
                    vmx_file_name = "\"$(esxcli vm process list | grep %s | tail -1 | awk '{print $3}')\"" % instance_name
 | 
						|
                    # parse vm instance vmx file to see if extraconfig has been added
 | 
						|
                    grep_config = "cat %s | grep -w '%s'" % (vmx_file_name, vmx_config)
 | 
						|
                    result = ssh_client.execute(grep_config)
 | 
						|
                    # Match exact configuration from vmx file, return empty result array if configuration is not found
 | 
						|
                    self.assertNotEqual(
 | 
						|
                        0,
 | 
						|
                        len(result),
 | 
						|
                        'Extra  configuration not found in instance vmx file'
 | 
						|
                    )
 | 
						|
            finally:
 | 
						|
                self.destroy_vm(response.id)
 | 
						|
                self.add_global_config(name, "")
 | 
						|
 | 
						|
    @attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="true")
 | 
						|
    def test_06_deploy_vm_with_extraconfig_throws_exception_xenserver(self):
 | 
						|
        '''
 | 
						|
        Test that extra config is not added when configuration key is not added on the allowed list global config for XenServer hosts
 | 
						|
        '''
 | 
						|
 | 
						|
        hypervisor = self.hypervisor.lower()
 | 
						|
        if hypervisor != 'xenserver':
 | 
						|
            raise self.skipTest("Skipping test case for non-xenserver hypervisor")
 | 
						|
 | 
						|
        '''
 | 
						|
        Following commands are used to convert a VM from HVM to PV and set using vm-param-set
 | 
						|
        HVM-boot-policy=
 | 
						|
        PV-bootloader=pygrub
 | 
						|
        PV-args=hvc0
 | 
						|
        '''
 | 
						|
 | 
						|
        extraconfig = 'HVM-boot-policy%3D%0APV-bootloader%3Dpygrub%0APV-args%3Dhvc0'
 | 
						|
 | 
						|
        try:
 | 
						|
            # Clear VMWARE allow list to show that code throws exception when command is not included in the list
 | 
						|
            name = 'allow.additional.vm.configuration.list.xenserver'
 | 
						|
 | 
						|
            self.add_global_config(name, "")
 | 
						|
            self.assertRaises(Exception,
 | 
						|
                              self.deploy_vm(hypervisor, extraconfig),
 | 
						|
                              "Exception was not thrown, check XenServer global configuration")
 | 
						|
 | 
						|
        except Exception as e:
 | 
						|
            logging.debug(e)
 | 
						|
        finally:
 | 
						|
            self.destroy_vm(self.list_vm().id)
 | 
						|
 | 
						|
    @attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="true")
 | 
						|
    def test_07_deploy_vm_with_extraconfig_xenserver(self):
 | 
						|
        hypervisor = self.hypervisor.lower()
 | 
						|
        if hypervisor != 'xenserver':
 | 
						|
            raise self.skipTest("Skipping test case for non-xenserver hypervisor")
 | 
						|
        """
 | 
						|
        Following commands are used to convert a VM from HVM to PV and set using vm-param-set
 | 
						|
        HVM-boot-policy=""
 | 
						|
        PV-bootloader=pygrub
 | 
						|
        PV-args=hvc0
 | 
						|
        """
 | 
						|
 | 
						|
        name = 'allow.additional.vm.configuration.list.xenserver'
 | 
						|
        value = 'HVM-boot-policy, PV-bootloader, PV-args'
 | 
						|
 | 
						|
        add_config_response = self.add_global_config(name, value)
 | 
						|
 | 
						|
        if add_config_response.name:
 | 
						|
            extraconfig = 'HVM-boot-policy%3D%22%22%0APV-bootloader%3Dpygrub%0APV-args%3Dhvc0'
 | 
						|
            try:
 | 
						|
                response = self.deploy_vm(hypervisor, extraconfig)
 | 
						|
                host_id = response.hostid
 | 
						|
                host = list_hosts(
 | 
						|
                    self.apiclient,
 | 
						|
                    id=host_id)
 | 
						|
 | 
						|
                host_ipaddress = host[0].ipaddress
 | 
						|
 | 
						|
                ssh_client = SshClient(host_ipaddress, port=22,
 | 
						|
                                       user=self.hostConfig['username'],
 | 
						|
                                       passwd=self.hostConfig['password'])
 | 
						|
 | 
						|
                extraconfig_decoded = urllib.parse.unquote(extraconfig)
 | 
						|
                config_arr = extraconfig_decoded.splitlines()
 | 
						|
 | 
						|
                # Get vm instance uuid
 | 
						|
                instance_uuid = self.get_vm_uuid(response.instancename, ssh_client)
 | 
						|
                for config in config_arr:
 | 
						|
                    config_tuple = self.get_xen_param_values(config)
 | 
						|
                    # Log on to XenServer host and check the vm-param-get
 | 
						|
                    vm_config_check = 'xe vm-param-get param-name={} uuid={}'.format(config_tuple[0], instance_uuid)
 | 
						|
                    result = ssh_client.execute(vm_config_check)
 | 
						|
                    param_value = config_tuple[1].strip()
 | 
						|
                    # Check if each configuration command has set the configuration as sent with extraconfig
 | 
						|
                    self.assertEqual(
 | 
						|
                        param_value,
 | 
						|
                        result[0],
 | 
						|
                        'Extra  configuration not found in VM param list'
 | 
						|
                    )
 | 
						|
            finally:
 | 
						|
                self.destroy_vm(response.id)
 | 
						|
                self.add_global_config(name, "")
 |