From 93916abcff5ef117fae3d84ab465682ab47582cc Mon Sep 17 00:00:00 2001 From: Chirag Jog Date: Thu, 5 Jul 2012 21:28:14 +0530 Subject: [PATCH] Adding Upload volumes & security enhancements tests --- .../test_security_keys_encryption.py | 372 ++++++++ .../component/test_upload_volumes.py | 896 ++++++++++++++++++ test/integration/lib/base.py | 34 +- 3 files changed, 1292 insertions(+), 10 deletions(-) create mode 100755 test/integration/component/test_security_keys_encryption.py create mode 100644 test/integration/component/test_upload_volumes.py diff --git a/test/integration/component/test_security_keys_encryption.py b/test/integration/component/test_security_keys_encryption.py new file mode 100755 index 00000000000..89907c217d2 --- /dev/null +++ b/test/integration/component/test_security_keys_encryption.py @@ -0,0 +1,372 @@ +""" P1 tests for Security Keys Encryption +""" +#Import Local Modules +from integration.lib.base import * +from integration.lib.common import * +from integration.lib.utils import * +from marvin import remoteSSHClient +from marvin.cloudstackAPI import * +from marvin.cloudstackTestCase import * +import datetime +import marvin + + +class Services: + """Test Security encryption Services + """ + + def __init__(self): + self.services = { + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended for unique + # username + "password": "fr3sca", + }, + "service_offering": { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 100, # in MHz + "memory": 64, # In MBs + }, + "virtual_machine": { + "displayname": "TestVM", + "username": "root", + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "vpn_user": { + "username": "test", + "password": "test", + }, + "host": { + "username": "root", + "password": "fr3sca", + }, + "globalconfig": { + "security.hash.key": "test", + "vmware.guest.vswitch": "test", + "vmware.public.vswitch": "test", + "vmware.private.vswitch": "test", + "kvm.guest.network.device": "test", + "ovm.guest.network.device": "test", + "xen.guest.network.device": "test", + "kvm.public.network.device": "test", + "ovm.public.network.device": "test", + "xen.public.network.device": "test", + "kvm.private.network.device": "test", + "ovm.private.network.device": "test", + "xen.private.network.device": "test", + "xen.storage.network.device1": "test", + "xen.storage.network.device2": "test", + "alert.smtp.password": "test", + "project.smtp.password": "test", + }, + "ostypeid": '7ddbbbb5-bb09-40de-b038-ee78995788ea', + # Cent OS 5.3 (64 bit) + "sleep": 60, + "timeout": 10, + "mode": 'advanced' + } + + +class TestSecurityKeysEncryption(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super(TestSecurityKeysEncryption, cls).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + + template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostypeid"] + ) + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + + cls.services["template"] = template.id + + # Create Account, VMs etc + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + cls.services["account"] = cls.account.account.name + + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) + cls.virtual_machine = VirtualMachine.create( + cls.api_client, + cls.services["virtual_machine"], + templateid=template.id, + accountid=cls.account.account.name, + domainid=cls.account.account.domainid, + serviceofferingid=cls.service_offering.id + ) + + cls.public_ip = PublicIPAddress.create( + cls.api_client, + cls.virtual_machine.account, + cls.virtual_machine.zoneid, + cls.virtual_machine.domainid, + cls.services["virtual_machine"] + ) + + cls._cleanup = [ + cls.service_offering, + cls.account, + ] + 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.cleanup = [] + return + + def tearDown(self): + try: + #Clean up, terminate the created instance, volumes and snapshots + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def test_vm_instance_vnc_password(self): + """ Verify vm_instance table's vnc_password column encryption """ + + tags = ["advanced", "basic"] + + #Steps, + #Deploy a VM + #Once VM is running goto db Server + #Validation, + #Verify vm_instance table's vnc_password column is encrypted + + qresultset = self.dbclient.execute( + "select vnc_password from vm_instance where uuid = '%s';" \ + % self.virtual_machine.id + ) + self.assertEqual( + isinstance(qresultset, list), + True, + "Check DB query result set for valid data" + ) + self.assertNotEqual( + qresultset[0][0], + self.services["virtual_machine"]["password"], + "Check vnc_password in vm_instance table to verify encryption" + ) + return + + def test_vpn_users_password(self): + """ Verify vpn_users table's password column encryption """ + + tags = ["advanced"] + + #Steps, + #Deploy a VM + #Aquire a IP + #Enable VPN on the acquired IP + #Add VPN user + #Validations, + #Verify vpn_users table's password column is encrypted + + self.debug("Created VPN with public IP: %s" % self.public_ip.ipaddress.id) + + #Assign VPN to Public IP + vpn = Vpn.create( + self.apiclient, + self.public_ip.ipaddress.id, + account=self.account.account.name, + domainid=self.account.account.domainid + ) + + self.debug("Created VPN user for account: %s" % + self.account.account.name) + + vpnuser = VpnUser.create( + self.apiclient, + self.services["vpn_user"]["username"], + self.services["vpn_user"]["password"], + account=self.account.account.name, + domainid=self.account.account.domainid + ) + + qresultset = self.dbclient.execute( + "select password from vpn_users where uuid = '%s';" \ + % vpnuser.id + ) + + self.assertEqual( + isinstance(qresultset, list), + True, + "Check DB query result set for valid data" + ) + + self.assertNotEqual( + qresultset[0][0], + self.services["vpn_user"]["password"], + "Check password in vpn_users table to verify encryption" + ) + + def test_user_secret_key(self): + """ Verify user table's SECRET key column encryption """ + #Steps, + #generate key for the user of the account + #Validations, + #Verify user table's secret key column is encrypted + + tags = ["advanced", "basic"] + + user_keys = User.registerUserKeys(self.apiclient, self.account.account.user[0].id) + qresultset = self.dbclient.execute( + "select secret_key from user where uuid = '%s';" \ + % self.account.account.user[0].id + ) + + self.assertEqual( + isinstance(qresultset, list), + True, + "Check DB query result set for valid data" + ) + + self.assertNotEqual( + qresultset[0][0], + user_keys.secretkey, + "Check secret key in users table to verify encryption" + ) + return + + def test_host_password(self): + """ Verify host details table's value column encryption where name is password """ + + tags = ["advanced", "basic"] + + #Validations, + #Verify host details table's value column is encrypted where name is password + + hosts = list_hosts( + self.apiclient, + zoneid=self.services["virtual_machine"]["zoneid"], + type='Routing', + state='Up' + ) + self.assertEqual( + isinstance(hosts, list), + True, + "Check list host returns a valid list" + ) + + host = hosts[0] + + qresultset = self.dbclient.execute( + "select id from host where uuid = '%s';" \ + % host.id + ) + + self.assertEqual( + isinstance(qresultset, list), + True, + "Check DB query result set for valid data" + ) + + hostid = qresultset[0][0] + + qresultset = self.dbclient.execute( + "select value from host_details where host_id = '%s' and name='password';" \ + % hostid + ) + + self.assertEqual( + isinstance(qresultset, list), + True, + "Check DB query result set for valid data" + ) + + self.assertNotEqual( + qresultset[0][0], + self.services["host"]["password"], + "Check password field value in host_details table to verify encryption" + ) + return + + def test_configurations_value_encryption(self): + """ verify configuration tables following name records value field are encrypted """ + + tags = ["advanced", "basic"] + + #Steps + #verify configuration tables following name records value field are encrypted + #security.hash.key + #vmware.guest.vswitch + #vmware.public.vswitch + #vmware.private.vswitch + #kvm.guest.network.device + #ovm.guest.network.device + #xen.guest.network.device + #kvm.public.network.device + #ovm.public.network.device + #xen.public.network.device + #kvm.private.network.device + #ovm.private.network.device + #xen.private.network.device + #xen.storage.network.device1 + #xen.storage.network.device2 + #alert.smtp.password + #project.smtp.password + #Validations, + #Verify configuration table's following name records value filed is encrypted + + for k, v in self.services["globalconfig"].items(): + + #setting some test value to the configuration + Configurations.update(self.apiclient, k, v) + + #fetching the value of the configuration from DB + qresultset = self.dbclient.execute( + "select value from configuration where name = '%s';" \ + % k + ) + + self.assertEqual( + isinstance(qresultset, list), + True, + "Check DB query result set for valid data" + ) + + config_value = qresultset[0][0] + + #verifying the value from db and set are not equal and the value in db is encrypted + self.assertNotEqual( + config_value, + v, + "Configuration %s 's value should be stored in encrypted format in DB" % k + ) + + #Setting the configuration value back to None as default value + Configurations.update(self.apiclient, k) + return diff --git a/test/integration/component/test_upload_volumes.py b/test/integration/component/test_upload_volumes.py new file mode 100644 index 00000000000..a7fa8286e4c --- /dev/null +++ b/test/integration/component/test_upload_volumes.py @@ -0,0 +1,896 @@ +# -*- encoding: utf-8 -*- +# Copyright 2012 Citrix Systems, Inc. Licensed under the +# Apache License, Version 2.0 (the "License"); you may not use this +# file except in compliance with the License. Citrix Systems, Inc. +# reserves all rights not expressly granted by 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. +# +# Automatically generated by addcopyright.py at 04/03/2012 + +""" P1 tests for Upload Volumes +""" + +#Import Local Modules +import marvin +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from integration.lib.utils import * +from integration.lib.base import * +from integration.lib.common import * +from marvin.remoteSSHClient import remoteSSHClient +#Import System modules +import os +import urllib +import time +import tempfile + + +class Services: + """Test Volume Services + """ + + def __init__(self): + self.services = { + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended for unique + # username + "password": "fr3sca", + }, + "service_offering": { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 100, # in MHz + "memory": 64, # In MBs + }, + "disk_offering": { + "displaytext": "Small", + "name": "Small", + "disksize": 1 + }, + "volume": { + "diskname": "UploadedVolume", + "url": "http://192.168.100.21/images/upload_1_gb.vhd", + "format": 'VHD', + }, + "volumes": { + # If you are testing for other hypervisor than XenServer, + # Please change this dict according to following + # "HYPERVISOR" : { + # 0: { + # """Configs for volume type 1 + # supported by HYPERVISOR""" + # Xenserver specific settings for volumes + "xenserver": { + 0: { + "diskname": "Volume_VHD_Format", + "url": "http://192.168.100.21/images/upload_1_gb.vhd", + "format": 'VHD', + }, + }, + }, + "virtual_machine": { + "displayname": "testVM", + "hypervisor": 'XenServer', + "protocol": 'TCP', + "ssh_port": 22, + "username": "root", + "password": "password", + "privateport": 22, + "publicport": 22, + }, + "sleep": 50, + "ostypeid": '7ddbbbb5-bb09-40de-b038-ee78995788ea', + "mode": 'basic', + } + + +class TestUploadDataDisk(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super( + TestUploadDataDisk, + cls + ).getClsTestClient().getApiClient() + cls.services = Services().services + + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostypeid"] + ) + # Create account, service offerings etc + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + + cls.services["account"] = cls.account.account.name + cls.services["zoneid"] = cls.zone.id + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) + cls.disk_offering = DiskOffering.create( + cls.api_client, + cls.services["disk_offering"] + ) + cls._cleanup = [ + cls.service_offering, + cls.disk_offering, + cls.account + ] + + def setUp(self): + + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + try: + #Clean up, terminate the created volumes + self.debug("Cleanup the resources..") + cleanup_resources(self.apiclient, self.cleanup) + self.debug("Cleanup succeeded") + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + def test_01_upload_data_disk(self): + """Test Upload a data disk + """ + + tags = ["advanced", "basic", "eip", "advancedns", "sg"] + + # Validate the following + # 1. call upload volume API with following parameters HTTP URL of the + # data disk, Zone ID, Name, Description, Hyper visor + # 2. Upload volume is successful + + self.debug("Uploading the volume to account: %s" % + self.account.account.name) + # Upload the volume + volume = Volume.upload( + self.apiclient, + self.services["volume"], + zoneid=self.zone.id, + account=self.account.account.name, + domainid=self.account.account.domainid, + url=self.services["volume"]["url"] + ) + self.debug("Registered volume: %s for account: %s" % ( + volume.name, + self.account.account.name + )) + self.debug("Waiting for upload of volume: %s" % volume.name) + try: + volume.wait_for_upload(self.apiclient) + self.debug("Volume: %s uploaded to CS successfully" % volume.name) + except Exception as e: + self.fail("Upload volume failed: %s" % e) + + # Check List Volume response for newly created volume + list_volume_response = Volume.list( + self.apiclient, + id=volume.id, + zoneid=self.zone.id, + listall=True + ) + self.assertNotEqual( + list_volume_response, + None, + "Check if volume exists in ListVolumes" + ) + volume_response = list_volume_response[0] + self.assertEqual( + volume_response.state, + "Uploaded", + "Volume state should be 'Uploaded' after importing to CS" + ) + return + + def test_02_upload_volume_limit(self): + """Test upload volume limits + """ + + tags = ["advanced", "basic", "eip", "advancedns", "sg"] + + # Validate the following + # 1. Update the volume resource limit for account to 1 + # 2. Upload volume in that account + # 3. Upload volume should fail with appropriate error + + self.debug( + "Updating volume resource limit for account: %s" % + self.account.account.name) + # Set usage_vm=1 for Account 1 + update_resource_limit( + self.apiclient, + 2, # Volume + account=self.account.account.name, + domainid=self.account.account.domainid, + max=1 + ) + + self.debug("Uploading the volume to account: %s" % + self.account.account.name) + with self.assertRaises(Exception): + # Upload the volume + volume = Volume.upload( + self.apiclient, + self.services["volume"], + zoneid=self.zone.id, + account=self.account.account.name, + domainid=self.account.account.domainid, + url=self.services["volume"]["url"] + ) + self.debug("Registered volume: %s for account: %s" % ( + volume.name, + self.account.account.name + )) + self.debug("Upload volume failed! Test succeeded..") + return + + +class TestUploadDiskDiffFormat(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super( + TestUploadDiskDiffFormat, + cls + ).getClsTestClient().getApiClient() + cls.services = Services().services + + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostypeid"] + ) + # Create account, service offerings etc + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + cls.services["zoneid"] = cls.zone.id + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) + cls.disk_offering = DiskOffering.create( + cls.api_client, + cls.services["disk_offering"] + ) + cls._cleanup = [ + cls.service_offering, + cls.disk_offering, + cls.account + ] + + def setUp(self): + + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + try: + #Clean up, terminate the created volumes + self.debug("Cleanup the resources..") + cleanup_resources(self.apiclient, self.cleanup) + self.debug("Cleanup succeeded") + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + def test_upload_disk_diff_format(self): + """Test Upload a data disk in different format + """ + + tags = ["advanced", "basic", "eip", "advancedns", "sg"] + + # Validate the following + # 1. call upload volume API with following parameters HTTP URL of the + # data disk, Zone ID, Name, Description, Hyper visor + # disk types are: zip file format,tar format,tar gzip format + # tar bzip format + # 2. Upload volume is successful + + for hypervisor, settings in self.services["volumes"].items(): + for k, v in settings.items(): + self.debug( + "Uploading the volume (type: %s) for Hypervisor: %s to account: %s" % ( + v["format"], + hypervisor, + self.account.account.name + )) + # Upload the volume + volume = Volume.upload( + self.apiclient, + v, + zoneid=self.zone.id, + account=self.account.account.name, + domainid=self.account.account.domainid, + ) + self.debug("Registered volume: %s for account: %s" % ( + volume.name, + self.account.account.name + )) + self.debug("Waiting for upload of volume: %s" % volume.name) + try: + volume.wait_for_upload(self.apiclient) + self.debug("Volume: %s uploaded to CS successfully" % + volume.name) + except Exception as e: + self.fail("Upload volume failed: %s" % e) + + # Check List Volume response for newly created volume + list_volume_response = list_volumes( + self.apiclient, + id=volume.id + ) + self.assertNotEqual( + list_volume_response, + None, + "Check if volume exists in ListVolumes" + ) + volume_response = list_volume_response[0] + self.assertEqual( + volume_response.state, + "Uploaded", + "Volume state should be 'Uploaded' after importing to CS" + ) + return + + +class TestUploadAttachDisk(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super( + TestUploadAttachDisk, + cls + ).getClsTestClient().getApiClient() + cls.services = Services().services + + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostypeid"] + ) + # Create account, service offerings etc + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + + cls.services["account"] = cls.account.account.name + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.services["zoneid"] = cls.zone.id + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) + cls.disk_offering = DiskOffering.create( + cls.api_client, + cls.services["disk_offering"] + ) + cls.virtual_machine = VirtualMachine.create( + cls.api_client, + cls.services["virtual_machine"], + templateid=template.id, + accountid=cls.account.account.name, + domainid=cls.account.account.domainid, + serviceofferingid=cls.service_offering.id, + ) + cls._cleanup = [ + cls.service_offering, + cls.disk_offering, + cls.account + ] + + def setUp(self): + + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + try: + #Clean up, terminate the created volumes + self.debug("Cleanup the resources..") + cleanup_resources(self.apiclient, self.cleanup) + self.debug("Cleanup succeeded") + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + def test_upload_attach_data_disk(self): + """Test Upload and attach a data disk + """ + + tags = ["advanced", "basic", "eip", "advancedns", "sg"] + + # Validate the following + # 1. call upload volume API with following parameters HTTP URL of the + # data disk, Zone ID, Name, Description, Hyper visor + # 2. Upload volume is successful + + self.debug("Uploading the volume to account: %s" % + self.account.account.name) + # Upload the volume + volume = Volume.upload( + self.apiclient, + self.services["volume"], + zoneid=self.zone.id, + account=self.account.account.name, + domainid=self.account.account.domainid, + url=self.services["volume"]["url"] + ) + self.debug("Registered volume: %s for account: %s" % ( + volume.name, + self.account.account.name + )) + self.debug("Waiting for upload of volume: %s" % volume.name) + try: + volume.wait_for_upload(self.apiclient) + self.debug("Volume: %s uploaded to CS successfully" % volume.name) + except Exception as e: + self.fail("Upload volume failed: %s" % e) + + # Check List Volume response for newly created volume + list_volume_response = Volume.list( + self.apiclient, + id=volume.id, + zoneid=self.zone.id, + listall=True + ) + self.assertNotEqual( + list_volume_response, + None, + "Check if volume exists in ListVolumes" + ) + volume_response = list_volume_response[0] + self.assertEqual( + volume_response.state, + "Uploaded", + "Volume state should be 'Uploaded' after importing to CS" + ) + self.debug( + "Attaching the disk: %s to VM: %s" % ( + self.virtual_machine.name, + volume.name + )) + self.virtual_machine.attach_volume(self.apiclient, volume) + self.debug( + "Volume attached to instance: %s" % + self.virtual_machine.name) + # Check List Volume response for newly created volume + list_volume_response = Volume.list( + self.apiclient, + id=volume.id, + virtualmachineid=self.virtual_machine.id, + listall=True + ) + self.assertNotEqual( + list_volume_response, + None, + "Check if volume exists in ListVolumes" + ) + + volume_response = list_volume_response[0] + self.assertEqual( + volume_response.state, + "Ready", + "Volume state should be 'Uploaded' after importing to CS" + ) + return + + +class TestUploadAttachDiskDiffFormat(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super( + TestUploadAttachDiskDiffFormat, + cls + ).getClsTestClient().getApiClient() + cls.services = Services().services + + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostypeid"] + ) + # Create account, service offerings etc + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.services["zoneid"] = cls.zone.id + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) + cls.disk_offering = DiskOffering.create( + cls.api_client, + cls.services["disk_offering"] + ) + cls.virtual_machine = VirtualMachine.create( + cls.api_client, + cls.services["virtual_machine"], + templateid=template.id, + accountid=cls.account.account.name, + domainid=cls.account.account.domainid, + serviceofferingid=cls.service_offering.id, + ) + cls._cleanup = [ + cls.service_offering, + cls.disk_offering, + cls.account + ] + + def setUp(self): + + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + try: + #Clean up, terminate the created volumes + self.debug("Cleanup the resources..") + cleanup_resources(self.apiclient, self.cleanup) + self.debug("Cleanup succeeded") + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + def test_upload_disk_diff_format(self): + """Test Upload a data disk in different format + """ + + tags = ["advanced", "basic", "eip", "advancedns", "sg"] + + # Validate the following + # 1. call upload volume API with following parameters HTTP URL of the + # data disk, Zone ID, Name, Description, Hyper visor + # disk types are: zip file format,tar format,tar gzip format + # tar bzip format + # 2. Upload volume is successful + + for hypervisor, settings in self.services["volumes"].items(): + for k, v in settings.items(): + self.debug( + "Uploading the volume (type: %s) for Hypervisor: %s to account: %s" % ( + v["format"], + hypervisor, + self.account.account.name + )) + # Upload the volume + volume = Volume.upload( + self.apiclient, + v, + zoneid=self.zone.id, + account=self.account.account.name, + domainid=self.account.account.domainid, + ) + self.debug("Registered volume: %s for account: %s" % ( + volume.name, + self.account.account.name + )) + self.debug("Waiting for upload of volume: %s" % volume.name) + try: + volume.wait_for_upload(self.apiclient) + self.debug("Volume: %s uploaded to CS successfully" % + volume.name) + except Exception as e: + self.fail("Upload volume failed: %s" % e) + + # Check List Volume response for newly created volume + list_volume_response = list_volumes( + self.apiclient, + id=volume.id + ) + self.assertNotEqual( + list_volume_response, + None, + "Check if volume exists in ListVolumes" + ) + volume_response = list_volume_response[0] + self.assertEqual( + volume_response.state, + "Uploaded", + "Volume state should be 'Uploaded' after importing to CS" + ) + + self.debug( + "Attaching the disk: %s to VM: %s" % ( + self.virtual_machine.name, + volume.name + )) + self.virtual_machine.attach_volume(self.apiclient, volume) + self.debug( + "Volume attached to instance: %s" % + self.virtual_machine.name) + # Check List Volume response for newly created volume + list_volume_response = Volume.list( + self.apiclient, + id=volume.id, + virtualmachineid=self.virtual_machine.id, + listall=True + ) + self.assertNotEqual( + list_volume_response, + None, + "Check if volume exists in ListVolumes" + ) + + volume_response = list_volume_response[0] + self.assertEqual( + volume_response.state, + "Ready", + "Volume state should be 'Uploaded' after importing to CS" + ) + return + + +class TestUploadDiskMultiStorage(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super( + TestUploadDiskMultiStorage, + cls + ).getClsTestClient().getApiClient() + cls.services = Services().services + + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + cls.pod = get_pod(cls.api_client, zoneid=cls.zone.id) + + template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostypeid"] + ) + # Create account, service offerings etc + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + + cls.services["account"] = cls.account.account.name + cls.services["zoneid"] = cls.zone.id + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) + cls.disk_offering = DiskOffering.create( + cls.api_client, + cls.services["disk_offering"] + ) + cls._cleanup = [ + cls.service_offering, + cls.disk_offering, + cls.account + ] + + def setUp(self): + + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + try: + #Clean up, terminate the created volumes + self.debug("Cleanup the resources..") + cleanup_resources(self.apiclient, self.cleanup) + self.debug("Cleanup succeeded") + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + def test_01_upload_volume_multi_sec_storage(self): + """Test Upload a data disk when multiple sec storages are present + """ + + tags = ["advanced", "basic", "eip", "advancedns", "sg"] + + # Validate the following + # 1. Assume multiple secondary storages are present in a zone + # 2. call upload volume API with following parameters HTTP URL of the + # data disk, Zone ID, Name, Description, Hyper visor + # 2. Upload volume is successful + + sec_storages = Host.list( + self.apiclient, + type='SecondaryStorage', + zoneid=self.zone.id + ) + self.assertEqual( + isinstance(sec_storages, list), + True, + "List Secondary storage should return a valid list" + ) + self.assertGreaterEqual( + len(sec_storages), + 2, + "Test requires atleast 2 secondary storages added to zone" + ) + self.debug("Uploading the volume to account: %s" % + self.account.account.name) + # Upload the volume + volume = Volume.upload( + self.apiclient, + self.services["volume"], + zoneid=self.zone.id, + account=self.account.account.name, + domainid=self.account.account.domainid, + url=self.services["volume"]["url"] + ) + self.debug("Registered volume: %s for account: %s" % ( + volume.name, + self.account.account.name + )) + self.debug("Waiting for upload of volume: %s" % volume.name) + try: + volume.wait_for_upload(self.apiclient) + self.debug("Volume: %s uploaded to CS successfully" % volume.name) + except Exception as e: + self.fail("Upload volume failed: %s" % e) + + # Check List Volume response for newly created volume + list_volume_response = Volume.list( + self.apiclient, + id=volume.id, + zoneid=self.zone.id, + listall=True + ) + self.assertNotEqual( + list_volume_response, + None, + "Check if volume exists in ListVolumes" + ) + volume_response = list_volume_response[0] + self.assertEqual( + volume_response.state, + "Uploaded", + "Volume state should be 'Uploaded' after importing to CS" + ) + return + + def test_02_upload_volume_multi_pri_storage(self): + """Test Upload a data disk when multiple primary storages are present + """ + + tags = ["advanced", "basic", "eip", "advancedns", "sg"] + + # Validate the following + # 1. Assume multiple primary storages are present in a pod + # 2. call upload volume API with following parameters HTTP URL of the + # data disk, Zone ID, Name, Description, Hyper visor + # 2. Upload volume is successful + + storage_pools = StoragePool.list( + self.apiclient, + zoneid=self.zone.id, + podid=self.pod.id + ) + self.assertEqual( + isinstance(storage_pools, list), + True, + "List Primary storage should return a valid list" + ) + self.assertGreaterEqual( + len(storage_pools), + 2, + "Test requires atleast 2 primary storages added to pod" + ) + self.debug("Uploading the volume to account: %s" % + self.account.account.name) + # Upload the volume + volume = Volume.upload( + self.apiclient, + self.services["volume"], + zoneid=self.zone.id, + account=self.account.account.name, + domainid=self.account.account.domainid, + url=self.services["volume"]["url"] + ) + self.debug("Registered volume: %s for account: %s" % ( + volume.name, + self.account.account.name + )) + self.debug("Waiting for upload of volume: %s" % volume.name) + try: + volume.wait_for_upload(self.apiclient) + self.debug("Volume: %s uploaded to CS successfully" % volume.name) + except Exception as e: + self.fail("Upload volume failed: %s" % e) + + # Check List Volume response for newly created volume + list_volume_response = Volume.list( + self.apiclient, + id=volume.id, + zoneid=self.zone.id, + listall=True + ) + self.assertNotEqual( + list_volume_response, + None, + "Check if volume exists in ListVolumes" + ) + volume_response = list_volume_response[0] + self.assertEqual( + volume_response.state, + "Uploaded", + "Volume state should be 'Uploaded' after importing to CS" + ) + return diff --git a/test/integration/lib/base.py b/test/integration/lib/base.py index 69882bcb13d..cc783c6764b 100644 --- a/test/integration/lib/base.py +++ b/test/integration/lib/base.py @@ -51,8 +51,12 @@ class Domain: cmd.parentdomainid = parentdomainid elif "parentdomainid" in services: cmd.parentdomainid = services["parentdomainid"] - - return Domain(apiclient.createDomain(cmd).__dict__) + try: + domain = apiclient.createDomain(cmd) + if domain is not None: + return Domain(domain.__dict__) + except Exception as e: + raise e def delete(self, apiclient, cleanup=None): """Delete an domain""" @@ -155,6 +159,12 @@ class User: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listUsers(cmd)) + @classmethod + def registerUserKeys(cls, apiclient, userid): + cmd = registerUserKeys.registerUserKeysCmd() + cmd.id = userid + return apiclient.registerUserKeys(cmd) + class VirtualMachine: """Manage virtual machine lifecycle""" @@ -255,14 +265,14 @@ class VirtualMachine: virtual_machine.domainid, services ) - fw_rule = FireWallRule.create( + FireWallRule.create( apiclient, ipaddressid=public_ip.ipaddress.id, protocol='TCP', cidrlist=['0.0.0.0/0'], startport=22, endport=22 - ) + ) nat_rule = NATRule.create( apiclient, virtual_machine, @@ -481,7 +491,7 @@ class Volume: return(apiclient.listVolumes(cmd)) @classmethod - def upload(cls, apiclient, services, zoneid=None, account=None, domainid=None): + def upload(cls, apiclient, services, zoneid=None, account=None, domainid=None, url=None): """Uploads the volume to specified account""" cmd = uploadVolume.uploadVolumeCmd() @@ -493,7 +503,10 @@ class Volume: cmd.domainid = domainid cmd.format = services["format"] cmd.name = services["diskname"] - cmd.url = services["url"] + if url: + cmd.url = url + else: + cmd.url = services["url"] return Volume(apiclient.uploadVolume(cmd).__dict__) def wait_for_upload(self, apiclient, timeout=5, interval=60): @@ -506,14 +519,13 @@ class Volume: apiclient, id=self.id, zoneid=self.zoneid, - templatefilter='self' ) if isinstance(volume_response, list): volume = volume_response[0] # If volume is ready, # volume.state = Allocated - if volue.state == 'Allocated': + if volume.state == 'Uploaded': break elif 'Uploading' in volume.state: @@ -523,7 +535,6 @@ class Volume: raise Exception( "Error in uploading volume: status - %s" % volume.state) - elif timeout == 0: break @@ -532,6 +543,7 @@ class Volume: timeout = timeout - 1 return + class Snapshot: """Manage Snapshot Lifecycle """ @@ -1104,7 +1116,7 @@ class NetworkOffering: cmd.specifyVlan = services["specifyVlan"] if "specifyIpRanges" in services: cmd.specifyIpRanges = services["specifyIpRanges"] - cmd.availability = 'Optional' + cmd.availability = 'Optional' [setattr(cmd, k, v) for k, v in kwargs.items()] @@ -1811,6 +1823,7 @@ class PhysicalNetwork: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listPhysicalNetworks(cmd)) + class SecurityGroup: """Manage Security Groups""" @@ -2178,6 +2191,7 @@ class NetworkServiceProvider: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listNetworkServiceProviders(cmd)) + class Router: """Manage router life cycle"""