| # 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. |
| |
| """ Smoke tests for VNF templates/appliances |
| """ |
| from marvin.cloudstackTestCase import cloudstackTestCase |
| from marvin.lib.base import (Account, |
| Domain, |
| Configurations, |
| ServiceOffering, |
| VirtualMachine, |
| Network, |
| NetworkOffering, |
| VnfAppliance, |
| VnfTemplate, |
| Zone) |
| from marvin.lib.common import get_zone, get_template |
| from nose.plugins.attrib import attr |
| |
| import time |
| |
| VNF_NICS = [{"deviceid": "0", "name": "WAN", "required": "true", "description": "Public WAN"}, |
| {"deviceid": "1", "name": "LAN-1", "required": "true", "description": "Private LAN-1"}] |
| NEW_VNF_NICS = [{"deviceid": "0", "name": "WAN", "required": "true", "description": "Public WAN"}, |
| {"deviceid": "1", "name": "LAN-1", "required": "true", "description": "Private LAN-1"}, |
| {"deviceid": "2", "name": "LAN-2", "required": "false", "description": "Private LAN-2"}] |
| VNF_DETAILS = [{"access_methods": "console,https,http", "username": "root"}] |
| NEW_VNF_DETAILS = [{"access_methods": "console,https,http", "username": "root", "password": "cloudstack"}] |
| |
| class TestVnfTemplates(cloudstackTestCase): |
| |
| @classmethod |
| def setUpClass(cls): |
| |
| testClient = super(TestVnfTemplates, cls).getClsTestClient() |
| cls.apiclient = testClient.getApiClient() |
| cls._cleanup = [] |
| cls.services = testClient.getParsedTestDataConfig() |
| |
| # Get Zone, Domain and templates |
| cls.hypervisor = cls.testClient.getHypervisorInfo() |
| zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests()) |
| cls.zone = Zone(zone.__dict__) |
| cls.template = get_template(cls.apiclient, cls.zone.id) |
| |
| cls.domain = Domain.create( |
| cls.apiclient, |
| cls.services["domain"] |
| ) |
| cls._cleanup.append(cls.domain) |
| |
| cls.account = Account.create( |
| cls.apiclient, |
| cls.services["account"], |
| admin=True, |
| domainid=cls.domain.id |
| ) |
| cls._cleanup.append(cls.account) |
| |
| cls.user = cls.account.user[0] |
| cls.user_apiclient = cls.testClient.getUserApiClient( |
| cls.user.username, cls.domain.name |
| ) |
| |
| cls.service_offering = ServiceOffering.create( |
| cls.apiclient, |
| cls.services["service_offerings"]["big"] |
| ) |
| cls._cleanup.append(cls.service_offering) |
| |
| cls.vnf_template_config = { |
| "name": "pfsense", |
| "displaytext": "pfsense", |
| "format": cls.template.format, |
| "url": cls.template.url, |
| "requireshvm": "True", |
| "ispublic": "True", |
| "isextractable": "True", |
| "hypervisor": cls.hypervisor, |
| "zoneid": cls.zone.id, |
| "ostype": "FreeBSD 12 (64-bit)", |
| "directdownload": False |
| } |
| |
| cls.initial_setting = Configurations.list( |
| cls.apiclient, |
| name="vnf.template.appliance.enabled")[0].value |
| |
| Configurations.update(cls.apiclient, "vnf.template.appliance.enabled", "true") |
| |
| cls.vnf_templates = [] |
| |
| @classmethod |
| def tearDownClass(cls): |
| Configurations.update(cls.apiclient, "vnf.template.appliance.enabled", cls.initial_setting) |
| if len(cls.vnf_templates) > 0: |
| for vnf_template in cls.vnf_templates: |
| vnf_template.delete(cls.user_apiclient) |
| super(TestVnfTemplates, cls).tearDownClass() |
| |
| def setUp(self): |
| self.apiclient = self.testClient.getApiClient() |
| self.dbclient = self.testClient.getDbConnection() |
| self.cleanup = [] |
| |
| def tearDown(self): |
| super(TestVnfTemplates, self).tearDown() |
| |
| def ensureVnfTemplateExists(self): |
| if len(self.vnf_templates) == 0: |
| self.vnf_template = VnfTemplate.register(self.user_apiclient, |
| self.vnf_template_config, |
| zoneid=self.zone.id, |
| hypervisor=self.hypervisor, |
| vnfnics=VNF_NICS, |
| vnfdetails=VNF_DETAILS) |
| self.vnf_templates.append(self.vnf_template) |
| else: |
| self.vnf_template = self.vnf_templates[0] |
| |
| def ensureVnfTemplateDownloaded(self): |
| """Check if template download will finish in 5 minutes""" |
| retries = 30 |
| interval = 10 |
| while retries > -1: |
| time.sleep(interval) |
| templates_response = VnfTemplate.list( |
| self.user_apiclient, |
| id=self.vnf_template.id, |
| zoneid=self.zone.id, |
| templatefilter='self' |
| ) |
| template = templates_response[0] |
| |
| if not hasattr(template, 'status') or not template or not template.status: |
| retries = retries - 1 |
| continue |
| |
| if 'Failed' in template.status: |
| raise Exception( |
| "Failed to download template: status - %s" % |
| template.status) |
| elif template.status == 'Download Complete' and template.isready: |
| return |
| elif 'Downloaded' in template.status: |
| retries = retries - 1 |
| continue |
| elif 'Installing' not in template.status: |
| if retries >= 0: |
| retries = retries - 1 |
| continue |
| raise Exception( |
| "Error in downloading template: status - %s" % |
| template.status) |
| else: |
| retries = retries - 1 |
| raise Exception("Template download failed exception.") |
| |
| @attr(tags=["advanced"], required_hardware="false") |
| def test_01_register_vnf_template(self): |
| """Test register VNF template |
| """ |
| self.ensureVnfTemplateExists() |
| |
| @attr(tags=["advanced"], required_hardware="false") |
| def test_02_list_vnf_template(self): |
| """Test list VNF template |
| """ |
| self.ensureVnfTemplateExists() |
| |
| templates_response = VnfTemplate.list( |
| self.user_apiclient, |
| id=self.vnf_template.id, |
| zoneid=self.zone.id, |
| templatefilter='self' |
| ) |
| |
| if isinstance(templates_response, list) and len(templates_response) > 0: |
| template = templates_response[0] |
| self.assertEqual("VNF", template.templatetype, |
| "The template type of VNF template should be VNF but actually it is %s" % template.templatetype) |
| self.assertTrue(isinstance(template.vnfnics, list), "The template vnfnics must be a list") |
| self.assertEqual(2, len(template.vnfnics), "The VNF template should have 2 VNF nics") |
| self.assertEqual(2, len(template.vnfdetails.__dict__), "The VNF template should have 2 VNF details") |
| else: |
| self.fail("Failed to get VNF templates by listVnfTemplates API") |
| |
| @attr(tags=["advanced"], required_hardware="false") |
| def test_03_edit_vnf_template(self): |
| """Test edit VNF template |
| """ |
| self.ensureVnfTemplateExists() |
| |
| self.vnf_template.update( |
| self.user_apiclient, |
| id=self.vnf_template.id, |
| vnfnics=NEW_VNF_NICS, |
| vnfdetails=NEW_VNF_DETAILS |
| ) |
| |
| templates_response = VnfTemplate.list( |
| self.user_apiclient, |
| id=self.vnf_template.id, |
| zoneid=self.zone.id, |
| templatefilter='self' |
| ) |
| |
| if isinstance(templates_response, list) and len(templates_response) > 0: |
| template = templates_response[0] |
| self.assertEqual("VNF", template.templatetype, |
| "The template type of VNF template should be VNF but actually it is %s" % template.templatetype) |
| self.assertEqual(3, len(template.vnfnics), "The VNF template should have 2 VNF nics") |
| self.assertEqual(3, len(template.vnfdetails.__dict__), "The VNF template should have 3 VNF details") |
| else: |
| self.fail("Failed to get VNF templates by listVnfTemplates API") |
| |
| @attr(tags=["advanced"], required_hardware="false") |
| def test_04_deploy_vnf_appliance(self): |
| """Test deploy VNF appliance |
| """ |
| self.ensureVnfTemplateExists() |
| self.ensureVnfTemplateDownloaded() |
| |
| templates_response = VnfTemplate.list( |
| self.user_apiclient, |
| id=self.vnf_template.id, |
| zoneid=self.zone.id, |
| templatefilter='self' |
| ) |
| |
| if isinstance(templates_response, list) and len(templates_response) > 0: |
| template = templates_response[0] |
| if not template.isready: |
| self.fail("VNF template is not Ready") |
| else: |
| self.fail("Failed to find VNF template") |
| |
| # Create network offerings |
| self.isolated_network_offering = NetworkOffering.create( |
| self.apiclient, |
| self.services["isolated_network_offering"]) |
| self.cleanup.append(self.isolated_network_offering) |
| self.isolated_network_offering.update( |
| self.apiclient, |
| state='Enabled') |
| |
| self.l2_network_offering = NetworkOffering.create( |
| self.apiclient, |
| self.services["l2-network_offering"]) |
| self.cleanup.append(self.l2_network_offering) |
| self.l2_network_offering.update( |
| self.apiclient, |
| state='Enabled') |
| |
| # Create networks |
| isolated_network = Network.create( |
| self.user_apiclient, |
| self.services["network"], |
| networkofferingid=self.isolated_network_offering.id, |
| zoneid=self.zone.id |
| ) |
| self.cleanup.append(isolated_network) |
| |
| l2_network_1 = Network.create( |
| self.user_apiclient, |
| self.services["l2-network"], |
| networkofferingid=self.l2_network_offering.id, |
| zoneid=self.zone.id |
| ) |
| self.cleanup.append(l2_network_1) |
| |
| l2_network_2 = Network.create( |
| self.user_apiclient, |
| self.services["l2-network"], |
| networkofferingid=self.l2_network_offering.id, |
| zoneid=self.zone.id |
| ) |
| self.cleanup.append(l2_network_2) |
| |
| # failed deployment |
| try: |
| self.virtual_machine = VirtualMachine.create( |
| self.user_apiclient, |
| self.services["virtual_machine"], |
| zoneid=self.zone.id, |
| templateid=self.vnf_template.id, |
| accountid=self.account.name, |
| domainid=self.account.domainid, |
| serviceofferingid=self.service_offering.id, |
| networkids=[isolated_network.id] |
| ) |
| self.cleanup.append(self.virtual_machine) |
| self.fail("The deployment should fail") |
| except Exception as e: |
| pass |
| |
| # success deployment |
| self.vnf_appliance = VnfAppliance.create( |
| self.user_apiclient, |
| self.services["virtual_machine"], |
| zoneid=self.zone.id, |
| templateid=self.vnf_template.id, |
| accountid=self.account.name, |
| domainid=self.account.domainid, |
| serviceofferingid=self.service_offering.id, |
| networkids=[isolated_network.id, l2_network_1.id, l2_network_2.id], |
| vnfconfiguremanagement='true' |
| ) |
| self.cleanup.append(self.vnf_appliance) |
| |
| @attr(tags=["advanced"], required_hardware="false") |
| def test_05_delete_vnf_template(self): |
| """Test delete VNF template |
| """ |
| self.ensureVnfTemplateExists() |
| |
| self.vnf_template.delete(self.user_apiclient) |
| |
| templates_response = VnfTemplate.list( |
| self.user_apiclient, |
| id=self.vnf_template.id, |
| zoneid=self.zone.id, |
| templatefilter='self' |
| ) |
| self.assertIsNone(templates_response, "The VNF template should be removed") |
| |
| self.vnf_templates.remove(self.vnf_template) |