| # 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. |
| """ P1 tests for Browser Based Upload Volumes |
| """ |
| # Import Local Modules |
| |
| import os |
| import random |
| import string |
| import tempfile |
| import time |
| import unittest |
| import urllib.error |
| import urllib.parse |
| import urllib.request |
| |
| import requests |
| from marvin.cloudstackAPI import * |
| from marvin.cloudstackTestCase import cloudstackTestCase |
| from marvin.codes import PASS, FAILED |
| from marvin.lib.base import * |
| from marvin.lib.common import * |
| from marvin.lib.utils import * |
| from nose.plugins.attrib import attr |
| |
| _multiprocess_shared_ = True |
| |
| |
| class TestBrowseUploadVolume(cloudstackTestCase): |
| """ |
| Testing Browse Upload Volume Feature |
| """ |
| |
| @classmethod |
| def setUpClass(cls): |
| cls.testClient = super(TestBrowseUploadVolume, cls).getClsTestClient() |
| cls.testdata = cls.testClient.getParsedTestDataConfig() |
| cls.apiclient = cls.testClient.getApiClient() |
| cls.hypervisor = cls.testClient.getHypervisorInfo() |
| cls._cleanup = [] |
| cls.uploadvolumeformat = "VHD" |
| cls.storagetype = 'shared' |
| cls.globalurl = "http://url" |
| |
| hosts = list_hosts( |
| cls.apiclient, |
| type="Routing" |
| ) |
| |
| if hosts is None: |
| raise unittest.SkipTest( |
| "There are no hypervisor's available.Check listhosts response") |
| for hypervisorhost in hosts: |
| if hypervisorhost.hypervisor == "XenServer": |
| cls.uploadvolumeformat = "VHD" |
| break |
| elif hypervisorhost.hypervisor == "VMware": |
| cls.uploadvolumeformat = "OVA" |
| break |
| elif hypervisorhost.hypervisor == "KVM": |
| cls.uploadvolumeformat = "QCOW2" |
| break |
| else: |
| break |
| |
| cls.uploadurl = cls.testdata["configurableData"]["browser_upload_volume"][cls.uploadvolumeformat]["url"] |
| cls.volname = cls.testdata["configurableData"]["browser_upload_volume"][cls.uploadvolumeformat]["diskname"] |
| cls.md5sum = cls.testdata["configurableData"]["browser_upload_volume"][cls.uploadvolumeformat]["checksum"] |
| cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests()) |
| cls.domain = get_domain(cls.apiclient) |
| cls.pod = get_pod(cls.apiclient, cls.zone.id) |
| |
| if cls.uploadvolumeformat == "QCOW2" or cls.uploadvolumeformat == "VHD": |
| cls.extuploadurl = cls.testdata["configurableData"]["browser_upload_volume"][cls.uploadvolumeformat]["url"] |
| cls.account = Account.create( |
| cls.apiclient, |
| cls.testdata["account"], |
| domainid=cls.domain.id |
| ) |
| cls._cleanup.append(cls.account) |
| |
| cls.template = get_template( |
| cls.apiclient, |
| cls.zone.id) |
| |
| if cls.template == FAILED: |
| raise unittest.SkipTest( |
| "Check for default cent OS template readiness ") |
| cls.service_offering = ServiceOffering.create( |
| cls.apiclient, |
| cls.testdata["service_offering"] |
| ) |
| cls._cleanup.append(cls.service_offering) |
| cls.disk_offering = DiskOffering.create( |
| cls.apiclient, |
| cls.testdata["configurableData"]["browser_upload_volume"]["browser_resized_disk_offering"], |
| custom=True |
| ) |
| cls._cleanup.append(cls.disk_offering) |
| cls.project = Project.create( |
| cls.apiclient, |
| cls.testdata["project"], |
| account=cls.account.name, |
| domainid=cls.account.domainid |
| ) |
| cls._cleanup.append(cls.project) |
| |
| def __verify_values(self, expected_vals, actual_vals): |
| |
| return_flag = True |
| |
| if len(expected_vals) != len(actual_vals): |
| return False |
| |
| keys = list(expected_vals.keys()) |
| for i in range(0, len(expected_vals)): |
| exp_val = expected_vals[keys[i]] |
| act_val = actual_vals[keys[i]] |
| if exp_val == act_val: |
| return_flag = return_flag and True |
| else: |
| return_flag = return_flag and False |
| self.debug( |
| "expected Value: %s, is not matching with actual value:\ |
| %s" % |
| (exp_val, act_val)) |
| return return_flag |
| |
| def validate_uploaded_volume(self, up_volid, volumestate): |
| |
| config1 = Configurations.list( |
| self.apiclient, |
| name='upload.operation.timeout' |
| ) |
| |
| config2 = Configurations.list( |
| self.apiclient, |
| name='upload.monitoring.interval' |
| ) |
| |
| uploadtimeout = int(config1[0].value) |
| monitoringinterval = int(config2[0].value) |
| |
| time.sleep((uploadtimeout * 60) + monitoringinterval) |
| |
| list_volume_response = Volume.list( |
| self.apiclient, |
| id=up_volid |
| ) |
| if list_volume_response is None: |
| self.debug("Volume got deleted after timeout") |
| return |
| |
| self.assertEqual( |
| list_volume_response[0].state, |
| volumestate, |
| "Check volume state in ListVolumes" |
| ) |
| return |
| |
| def browse_upload_volume_with_projectid(self, projectid): |
| |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.format = self.uploadvolumeformat |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| cmd.projectid = projectid |
| getuploadparamsresponse = self.apiclient.getUploadParamsForVolume(cmd) |
| |
| signt = getuploadparamsresponse.signature |
| posturl = getuploadparamsresponse.postURL |
| metadata = getuploadparamsresponse.metadata |
| expiredata = getuploadparamsresponse.expires |
| |
| url = self.uploadurl |
| |
| uploadfile = url.split('/')[-1] |
| r = requests.get(url, stream=True) |
| with open(uploadfile, 'wb') as f: |
| for chunk in r.iter_content(chunk_size=1024): |
| if chunk: # filter out keep-alive new chunks |
| f.write(chunk) |
| f.flush() |
| |
| files = {'file': (uploadfile, open(uploadfile, 'rb'), 'application/octet-stream')} |
| |
| headers = {'x-signature': signt, 'x-metadata': metadata, 'x-expires': expiredata} |
| |
| results = requests.post(posturl, files=files, headers=headers, verify=False) |
| |
| print(results.status_code) |
| if results.status_code != 200: |
| self.fail("Upload is not fine") |
| |
| self.validate_uploaded_volume(getuploadparamsresponse.id, 'Uploaded') |
| |
| list_volume_response = Volume.list( |
| self.apiclient, |
| projectid=projectid |
| ) |
| if list_volume_response[0].id == getuploadparamsresponse.id: |
| return (getuploadparamsresponse) |
| else: |
| self.fail("Volume is not listed with projectid") |
| |
| def browse_upload_volume_with_out_zoneid(self): |
| |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.format = self.uploadvolumeformat |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| success = False |
| try: |
| self.apiclient.getUploadParamsForVolume(cmd) |
| except Exception as ex: |
| if "Invalid Parameter" in str(ex): |
| success = True |
| self.assertEqual( |
| success, |
| True, |
| "Upload Volume - verify upload volume API request is handled without mandatory params - zoneid ") |
| |
| return |
| |
| def browse_upload_volume_with_out_format(self): |
| |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| success = False |
| try: |
| self.apiclient.getUploadParamsForVolume(cmd) |
| except Exception as ex: |
| if "Invalid Parameter" in str(ex): |
| success = True |
| self.assertEqual( |
| success, |
| True, |
| "Upload Volume - verify upload volume API request is handled without mandatory params - format") |
| |
| return |
| |
| def browse_upload_volume(self): |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.format = self.uploadvolumeformat |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| cmd.account = self.account.name |
| cmd.domainid = self.domain.id |
| getuploadparamsresponse = self.apiclient.getUploadParamsForVolume(cmd) |
| |
| signt = getuploadparamsresponse.signature |
| posturl = getuploadparamsresponse.postURL |
| metadata = getuploadparamsresponse.metadata |
| expiredata = getuploadparamsresponse.expires |
| self.globalurl = getuploadparamsresponse.postURL |
| # url = 'http://10.147.28.7/templates/rajani-thin-volume.vhd' |
| url = self.uploadurl |
| |
| uploadfile = url.split('/')[-1] |
| r = requests.get(url, stream=True) |
| with open(uploadfile, 'wb') as f: |
| for chunk in r.iter_content(chunk_size=1024): |
| if chunk: # filter out keep-alive new chunks |
| f.write(chunk) |
| f.flush() |
| |
| files = {'file': (uploadfile, open(uploadfile, 'rb'), 'application/octet-stream')} |
| |
| headers = {'x-signature': signt, 'x-metadata': metadata, 'x-expires': expiredata} |
| |
| results = requests.post(posturl, files=files, headers=headers, verify=False) |
| |
| print(results.status_code) |
| if results.status_code != 200: |
| self.fail("Upload is not fine") |
| |
| self.validate_uploaded_volume(getuploadparamsresponse.id, 'Uploaded') |
| |
| return (getuploadparamsresponse) |
| |
| def onlyupload(self): |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.format = self.uploadvolumeformat |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| cmd.account = self.account.name |
| cmd.domainid = self.domain.id |
| getuploadparamsresponse = self.apiclient.getUploadParamsForVolume(cmd) |
| return (getuploadparamsresponse) |
| |
| def invalidupload(self): |
| |
| success = False |
| try: |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.format = "invalidformat" |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| cmd.account = self.account.name |
| cmd.domainid = self.domain.id |
| self.apiclient.getUploadParamsForVolume(cmd) |
| |
| except Exception as ex: |
| if "No enum constant com.cloud.storage.Storage.ImageFormat" in str(ex): |
| success = True |
| self.assertEqual( |
| success, |
| True, |
| "Verify - Upload volume with invalid format is handled") |
| |
| return |
| |
| def invalidposturl(self): |
| |
| success = False |
| try: |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.format = self.uploadvolumeformat |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| cmd.account = self.account.name |
| cmd.domainid = self.domain.id |
| getuploadparamsresponse = self.apiclient.getUploadParamsForVolume(cmd) |
| |
| signt = getuploadparamsresponse.signature |
| posturl = "http://invalidposturl/2999834." + self.uploadvolumeformat |
| metadata = getuploadparamsresponse.metadata |
| expiredata = getuploadparamsresponse.expires |
| # url = 'http://10.147.28.7/templates/rajani-thin-volume.vhd' |
| url = self.uploadurl |
| |
| uploadfile = url.split('/')[-1] |
| r = requests.get(url, stream=True) |
| with open(uploadfile, 'wb') as f: |
| for chunk in r.iter_content(chunk_size=1024): |
| if chunk: # filter out keep-alive new chunks |
| f.write(chunk) |
| f.flush() |
| |
| files = {'file': (uploadfile, open(uploadfile, 'rb'), 'application/octet-stream')} |
| |
| headers = {'x-signature': signt, 'x-metadata': metadata, 'x-expires': expiredata} |
| |
| results = requests.post(posturl, files=files, headers=headers, verify=False) |
| |
| self.debug(results.status_code) |
| if results.status_code != 200: |
| self.fail("Upload is not fine") |
| |
| self.validate_uploaded_volume(getuploadparamsresponse.id, 'UploadedAbandoned') |
| |
| except Exception as ex: |
| if "Max retries exceeded with url" in str(ex): |
| success = True |
| |
| self.assertEqual( |
| success, |
| True, |
| "Verify - Tampered Post URL is handled") |
| |
| return (getuploadparamsresponse) |
| |
| def reuse_url(self): |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.format = self.uploadvolumeformat |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| cmd.account = self.account.name |
| cmd.domainid = self.domain.id |
| getuploadparamsresponse = self.apiclient.getUploadParamsForVolume(cmd) |
| |
| signt = getuploadparamsresponse.signature |
| posturl = self.globalurl |
| metadata = getuploadparamsresponse.metadata |
| expiredata = getuploadparamsresponse.expires |
| url = self.uploadurl |
| time.sleep(300) |
| |
| uploadfile = url.split('/')[-1] |
| r = requests.get(url, stream=True) |
| with open(uploadfile, 'wb') as f: |
| for chunk in r.iter_content(chunk_size=1024): |
| if chunk: # filter out keep-alive new chunks |
| f.write(chunk) |
| f.flush() |
| |
| files = {'file': (uploadfile, open(uploadfile, 'rb'), 'application/octet-stream')} |
| |
| headers = {'x-signature': signt, 'x-metadata': metadata, 'x-expires': expiredata} |
| |
| results = requests.post(posturl, files=files, headers=headers, verify=False) |
| time.sleep(60) |
| |
| if results.status_code == 200: |
| self.fail("Upload URL is allowed to reuse") |
| |
| config = Configurations.list( |
| self.apiclient, |
| name='upload.operation.timeout' |
| ) |
| |
| uploadtimeout = int(config[0].value) |
| time.sleep(uploadtimeout * 60) |
| self.validate_uploaded_volume(getuploadparamsresponse.id, 'UploadAbandoned') |
| return |
| |
| def validate_storage_cleanup(self, invalidpostvolume, cleanup_interval): |
| |
| list_volume_response = Volume.list( |
| self.apiclient, |
| id=invalidpostvolume.id |
| ) |
| self.assertNotEqual( |
| list_volume_response, |
| None, |
| "Check if volume exists in ListVolumes" |
| ) |
| |
| config1 = Configurations.list( |
| self.apiclient, |
| name='upload.operation.timeout' |
| ) |
| config2 = Configurations.list( |
| self.apiclient, |
| name='upload.monitoring.interval' |
| ) |
| uploadtimeout = int(config1[0].value) |
| monitorinterval = int(config2[0].value) |
| |
| if cleanup_interval >= ((uploadtimeout * 60) + monitorinterval): |
| time.sleep(cleanup_interval) |
| else: |
| time.sleep(((uploadtimeout * 60) + monitorinterval)) |
| |
| list_volume_response = Volume.list( |
| self.apiclient, |
| id=invalidpostvolume.id |
| ) |
| self.assertEqual( |
| list_volume_response, |
| None, |
| "Storage Cleanup - Verify UploadAbandoned volumes are deleted" |
| ) |
| |
| def validate_max_vol_size(self, up_vol, volumestate): |
| |
| list_volume_response = Volume.list( |
| self.apiclient, |
| id=up_vol.id |
| ) |
| self.assertNotEqual( |
| list_volume_response, |
| None, |
| "Check if volume exists in ListVolumes" |
| ) |
| |
| self.assertEqual( |
| list_volume_response[0].state, |
| volumestate, |
| "Check volume state in ListVolumes" |
| ) |
| |
| config = Configurations.list( |
| self.apiclient, |
| name='storage.max.volume.upload.size' |
| ) |
| |
| max_size = int(config[0].value) |
| self.debug(max_size) |
| self.debug(int(list_volume_response[0].size) / (1024 * 1024 * 1024)) |
| if (int(list_volume_response[0].size) / (1024 * 1024 * 1024)) > max_size: |
| self.fail("Global Config storage.max.volume.upload.size is not considered with Browser Based Upload volumes") |
| |
| def browse_upload_volume_with_md5(self): |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.format = self.uploadvolumeformat |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| cmd.account = self.account.name |
| cmd.domainid = self.domain.id |
| cmd.checksum = self.md5sum |
| getuploadparamsresponse = self.apiclient.getUploadParamsForVolume(cmd) |
| |
| signt = getuploadparamsresponse.signature |
| posturl = getuploadparamsresponse.postURL |
| metadata = getuploadparamsresponse.metadata |
| expiredata = getuploadparamsresponse.expires |
| # url = 'http://10.147.28.7/templates/rajani-thin-volume.vhd' |
| url = self.uploadurl |
| |
| uploadfile = url.split('/')[-1] |
| r = requests.get(url, stream=True) |
| with open(uploadfile, 'wb') as f: |
| for chunk in r.iter_content(chunk_size=1024): |
| if chunk: # filter out keep-alive new chunks |
| f.write(chunk) |
| f.flush() |
| |
| # uploadfile='rajani-thin-volume.vhd' |
| |
| # files={'file':('rajani-thin-volume.vhd',open(uploadfile,'rb'),'application/octet-stream')} |
| |
| # headers={'x-signature':signt,'x-metadata':metadata,'x-expires':expiredata} |
| |
| files = {'file': (uploadfile, open(uploadfile, 'rb'), 'application/octet-stream')} |
| |
| headers = {'x-signature': signt, 'x-metadata': metadata, 'x-expires': expiredata} |
| |
| results = requests.post(posturl, files=files, headers=headers, verify=False) |
| time.sleep(60) |
| |
| if results.status_code != 200: |
| self.fail("Upload is not fine") |
| |
| self.validate_uploaded_volume(getuploadparamsresponse.id, 'Uploaded') |
| |
| return (getuploadparamsresponse) |
| |
| def browse_upload_volume_with_invalid_md5(self): |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.format = self.uploadvolumeformat |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| cmd.account = self.account.name |
| cmd.domainid = self.domain.id |
| cmd.checksum = "xxxxxxxx" |
| getuploadparamsresponse = self.apiclient.getUploadParamsForVolume(cmd) |
| |
| signt = getuploadparamsresponse.signature |
| posturl = getuploadparamsresponse.postURL |
| metadata = getuploadparamsresponse.metadata |
| expiredata = getuploadparamsresponse.expires |
| # url = 'http://10.147.28.7/templates/rajani-thin-volume.vhd' |
| url = self.uploadurl |
| |
| uploadfile = url.split('/')[-1] |
| r = requests.get(url, stream=True) |
| with open(uploadfile, 'wb') as f: |
| for chunk in r.iter_content(chunk_size=1024): |
| if chunk: # filter out keep-alive new chunks |
| f.write(chunk) |
| f.flush() |
| |
| # uploadfile='rajani-thin-volume.vhd' |
| |
| # files={'file':('rajani-thin-volume.vhd',open(uploadfile,'rb'),'application/octet-stream')} |
| |
| # headers={'x-signature':signt,'x-metadata':metadata,'x-expires':expiredata} |
| |
| files = {'file': (uploadfile, open(uploadfile, 'rb'), 'application/octet-stream')} |
| |
| headers = {'x-signature': signt, 'x-metadata': metadata, 'x-expires': expiredata} |
| |
| results = requests.post(posturl, files=files, headers=headers, verify=False) |
| time.sleep(60) |
| |
| print(results.status_code) |
| if results.status_code != 200: |
| self.fail("Upload is not fine") |
| |
| self.validate_uploaded_volume(getuploadparamsresponse.id, 'Uploaded') |
| |
| return (getuploadparamsresponse) |
| |
| def validate_vm(self, vmdetails, vmstate): |
| |
| time.sleep(120) |
| vm_response = VirtualMachine.list( |
| self.apiclient, |
| id=vmdetails.id, |
| ) |
| self.assertEqual( |
| isinstance(vm_response, list), |
| True, |
| "Check list VM response for valid list" |
| ) |
| |
| # Verify VM response to check whether VM deployment was successful |
| self.assertNotEqual( |
| len(vm_response), |
| 0, |
| "Check VMs available in List VMs response" |
| ) |
| |
| deployedvm = vm_response[0] |
| self.assertEqual( |
| deployedvm.state, |
| vmstate, |
| "Check the state of VM" |
| ) |
| |
| def deploy_vm(self): |
| virtual_machine = VirtualMachine.create( |
| self.apiclient, |
| self.testdata["virtual_machine"], |
| templateid=self.template.id, |
| zoneid=self.zone.id, |
| accountid=self.account.name, |
| domainid=self.account.domainid, |
| serviceofferingid=self.service_offering.id, |
| ) |
| self.validate_vm(virtual_machine, 'Running') |
| return (virtual_machine) |
| |
| def attach_volume(self, vmlist, volid): |
| |
| list_volume_response = Volume.list( |
| self.apiclient, |
| id=volid |
| ) |
| print(list_volume_response[0]) |
| vmlist.attach_volume( |
| self.apiclient, |
| list_volume_response[0] |
| ) |
| list_volume_response = Volume.list( |
| self.apiclient, |
| virtualmachineid=vmlist.id, |
| type='DATADISK', |
| listall=True |
| ) |
| self.assertNotEqual( |
| list_volume_response, |
| None, |
| "Check if volume exists in ListVolumes") |
| self.assertEqual( |
| isinstance(list_volume_response, list), |
| True, |
| "Check list volumes response for valid list") |
| self.validate_uploaded_volume(volid, 'Ready') |
| |
| def attach_deleted_volume(self, vmlist, volume): |
| |
| success = False |
| try: |
| vmlist.attach_volume( |
| self.apiclient, |
| volume |
| ) |
| except Exception as ex: |
| if "Please specify a volume with the valid type: DATADISK" in str(ex): |
| success = True |
| self.assertEqual( |
| success, |
| True, |
| "Attaching the Deleted Volume is handled appropriately not to get attached the deleted uploaded volume") |
| |
| return |
| |
| def reboot_vm(self, vmdetails): |
| vmdetails.reboot(self.apiclient) |
| self.validate_vm(vmdetails, 'Running') |
| |
| def stop_vm(self, vmdetails): |
| vmdetails.stop(self.apiclient) |
| self.validate_vm(vmdetails, 'Stopped') |
| |
| def start_vm(self, vmdetails): |
| vmdetails.start(self.apiclient) |
| self.validate_vm(vmdetails, 'Running') |
| |
| def vmoperations(self, vmdetails): |
| self.reboot_vm(vmdetails) |
| |
| self.stop_vm(vmdetails) |
| |
| self.start_vm(vmdetails) |
| |
| def detach_volume(self, vmdetails, volid): |
| """Detach a Volume attached to a VM |
| """ |
| list_volume_response = Volume.list( |
| self.apiclient, |
| id=volid |
| ) |
| vmdetails.detach_volume(self.apiclient, list_volume_response[0]) |
| |
| # Sleep to ensure the current state will reflected in other calls |
| time.sleep(self.testdata["sleep"]) |
| |
| list_volume_response = Volume.list( |
| self.apiclient, |
| id=volid |
| ) |
| self.assertNotEqual( |
| list_volume_response, |
| None, |
| "Check if volume exists in ListVolumes" |
| ) |
| self.assertEqual( |
| isinstance(list_volume_response, list), |
| True, |
| "Check list volumes response for valid list" |
| ) |
| volume = list_volume_response[0] |
| self.assertEqual( |
| volume.virtualmachineid, |
| None, |
| "Check if volume state (detached) is reflected" |
| ) |
| |
| self.assertEqual( |
| volume.vmname, |
| None, |
| "Check if volume state (detached) is reflected" |
| ) |
| return |
| |
| def restore_vm(self, vmdetails): |
| # TODO: SIMENH: add another test the data on the restored VM. |
| """Test recover Virtual Machine |
| """ |
| |
| # cmd = recoverVirtualMachine.recoverVirtualMachineCmd() |
| cmd = restoreVirtualMachine.restoreVirtualMachineCmd() |
| cmd.virtualmachineid = vmdetails.id |
| self.apiclient.recoverVirtualMachine(cmd) |
| |
| list_vm_response = VirtualMachine.list( |
| self.apiclient, |
| id=vmdetails.id |
| ) |
| self.assertEqual( |
| isinstance(list_vm_response, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| |
| self.assertNotEqual( |
| len(list_vm_response), |
| 0, |
| "Check VM available in List Virtual Machines" |
| ) |
| |
| self.assertEqual( |
| list_vm_response[0].state, |
| "Running", |
| "Check virtual machine is in Running state" |
| ) |
| |
| return |
| |
| def deletevolume_fail(self, volumeid): |
| """Delete a Volume attached to a VM |
| """ |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = volumeid |
| success = False |
| try: |
| self.apiclient.deleteVolume(cmd) |
| except Exception as ex: |
| if "Please specify a volume that is not attached to any VM" in str(ex): |
| success = True |
| self.assertEqual( |
| success, |
| True, |
| "DeleteVolume - verify Ready State volume (attached to a VM) is handled appropriately not to get deleted ") |
| |
| return |
| |
| def delete_volume(self, volumeid): |
| """Delete a Volume attached to a VM |
| """ |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = volumeid |
| |
| self.apiclient.deleteVolume(cmd) |
| |
| def download_volume(self, volumeid): |
| |
| cmd = extractVolume.extractVolumeCmd() |
| cmd.id = volumeid |
| cmd.mode = "HTTP_DOWNLOAD" |
| cmd.zoneid = self.zone.id |
| extract_vol = self.apiclient.extractVolume(cmd) |
| |
| try: |
| formatted_url = urllib.parse.unquote_plus(extract_vol.url) |
| self.debug("Attempting to download volume at url %s" % formatted_url) |
| response = urllib.request.urlopen(formatted_url) |
| self.debug("response from volume url %s" % response.getcode()) |
| fd, path = tempfile.mkstemp() |
| self.debug("Saving volume %s to path %s" % (volumeid, path)) |
| os.close(fd) |
| with open(path, 'wb') as fd: |
| fd.write(response.read()) |
| self.debug("Saved volume successfully") |
| except Exception: |
| self.fail( |
| "Extract Volume Failed with invalid URL %s (vol id: %s)" \ |
| % (extract_vol.url, volumeid) |
| ) |
| |
| def resize_fail(self, volumeid): |
| |
| cmd = resizeVolume.resizeVolumeCmd() |
| cmd.id = volumeid |
| cmd.diskofferingid = self.disk_offering.id |
| success = False |
| try: |
| self.apiclient.resizeVolume(cmd) |
| except Exception as ex: |
| if "Volume should be in ready or allocated state before attempting a resize" in str(ex): |
| success = True |
| self.assertEqual( |
| success, |
| True, |
| "ResizeVolume - verify Uploaded State volume is handled appropriately") |
| |
| def resize_volume(self, volumeid): |
| |
| """Test resize a volume""" |
| |
| self.testdata["configurableData"]["browser_upload_volume"]["browser_resized_disk_offering"]["disksize"] = 20 |
| |
| disk_offering_20_GB = DiskOffering.create( |
| self.apiclient, |
| self.testdata["configurableData"]["browser_upload_volume"]["browser_resized_disk_offering"] |
| ) |
| self.cleanup.append(disk_offering_20_GB) |
| |
| cmd = resizeVolume.resizeVolumeCmd() |
| cmd.id = volumeid |
| cmd.diskofferingid = disk_offering_20_GB.id |
| |
| self.apiclient.resizeVolume(cmd) |
| |
| count = 0 |
| success = False |
| while count < 3: |
| list_volume_response = Volume.list( |
| self.apiclient, |
| id=volumeid, |
| type='DATADISK' |
| ) |
| for vol in list_volume_response: |
| if vol.id == volumeid and int(vol.size) == (int(disk_offering_20_GB.disksize) * (1024 ** 3)) and vol.state == 'Ready': |
| success = True |
| if success: |
| break |
| else: |
| time.sleep(10) |
| count += 1 |
| |
| self.assertEqual( |
| success, |
| True, |
| "Check if the data volume resized appropriately" |
| ) |
| |
| return |
| |
| def destroy_vm(self, vmdetails): |
| |
| success = False |
| vmdetails.delete(self.apiclient, expunge=False) |
| |
| try: |
| list_vm_response1 = VirtualMachine.list( |
| self.apiclient, |
| id=vmdetails.id |
| ) |
| except Exception as ex: |
| if "Unable to find a virtual machine with specified vmId" in str(ex): |
| success = True |
| |
| if success == "True": |
| self.debug("VM is already expunged") |
| return |
| |
| list_vm_response1 = VirtualMachine.list( |
| self.apiclient, |
| id=vmdetails.id |
| ) |
| |
| if list_vm_response1 is None: |
| self.debug("VM already expunged") |
| return |
| |
| if list_vm_response1[0].state == "Expunging": |
| self.debug("VM already getting expunged") |
| return |
| |
| list_vm_response = VirtualMachine.list( |
| self.apiclient, |
| id=vmdetails.id |
| ) |
| if list_vm_response is None: |
| self.debug("VM already expunged") |
| return |
| |
| self.assertEqual( |
| isinstance(list_vm_response, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| |
| self.assertNotEqual( |
| len(list_vm_response), |
| 0, |
| "Check VM available in List Virtual Machines" |
| ) |
| |
| self.assertEqual( |
| list_vm_response[0].state, |
| "Destroyed", |
| "Check virtual machine is in destroyed state" |
| ) |
| return |
| |
| def recover_destroyed_vm(self, vmdetails): |
| |
| list_vm_response1 = VirtualMachine.list( |
| self.apiclient, |
| id=vmdetails.id |
| ) |
| if list_vm_response1 is None: |
| self.debug("VM already expunged") |
| return |
| |
| cmd = recoverVirtualMachine.recoverVirtualMachineCmd() |
| cmd.id = vmdetails.id |
| self.apiclient.recoverVirtualMachine(cmd) |
| |
| list_vm_response1 = VirtualMachine.list( |
| self.apiclient, |
| id=vmdetails.id |
| ) |
| if list_vm_response1 is None: |
| self.debug("VM already expunged") |
| return |
| |
| list_vm_response1 = VirtualMachine.list( |
| self.apiclient, |
| id=vmdetails.id |
| ) |
| if list_vm_response1[0].state == "Expunging": |
| self.debug("VM already getting expunged") |
| return |
| |
| list_vm_response = VirtualMachine.list( |
| self.apiclient, |
| id=vmdetails.id |
| ) |
| self.assertEqual( |
| isinstance(list_vm_response, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| |
| self.assertNotEqual( |
| len(list_vm_response), |
| 0, |
| "Check VM available in List Virtual Machines" |
| ) |
| |
| self.assertEqual( |
| list_vm_response[0].state, |
| "Stopped", |
| "Check virtual machine is in Stopped state" |
| ) |
| |
| return |
| |
| def expunge_vm(self, vmdetails): |
| |
| self.debug("Expunge VM-ID: %s" % vmdetails.id) |
| |
| cmd = destroyVirtualMachine.destroyVirtualMachineCmd() |
| cmd.id = vmdetails.id |
| self.apiclient.destroyVirtualMachine(cmd) |
| |
| config = Configurations.list( |
| self.apiclient, |
| name='expunge.delay' |
| ) |
| |
| expunge_delay = int(config[0].value) |
| time.sleep(expunge_delay * 2) |
| |
| # VM should be destroyed unless expunge thread hasn't run |
| # Wait for two cycles of the expunge thread |
| config = Configurations.list( |
| self.apiclient, |
| name='expunge.interval' |
| ) |
| expunge_cycle = int(config[0].value) |
| wait_time = expunge_cycle * 4 |
| while wait_time >= 0: |
| list_vm_response = VirtualMachine.list( |
| self.apiclient, |
| id=vmdetails.id |
| ) |
| if not list_vm_response: |
| break |
| self.debug("Waiting for VM to expunge") |
| time.sleep(expunge_cycle) |
| wait_time = wait_time - expunge_cycle |
| |
| self.debug("listVirtualMachines response: %s" % list_vm_response) |
| |
| self.assertEqual(list_vm_response, None, "Check Expunged virtual machine is in listVirtualMachines response") |
| return |
| |
| def volume_snapshot(self, volumedetails): |
| """ |
| @summary: Test to verify creation of snapshot from volume |
| and creation of template, volume from snapshot |
| """ |
| |
| if self.uploadvolumeformat == "QCOW2": |
| config = Configurations.list( |
| self.apiclient, |
| name='kvm.snapshot.enabled' |
| ) |
| kvmsnapshotenabled = config[0].value |
| if kvmsnapshotenabled == "false": |
| self.fail("Please enable kvm.snapshot.enable global config") |
| list_volumes = Volume.list( |
| self.apiclient, |
| id=volumedetails.id |
| ) |
| # Creating Snapshot from volume |
| snapshot_created = Snapshot.create( |
| self.apiclient, |
| volumedetails.id, |
| ) |
| |
| self.assertIsNotNone(snapshot_created, "Snapshot not created") |
| |
| self.cleanup.append(snapshot_created) |
| |
| # Creating expected and actual values dictionaries |
| expected_dict = { |
| "id": volumedetails.id, |
| "intervaltype": "MANUAL", |
| "snapshottype": "MANUAL", |
| "volumetype": list_volumes[0].type, |
| "domain": self.domain.id |
| } |
| actual_dict = { |
| "id": snapshot_created.volumeid, |
| "intervaltype": snapshot_created.intervaltype, |
| "snapshottype": snapshot_created.snapshottype, |
| "volumetype": snapshot_created.volumetype, |
| "domain": snapshot_created.domainid, |
| } |
| status = self.__verify_values( |
| expected_dict, |
| actual_dict |
| ) |
| self.assertEqual( |
| True, |
| status, |
| "Snapshot created from Volume details are not as expected" |
| ) |
| return (snapshot_created) |
| |
| def volume_snapshot_volume(self, snapshot_created): |
| |
| # Creating Volume from snapshot |
| cmd = createVolume.createVolumeCmd() |
| cmd.name = "-".join([self.testdata["volume"] |
| ["diskname"], random_gen()]) |
| cmd.snapshotid = snapshot_created.id |
| |
| volume_from_snapshot = Volume( |
| self.apiclient.createVolume(cmd).__dict__) |
| |
| self.assertIsNotNone( |
| volume_from_snapshot, |
| "Volume creation failed from snapshot" |
| ) |
| |
| return |
| |
| def volume_snapshot_template(self, snapshot_created): |
| # Creating Template from Snapshot |
| list_templates_before = Template.list( |
| self.apiclient, |
| templatefilter='self') |
| |
| if list_templates_before is None: |
| templates_before_size = 0 |
| else: |
| templates_before_size = len(list_templates_before) |
| |
| cmd = createTemplate.createTemplateCmd() |
| cmd.name = self.testdata["ostype"] |
| cmd.displaytext = self.testdata["ostype"] |
| cmd.ostypeid = self.template.ostypeid |
| cmd.snapshotid = snapshot_created.id |
| cmd.ispublic = False |
| cmd.passwordenabled = False |
| |
| template_from_snapshot = Template( |
| self.apiclient.createTemplate(cmd).__dict__) |
| |
| self.assertIsNotNone( |
| template_from_snapshot, |
| "Template creation failed from snapshot" |
| ) |
| |
| self.cleanup.append(template_from_snapshot) |
| |
| # Creating expected and actual values dictionaries |
| expected_dict = { |
| "name": self.testdata["ostype"], |
| "ostypeid": self.template.ostypeid, |
| "type": "USER", |
| "zone": self.zone.id, |
| "passwordenabled": False, |
| "ispublic": False, |
| "size": self.disk_offering.disksize |
| } |
| actual_dict = { |
| "name": template_from_snapshot.name, |
| "ostypeid": template_from_snapshot.ostypeid, |
| "type": template_from_snapshot.templatetype, |
| "zone": template_from_snapshot.zoneid, |
| "passwordenabled": template_from_snapshot.passwordenabled, |
| "ispublic": template_from_snapshot.ispublic, |
| "size": template_from_snapshot.size / (1024 * 1024 * 1024) |
| } |
| status = self.__verify_values( |
| expected_dict, |
| actual_dict |
| ) |
| # self.assertEqual( |
| # True, |
| # status, |
| # "Template created from Snapshot details are not as expected" |
| # ) |
| |
| list_templates_after = Template.list( |
| self.apiclient, |
| templatefilter='self') |
| |
| self.assertEqual( |
| templates_before_size + 1, |
| len(list_templates_after), |
| "Template creation failed from snapshot" |
| ) |
| return |
| |
| def waitForSystemVMAgent(self, vmname): |
| timeout = self.testdata["timeout"] |
| |
| while True: |
| list_host_response = list_hosts( |
| self.apiclient, |
| name=vmname |
| ) |
| |
| if list_host_response and list_host_response[0].state == 'Up': |
| break |
| |
| if timeout == 0: |
| raise Exception("Timed out waiting for SSVM agent to be Up") |
| |
| time.sleep(self.testdata["sleep"]) |
| timeout = timeout - 1 |
| |
| def ssvm_internals(self): |
| |
| list_ssvm_response = list_ssvms( |
| self.apiclient, |
| systemvmtype='secondarystoragevm', |
| state='Running', |
| zoneid=self.zone.id |
| ) |
| self.assertEqual( |
| isinstance(list_ssvm_response, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| ssvm = list_ssvm_response[0] |
| |
| hosts = list_hosts( |
| self.apiclient, |
| id=ssvm.hostid |
| ) |
| self.assertEqual( |
| isinstance(hosts, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| host = hosts[0] |
| |
| self.debug("Running SSVM check script") |
| |
| if self.hypervisor.lower() in ('vmware', 'hyperv'): |
| # SSH into SSVMs is done via management server for Vmware and Hyper-V |
| result = get_process_status( |
| self.apiclient.connection.mgtSvr, |
| 22, |
| self.apiclient.connection.user, |
| self.apiclient.connection.passwd, |
| ssvm.privateip, |
| "/usr/local/cloud/systemvm/ssvm-check.sh |grep -e ERROR -e WARNING -e FAIL", |
| hypervisor=self.hypervisor |
| ) |
| else: |
| try: |
| host.user, host.passwd = get_host_credentials(self.config, host.ipaddress) |
| result = get_process_status( |
| host.ipaddress, |
| 22, |
| host.user, |
| host.passwd, |
| ssvm.linklocalip, |
| "/usr/local/cloud/systemvm/ssvm-check.sh |grep -e ERROR -e WARNING -e FAIL" |
| ) |
| except KeyError: |
| self.skipTest("Marvin configuration has no host credentials to check router services") |
| res = str(result) |
| self.debug("SSVM script output: %s" % res) |
| |
| self.assertEqual( |
| res.count("ERROR"), |
| 1, |
| "Check for Errors in tests" |
| ) |
| |
| self.assertEqual( |
| res.count("WARNING"), |
| 1, |
| "Check for warnings in tests" |
| ) |
| |
| # Check status of cloud service |
| if self.hypervisor.lower() in ('vmware', 'hyperv'): |
| # SSH into SSVMs is done via management server for Vmware and Hyper-V |
| result = get_process_status( |
| self.apiclient.connection.mgtSvr, |
| 22, |
| self.apiclient.connection.user, |
| self.apiclient.connection.passwd, |
| ssvm.privateip, |
| "systemctl is-active cloud", |
| hypervisor=self.hypervisor |
| ) |
| else: |
| try: |
| host.user, host.passwd = get_host_credentials(self.config, host.ipaddress) |
| result = get_process_status( |
| host.ipaddress, |
| 22, |
| host.user, |
| host.passwd, |
| ssvm.linklocalip, |
| "systemctl is-active cloud" |
| ) |
| except KeyError: |
| self.skipTest("Marvin configuration has no host credentials to check router services") |
| res = str(result) |
| self.debug("Cloud Process status: %s" % res) |
| # Apache CloudStack service (type=secstorage) is running: process id: 2346 |
| self.assertEqual( |
| res.count("active"), |
| 1, |
| "Check cloud service is running or not" |
| ) |
| return |
| |
| def list_sec_storage_vm(self): |
| |
| list_ssvm_response = list_ssvms( |
| self.apiclient, |
| systemvmtype='secondarystoragevm', |
| state='Running', |
| ) |
| self.assertEqual( |
| isinstance(list_ssvm_response, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| # Verify SSVM response |
| self.assertNotEqual( |
| len(list_ssvm_response), |
| 0, |
| "Check list System VMs response" |
| ) |
| |
| list_zones_response = list_zones(self.apiclient) |
| |
| self.assertEqual( |
| isinstance(list_zones_response, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| |
| self.debug("Number of zones: %s" % len(list_zones_response)) |
| self.debug("Number of SSVMs: %s" % len(list_ssvm_response)) |
| # Number of Sec storage VMs = No of Zones |
| self.assertEqual( |
| len(list_ssvm_response), |
| len(list_zones_response), |
| "Check number of SSVMs with number of zones" |
| ) |
| # For each secondary storage VM check private IP, |
| # public IP, link local IP and DNS |
| for ssvm in list_ssvm_response: |
| |
| self.debug("SSVM state: %s" % ssvm.state) |
| self.assertEqual( |
| ssvm.state, |
| 'Running', |
| "Check whether state of SSVM is running" |
| ) |
| |
| self.assertEqual( |
| hasattr(ssvm, 'privateip'), |
| True, |
| "Check whether SSVM has private IP field" |
| ) |
| |
| self.assertEqual( |
| hasattr(ssvm, 'linklocalip'), |
| True, |
| "Check whether SSVM has link local IP field" |
| ) |
| |
| self.assertEqual( |
| hasattr(ssvm, 'publicip'), |
| True, |
| "Check whether SSVM has public IP field" |
| ) |
| |
| # Fetch corresponding ip ranges information from listVlanIpRanges |
| ipranges_response = list_vlan_ipranges( |
| self.apiclient, |
| zoneid=ssvm.zoneid |
| ) |
| self.assertEqual( |
| isinstance(ipranges_response, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| iprange = ipranges_response[0] |
| |
| # Fetch corresponding Physical Network of SSVM's Zone |
| listphyntwk = PhysicalNetwork.list( |
| self.apiclient, |
| zoneid=ssvm.zoneid |
| ) |
| |
| # Execute the following assertion in all zones except EIP-ELB Zones |
| if not (self.zone.networktype.lower() == 'basic' and isinstance(NetScaler.list(self.apiclient, physicalnetworkid=listphyntwk[0].id), list) is True): |
| self.assertEqual( |
| ssvm.gateway, |
| iprange.gateway, |
| "Check gateway with that of corresponding ip range" |
| ) |
| |
| # Fetch corresponding zone information from listZones |
| zone_response = list_zones( |
| self.apiclient, |
| id=ssvm.zoneid |
| ) |
| self.assertEqual( |
| isinstance(zone_response, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| self.assertEqual( |
| ssvm.dns1, |
| zone_response[0].dns1, |
| "Check DNS1 with that of corresponding zone" |
| ) |
| |
| self.assertEqual( |
| ssvm.dns2, |
| zone_response[0].dns2, |
| "Check DNS2 with that of corresponding zone" |
| ) |
| return |
| |
| def stop_ssvm(self): |
| |
| list_ssvm_response = list_ssvms( |
| self.apiclient, |
| systemvmtype='secondarystoragevm', |
| state='Running', |
| zoneid=self.zone.id |
| ) |
| self.assertEqual( |
| isinstance(list_ssvm_response, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| ssvm = list_ssvm_response[0] |
| |
| hosts = list_hosts( |
| self.apiclient, |
| id=ssvm.hostid |
| ) |
| self.assertEqual( |
| isinstance(hosts, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| host = hosts[0] |
| |
| self.debug("Stopping SSVM: %s" % ssvm.id) |
| cmd = stopSystemVm.stopSystemVmCmd() |
| cmd.id = ssvm.id |
| self.apiclient.stopSystemVm(cmd) |
| |
| timeout = self.testdata["timeout"] |
| while True: |
| list_ssvm_response = list_ssvms( |
| self.apiclient, |
| id=ssvm.id |
| ) |
| if isinstance(list_ssvm_response, list): |
| if list_ssvm_response[0].state == 'Running': |
| break |
| if timeout == 0: |
| raise Exception("List SSVM call failed!") |
| |
| time.sleep(self.testdata["sleep"]) |
| timeout = timeout - 1 |
| |
| self.assertEqual( |
| isinstance(list_ssvm_response, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| ssvm_response = list_ssvm_response[0] |
| self.debug("SSVM state after debug: %s" % ssvm_response.state) |
| self.assertEqual( |
| ssvm_response.state, |
| 'Running', |
| "Check whether SSVM is running or not" |
| ) |
| # Wait for the agent to be up |
| self.waitForSystemVMAgent(ssvm_response.name) |
| |
| # Call above tests to ensure SSVM is properly running |
| self.list_sec_storage_vm() |
| |
| def reboot_ssvm(self): |
| |
| list_ssvm_response = list_ssvms( |
| self.apiclient, |
| systemvmtype='secondarystoragevm', |
| state='Running', |
| zoneid=self.zone.id |
| ) |
| |
| self.assertEqual( |
| isinstance(list_ssvm_response, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| |
| ssvm_response = list_ssvm_response[0] |
| |
| hosts = list_hosts( |
| self.apiclient, |
| id=ssvm_response.hostid |
| ) |
| self.assertEqual( |
| isinstance(hosts, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| host = hosts[0] |
| |
| # Store the public & private IP values before reboot |
| old_public_ip = ssvm_response.publicip |
| old_private_ip = ssvm_response.privateip |
| |
| self.debug("Rebooting SSVM: %s" % ssvm_response.id) |
| cmd = rebootSystemVm.rebootSystemVmCmd() |
| cmd.id = ssvm_response.id |
| self.apiclient.rebootSystemVm(cmd) |
| |
| timeout = self.testdata["timeout"] |
| while True: |
| list_ssvm_response = list_ssvms( |
| self.apiclient, |
| id=ssvm_response.id |
| ) |
| if isinstance(list_ssvm_response, list): |
| if list_ssvm_response[0].state == 'Running': |
| break |
| if timeout == 0: |
| raise Exception("List SSVM call failed!") |
| |
| time.sleep(self.testdata["sleep"]) |
| timeout = timeout - 1 |
| |
| ssvm_response = list_ssvm_response[0] |
| self.debug("SSVM State: %s" % ssvm_response.state) |
| self.assertEqual( |
| 'Running', |
| str(ssvm_response.state), |
| "Check whether CPVM is running or not" |
| ) |
| |
| self.assertEqual( |
| ssvm_response.publicip, |
| old_public_ip, |
| "Check Public IP after reboot with that of before reboot" |
| ) |
| |
| self.assertEqual( |
| ssvm_response.privateip, |
| old_private_ip, |
| "Check Private IP after reboot with that of before reboot" |
| ) |
| |
| # Wait for the agent to be up |
| self.waitForSystemVMAgent(ssvm_response.name) |
| |
| return |
| |
| def destroy_ssvm(self): |
| |
| list_ssvm_response = list_ssvms( |
| self.apiclient, |
| systemvmtype='secondarystoragevm', |
| state='Running', |
| zoneid=self.zone.id |
| ) |
| self.assertEqual( |
| isinstance(list_ssvm_response, list), |
| True, |
| "Check list response returns a valid list" |
| ) |
| ssvm_response = list_ssvm_response[0] |
| |
| old_name = ssvm_response.name |
| |
| self.debug("Destroying SSVM: %s" % ssvm_response.id) |
| cmd = destroySystemVm.destroySystemVmCmd() |
| cmd.id = ssvm_response.id |
| self.apiclient.destroySystemVm(cmd) |
| |
| timeout = self.testdata["timeout"] |
| while True: |
| list_ssvm_response = list_ssvms( |
| self.apiclient, |
| zoneid=self.zone.id, |
| systemvmtype='secondarystoragevm' |
| ) |
| if isinstance(list_ssvm_response, list): |
| if list_ssvm_response[0].state == 'Running': |
| break |
| if timeout == 0: |
| raise Exception("List SSVM call failed!") |
| |
| time.sleep(self.testdata["sleep"]) |
| timeout = timeout - 1 |
| |
| ssvm_response = list_ssvm_response[0] |
| |
| # Verify Name, Public IP, Private IP and Link local IP |
| # for newly created SSVM |
| self.assertNotEqual( |
| ssvm_response.name, |
| old_name, |
| "Check SSVM new name with name of destroyed SSVM" |
| ) |
| self.assertEqual( |
| hasattr(ssvm_response, 'privateip'), |
| True, |
| "Check whether SSVM has private IP field" |
| ) |
| |
| self.assertEqual( |
| hasattr(ssvm_response, 'linklocalip'), |
| True, |
| "Check whether SSVM has link local IP field" |
| ) |
| |
| self.assertEqual( |
| hasattr(ssvm_response, 'publicip'), |
| True, |
| "Check whether SSVM has public IP field" |
| ) |
| |
| # Wait for the agent to be up |
| self.waitForSystemVMAgent(ssvm_response.name) |
| |
| return |
| |
| def uploadvol(self, getuploadparamsresponse): |
| |
| signt = getuploadparamsresponse.signature |
| posturl = getuploadparamsresponse.postURL |
| metadata = getuploadparamsresponse.metadata |
| expiredata = getuploadparamsresponse.expires |
| success = False |
| url = self.uploadurl |
| |
| uploadfile = url.split('/')[-1] |
| r = requests.get(url, stream=True) |
| with open(uploadfile, 'wb') as f: |
| for chunk in r.iter_content(chunk_size=1024): |
| if chunk: # filter out keep-alive new chunks |
| f.write(chunk) |
| f.flush() |
| |
| files = {'file': (uploadfile, open(uploadfile, 'rb'), 'application/octet-stream')} |
| |
| headers = {'x-signature': signt, 'x-metadata': metadata, 'x-expires': expiredata} |
| |
| results = requests.post(posturl, files=files, headers=headers, verify=False) |
| list_volume_response = Volume.list( |
| self.apiclient, |
| id=getuploadparamsresponse.id |
| ) |
| self.debug("======================Before SSVM Reboot==================") |
| |
| self.reboot_ssvm() |
| self.debug("======================After SSVM Reboot==================") |
| |
| config = Configurations.list( |
| self.apiclient, |
| name='upload.operation.timeout' |
| ) |
| |
| uploadtimeout = int(config[0].value) |
| time.sleep(uploadtimeout * 60) |
| |
| self.validate_uploaded_volume(getuploadparamsresponse.id, 'UploadAbandoned') |
| |
| return () |
| |
| def uploadvolwithssvmreboot(self, getuploadparamsresponse): |
| |
| signt = getuploadparamsresponse.signature |
| posturl = getuploadparamsresponse.postURL |
| metadata = getuploadparamsresponse.metadata |
| expiredata = getuploadparamsresponse.expires |
| |
| self.debug("======================Before SSVM Reboot==================") |
| list_volume_response = Volume.list( |
| self.apiclient, |
| id=getuploadparamsresponse.id |
| ) |
| |
| self.debug(list_volume_response[0]) |
| self.reboot_ssvm() |
| |
| success = False |
| url = self.uploadurl |
| |
| uploadfile = url.split('/')[-1] |
| r = requests.get(url, stream=True) |
| with open(uploadfile, 'wb') as f: |
| for chunk in r.iter_content(chunk_size=1024): |
| if chunk: # filter out keep-alive new chunks |
| f.write(chunk) |
| f.flush() |
| |
| files = {'file': (uploadfile, open(uploadfile, 'rb'), 'application/octet-stream')} |
| |
| headers = {'x-signature': signt, 'x-metadata': metadata, 'x-expires': expiredata} |
| |
| results = requests.post(posturl, files=files, headers=headers, verify=False) |
| list_volume_response = Volume.list( |
| self.apiclient, |
| id=getuploadparamsresponse.id |
| ) |
| |
| self.debug("======================Upload After SSVM Reboot==================") |
| self.debug(list_volume_response[0]) |
| |
| self.validate_uploaded_volume(getuploadparamsresponse.id, 'Uploaded') |
| |
| return () |
| |
| def uploadwithcustomoffering(self): |
| |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.format = self.uploadvolumeformat |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| cmd.account = self.account.name |
| cmd.domainid = self.domain.id |
| cmd.diskofferingid = self.disk_offering.id |
| getuploadparamsresponse = self.apiclient.getUploadParamsForVolume(cmd) |
| |
| signt = getuploadparamsresponse.signature |
| posturl = getuploadparamsresponse.postURL |
| metadata = getuploadparamsresponse.metadata |
| expiredata = getuploadparamsresponse.expires |
| self.globalurl = getuploadparamsresponse.postURL |
| # url = 'http://10.147.28.7/templates/rajani-thin-volume.vhd' |
| url = self.uploadurl |
| |
| uploadfile = url.split('/')[-1] |
| r = requests.get(url, stream=True) |
| with open(uploadfile, 'wb') as f: |
| for chunk in r.iter_content(chunk_size=1024): |
| if chunk: # filter out keep-alive new chunks |
| f.write(chunk) |
| f.flush() |
| |
| files = {'file': (uploadfile, open(uploadfile, 'rb'), 'application/octet-stream')} |
| |
| headers = {'x-signature': signt, 'x-metadata': metadata, 'x-expires': expiredata} |
| |
| results = requests.post(posturl, files=files, headers=headers, verify=False) |
| |
| print(results.status_code) |
| if results.status_code != 200: |
| self.fail("Upload is not fine") |
| |
| self.validate_uploaded_volume(getuploadparamsresponse.id, 'Uploaded') |
| |
| def uploadwithimagestoreid(self): |
| |
| sscmd = listImageStores.listImageStoresCmd() |
| sscmd.zoneid = self.zone.id |
| sscmdresponse = self.apiclient.listImageStores(sscmd) |
| |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.format = self.uploadvolumeformat |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| cmd.account = self.account.name |
| cmd.domainid = self.domain.id |
| cmd.imagestoreuuid = sscmdresponse[0].id |
| getuploadparamsresponse = self.apiclient.getUploadParamsForVolume(cmd) |
| |
| signt = getuploadparamsresponse.signature |
| posturl = getuploadparamsresponse.postURL |
| metadata = getuploadparamsresponse.metadata |
| expiredata = getuploadparamsresponse.expires |
| self.globalurl = getuploadparamsresponse.postURL |
| # url = 'http://10.147.28.7/templates/rajani-thin-volume.vhd' |
| url = self.uploadurl |
| |
| uploadfile = url.split('/')[-1] |
| r = requests.get(url, stream=True) |
| with open(uploadfile, 'wb') as f: |
| for chunk in r.iter_content(chunk_size=1024): |
| if chunk: # filter out keep-alive new chunks |
| f.write(chunk) |
| f.flush() |
| |
| files = {'file': (uploadfile, open(uploadfile, 'rb'), 'application/octet-stream')} |
| |
| headers = {'x-signature': signt, 'x-metadata': metadata, 'x-expires': expiredata} |
| |
| results = requests.post(posturl, files=files, headers=headers, verify=False) |
| |
| print(results.status_code) |
| if results.status_code != 200: |
| self.fail("Upload is not fine") |
| |
| self.validate_uploaded_volume(getuploadparamsresponse.id, 'Uploaded') |
| |
| def uploadwithsamedisplaytext(self, voldetails): |
| |
| list_volume_response = Volume.list( |
| self.apiclient, |
| id=voldetails.id |
| ) |
| |
| success = True |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.format = self.uploadvolumeformat |
| cmd.name = list_volume_response[0].name |
| cmd.account = self.account.name |
| cmd.domainid = self.domain.id |
| getuploadparamsresponse = self.apiclient.getUploadParamsForVolume(cmd) |
| list_volume_response1 = Volume.list( |
| self.apiclient, |
| id=getuploadparamsresponse.id |
| ) |
| if list_volume_response1[0].name == voldetails.name: |
| success = False |
| |
| self.assertEqual( |
| success, |
| False, |
| "Verify: Upload Multiple volumes with same name is handled") |
| |
| return |
| |
| def uploadvolwithmultissvm(self): |
| |
| ssvmhosts = list_hosts( |
| self.apiclient, |
| type="SecondaryStorageVM" |
| ) |
| self.debug("Total SSVMs are:") |
| self.debug(len(ssvmhosts)) |
| |
| if len(ssvmhosts) == 1: |
| return (1) |
| |
| config = Configurations.list( |
| self.apiclient, |
| name='secstorage.session.max' |
| ) |
| |
| multissvmvalue = int(config[0].value) |
| if multissvmvalue != 1: |
| return (0) |
| |
| browseup_vol = self.browse_upload_volume() |
| |
| vm1details = self.deploy_vm() |
| |
| self.attach_volume(vm1details, browseup_vol.id) |
| |
| self.vmoperations(vm1details) |
| |
| self.destroy_vm(vm1details) |
| |
| self.detach_volume(vm1details, browseup_vol.id) |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = browseup_vol.id |
| self.apiclient.deleteVolume(cmd) |
| |
| return (2) |
| |
| def uploadwithextendedfileextentions(self): |
| |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.format = self.uploadvolumeformat |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| cmd.account = self.account.name |
| cmd.domainid = self.domain.id |
| cmd.diskofferingid = self.disk_offering.id |
| getuploadparamsresponse = self.apiclient.getUploadParamsForVolume(cmd) |
| |
| signt = getuploadparamsresponse.signature |
| posturl = getuploadparamsresponse.postURL |
| metadata = getuploadparamsresponse.metadata |
| expiredata = getuploadparamsresponse.expires |
| |
| # url = 'http://10.147.28.7/templates/rajani-thin-volume.vhd' |
| url = self.extuploadurl |
| |
| uploadfile = url.split('/')[-1] |
| r = requests.get(url, stream=True) |
| with open(uploadfile, 'wb') as f: |
| for chunk in r.iter_content(chunk_size=1024): |
| if chunk: # filter out keep-alive new chunks |
| f.write(chunk) |
| f.flush() |
| |
| files = {'file': (uploadfile, open(uploadfile, 'rb'), 'application/octet-stream')} |
| |
| headers = {'x-signature': signt, 'x-metadata': metadata, 'x-expires': expiredata} |
| |
| results = requests.post(posturl, files=files, headers=headers, verify=False) |
| |
| print(results.status_code) |
| if results.status_code != 200: |
| self.fail("Upload is not fine") |
| |
| self.validate_uploaded_volume(getuploadparamsresponse.id, 'Uploaded') |
| |
| def posturlwithdeletedvolume(self, getuploadparamsresponse): |
| |
| signt = getuploadparamsresponse.signature |
| posturl = getuploadparamsresponse.postURL |
| metadata = getuploadparamsresponse.metadata |
| expiredata = getuploadparamsresponse.expires |
| self.validate_uploaded_volume(getuploadparamsresponse.id, 'UploadAbandoned') |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = getuploadparamsresponse.id |
| |
| self.apiclient.delete_volume(cmd) |
| |
| success = False |
| |
| url = self.extuploadurl |
| |
| uploadfile = url.split('/')[-1] |
| r = requests.get(url, stream=True) |
| with open(uploadfile, 'wb') as f: |
| for chunk in r.iter_content(chunk_size=1024): |
| if chunk: # filter out keep-alive new chunks |
| f.write(chunk) |
| f.flush() |
| |
| files = {'file': (uploadfile, open(uploadfile, 'rb'), 'application/octet-stream')} |
| |
| headers = {'x-signature': signt, 'x-metadata': metadata, 'x-expires': expiredata} |
| |
| results = requests.post(posturl, files=files, headers=headers, verify=False) |
| |
| print(results.status_code) |
| if results.status_code == 200: |
| return ("FAIL") |
| return ("PASS") |
| |
| def volume_migration(self, browseup_vol, vm1details): |
| |
| pools = StoragePool.list( |
| self.apiclient, |
| zoneid=self.zone.id |
| ) |
| if not pools: |
| self.skipTest( |
| "No suitable storage pools found for volume migration.\ |
| Skipping") |
| self.assertEqual( |
| validateList(pools)[0], |
| PASS, |
| "invalid pool response from findStoragePoolsForMigration") |
| pool = pools[0] |
| |
| try: |
| if vm1details is None: |
| Volume.migrate( |
| self.apiclient, |
| volumeid=browseup_vol.id, |
| storageid=pool.id, |
| livemigrate='false' |
| ) |
| else: |
| Volume.migrate( |
| self.apiclient, |
| volumeid=browseup_vol.id, |
| storageid=pool.id, |
| livemigrate='true' |
| ) |
| |
| except Exception as e: |
| self.fail("Volume migration failed with error %s" % e) |
| |
| return |
| |
| def getvolumelimts(self): |
| |
| totalresourcelist = Account.list( |
| self.apiclient, |
| id=self.account.id |
| ) |
| totalvolumes = totalresourcelist[0].volumetotal |
| |
| return (totalvolumes) |
| |
| def getstoragelimts(self, rtype): |
| |
| cmd = updateResourceCount.updateResourceCountCmd() |
| cmd.account = self.account.name |
| cmd.domainid = self.domain.id |
| cmd.resourcetype = rtype |
| |
| response = self.apiclient.updateResourceCount(cmd) |
| |
| totalstorage = response[0].resourcecount |
| |
| return (totalstorage) |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_01_Browser_volume_Life_cycle_tpath(self): |
| """ |
| Test Browser_volume_Life_cycle - This includes upload volume,attach to a VM, write data ,Stop ,Start, Reboot,Reset of a VM, detach,attach back to the VM, delete volumes |
| """ |
| try: |
| |
| self.debug("========================= Test 1: Upload Browser based volume and validate ========================= ") |
| browseup_vol = self.browse_upload_volume() |
| |
| self.debug("========================= Test 2: Deploy a VM , Attach Uploaded Browser based volume and validate VM Operations========================= ") |
| |
| vm1details = self.deploy_vm() |
| |
| self.attach_volume(vm1details, browseup_vol.id) |
| |
| self.vmoperations(vm1details) |
| |
| self.debug("========================= Test 3: Restore VM with Uploaded volume attached========================= ") |
| |
| self.restore_vm(vm1details) |
| |
| self.debug("========================= Test 4: Detach Uploaded volume and validation of VM operations after detach========================= ") |
| |
| self.detach_volume(vm1details, browseup_vol.id) |
| |
| self.vmoperations(vm1details) |
| |
| self.destroy_vm(vm1details) |
| |
| self.debug("========================= Test 5: Deploy New VM,Attach the detached Uploaded volume and validate VM operations after attach========================= ") |
| |
| vm2details = self.deploy_vm() |
| |
| self.attach_volume(vm2details, browseup_vol.id) |
| |
| self.vmoperations(vm2details) |
| |
| self.debug("========================= Test 6: Detach Uploaded volume and resize detached uploaded volume========================= ") |
| |
| self.detach_volume(vm2details, browseup_vol.id) |
| |
| if self.hypervisor.lower() != "hyperv": |
| self.resize_volume(browseup_vol.id) |
| |
| self.debug("========================= Test 7: Attach resized uploaded volume and validate VM operations========================= ") |
| |
| self.attach_volume(vm2details, browseup_vol.id) |
| |
| self.vmoperations(vm2details) |
| self.detach_volume(vm2details, browseup_vol.id) |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = browseup_vol.id |
| self.apiclient.deleteVolume(cmd) |
| |
| self.debug("========================= Test 8: Try resizing uploaded state volume and validate the error scenario========================= ") |
| |
| browseup_vol2 = self.browse_upload_volume() |
| |
| self.resize_fail(browseup_vol2.id) |
| |
| self.debug("========================= Test 9: Attach multiple uploaded volumes to a VM and validate VM operations========================= ") |
| |
| browseup_vol3 = self.browse_upload_volume() |
| |
| self.attach_volume(vm2details, browseup_vol2.id) |
| |
| self.attach_volume(vm2details, browseup_vol3.id) |
| |
| self.vmoperations(vm2details) |
| |
| self.debug("========================= Test 10: Detach and delete uploaded volume========================= ") |
| |
| self.detach_volume(vm2details, browseup_vol2.id) |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = browseup_vol2.id |
| self.apiclient.deleteVolume(cmd) |
| |
| self.debug("========================= Test 11: Detach and download uploaded volume========================= ") |
| |
| self.detach_volume(vm2details, browseup_vol3.id) |
| |
| self.download_volume(browseup_vol3.id) |
| |
| self.debug("========================= Test 12: Delete detached uploaded volume========================= ") |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = browseup_vol3.id |
| self.apiclient.deleteVolume(cmd) |
| |
| self.debug("========================= Deletion of UnUsed VM's after test is complete========================= ") |
| |
| self.expunge_vm(vm2details) |
| |
| self.debug("========================= Test 13: Delete Uploaded State volume========================= ") |
| |
| browseup_vol4 = self.browse_upload_volume() |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = browseup_vol4.id |
| self.apiclient.deleteVolume(cmd) |
| |
| self.debug("========================= Test 14: Destroy VM which has Uploaded volumes attached========================= ") |
| |
| vm4details = self.deploy_vm() |
| |
| newvolumetodestoy_VM = self.browse_upload_volume() |
| |
| self.attach_volume(vm4details, newvolumetodestoy_VM.id) |
| |
| self.destroy_vm(vm4details) |
| |
| self.debug("========================= Test 15: Recover destroyed VM which has Uploaded volumes attached========================= ") |
| |
| self.recover_destroyed_vm(vm4details) |
| self.expunge_vm(vm4details) |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = newvolumetodestoy_VM.id |
| self.apiclient.deleteVolume(cmd) |
| |
| self.debug( |
| "========================= Test 16: Delete attached Uploaded volume which is in ready state and it should not be allowed to delete========================= ") |
| |
| vm5details = self.deploy_vm() |
| browseup_vol5 = self.browse_upload_volume() |
| self.attach_volume(vm5details, browseup_vol5.id) |
| self.deletevolume_fail(browseup_vol5.id) |
| |
| self.debug("========================= Test 17: Create Volume Backup Snapshot uploaded volume attached to the VM========================= ") |
| |
| vm6details = self.deploy_vm() |
| browseup_vol6 = self.browse_upload_volume() |
| |
| self.attach_volume(vm6details, browseup_vol6.id) |
| |
| snapshotdetails = self.volume_snapshot(browseup_vol6) |
| |
| self.debug("========================= Test 18: Create Volume from Backup Snapshot of attached uploaded volume========================= ") |
| |
| self.volume_snapshot_volume(snapshotdetails) |
| |
| self.debug("========================= Test 19: Create template from Backup Snapshot of attached uploaded volume========================= ") |
| self.volume_snapshot_template(snapshotdetails) |
| |
| self.detach_volume(vm6details, browseup_vol6.id) |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = browseup_vol6.id |
| self.apiclient.deleteVolume(cmd) |
| |
| self.expunge_vm(vm6details) |
| |
| self.debug("========================= Test 20: Upload Browser based volume with checksum and validate ========================= ") |
| browseup_vol_withchecksum = self.browse_upload_volume_with_md5() |
| |
| self.debug("========================= Test 21: Deploy a VM , Attach Uploaded Browser based volume with checksum and validate VM Operations========================= ") |
| |
| vm7details = self.deploy_vm() |
| |
| self.attach_volume(vm7details, browseup_vol_withchecksum.id) |
| |
| self.debug("========================= Test 22: Detach Uploaded volume with checksum and validation of VM operations after detach========================= ") |
| |
| self.detach_volume(vm7details, browseup_vol_withchecksum.id) |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = browseup_vol_withchecksum.id |
| |
| self.apiclient.deleteVolume(cmd) |
| |
| self.vmoperations(vm7details) |
| |
| self.expunge_vm(vm7details) |
| |
| |
| except Exception as e: |
| self.fail("Exception occurred : %s" % e) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_02_SSVM_Life_Cycle_With_Browser_Volume_TPath(self): |
| """ |
| Test SSVM_Life_Cycle_With_Browser_Volume_TPath - This includes SSVM life cycle followed by Browser volume upload operations |
| """ |
| try: |
| |
| self.debug("========================= Test 23: Stop and Start SSVM and Perform Browser based volume validations ========================= ") |
| |
| self.stop_ssvm() |
| ssvm1browseup_vol = self.browse_upload_volume() |
| |
| ssvm1vm1details = self.deploy_vm() |
| |
| self.attach_volume(ssvm1vm1details, ssvm1browseup_vol.id) |
| |
| self.vmoperations(ssvm1vm1details) |
| |
| self.detach_volume(ssvm1vm1details, ssvm1browseup_vol.id) |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = ssvm1browseup_vol.id |
| self.apiclient.deleteVolume(cmd) |
| |
| self.expunge_vm(ssvm1vm1details) |
| |
| self.debug("========================= Test 24: Reboot SSVM and Perform Browser based volume validations ========================= ") |
| |
| self.reboot_ssvm() |
| ssvm2browseup_vol = self.browse_upload_volume() |
| |
| ssvm2vm1details = self.deploy_vm() |
| |
| self.attach_volume(ssvm2vm1details, ssvm2browseup_vol.id) |
| |
| self.vmoperations(ssvm2vm1details) |
| |
| self.detach_volume(ssvm2vm1details, ssvm2browseup_vol.id) |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = ssvm2browseup_vol.id |
| self.apiclient.deleteVolume(cmd) |
| |
| self.expunge_vm(ssvm2vm1details) |
| |
| self.debug("========================= Test 25: Reboot SSVM and Perform Browser based volume validations ========================= ") |
| |
| self.destroy_ssvm() |
| ssvm3browseup_vol = self.browse_upload_volume() |
| |
| ssvm3vm1details = self.deploy_vm() |
| |
| self.attach_volume(ssvm3vm1details, ssvm3browseup_vol.id) |
| |
| self.vmoperations(ssvm3vm1details) |
| |
| self.detach_volume(ssvm3vm1details, ssvm3browseup_vol.id) |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = ssvm3browseup_vol.id |
| self.apiclient.deleteVolume(cmd) |
| |
| self.expunge_vm(ssvm3vm1details) |
| |
| except Exception as e: |
| self.fail("Exception occurred : %s" % e) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_03_Browser_Upload_Volume_Global_Config_TPath(self): |
| """ |
| Test Browser_Upload_Volume_Global_Config limits |
| """ |
| try: |
| |
| self.debug("========================= Test 26 Validate Storage.max.upload.size ========================= ") |
| globalconfig_browse_up_vol = self.browse_upload_volume() |
| self.validate_max_vol_size(globalconfig_browse_up_vol, "Uploaded") |
| |
| |
| except Exception as e: |
| self.fail("Exception occurred : %s" % e) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_04_Browser_Upload_Volume_Negative_Scenarios_TPath(self): |
| """ |
| Test Browser_Upload_Volume_Negative_Scenarios |
| """ |
| try: |
| self.debug("========================= Test 27 Reuse the POST URL after expiry time========================= ") |
| reuse_browse_up_vol = self.browse_upload_volume() |
| self.reuse_url() |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = reuse_browse_up_vol.id |
| self.apiclient.deleteVolume(cmd) |
| |
| self.debug("========================= Test 28 Reboot SSVM before upload is completed=========================") |
| browse_up_vol = self.onlyupload() |
| self.uploadvol(browse_up_vol) |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = browse_up_vol.id |
| self.apiclient.deleteVolume(cmd) |
| |
| self.debug("========================= Test 29 Reboot SSVM after getting the upload volume params and before initiating the upload=========================") |
| browse_up_vol = self.onlyupload() |
| self.uploadvolwithssvmreboot(browse_up_vol) |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = reuse_browse_up_vol.id |
| self.apiclient.deleteVolume(cmd) |
| |
| self.debug("========================= Test 30 Attach Deleted Volume=========================") |
| deleted_browse_up_vol = self.browse_upload_volume() |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = deleted_browse_up_vol.id |
| self.apiclient.deleteVolume(cmd) |
| |
| deletedvm1details = self.deploy_vm() |
| self.attach_deleted_volume(deletedvm1details, deleted_browse_up_vol) |
| |
| self.debug("========================= Test 31 Upload Volume with Invalid Format=========================") |
| self.invalidupload() |
| |
| self.debug("========================= Test 32 Upload Mutliple Volumes with same display text=========================") |
| samedisplaytext_browse_up_vol = self.browse_upload_volume() |
| self.uploadwithsamedisplaytext(samedisplaytext_browse_up_vol) |
| |
| self.debug("========================= Test 33 Upload Volume with custom offering id=========================") |
| self.uploadwithcustomoffering() |
| |
| except Exception as e: |
| self.fail("Exception occurred : %s" % e) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_05_Browser_Upload_Volume_MultiSSVM_Scenarios_TPath(self): |
| """ |
| Test Browser_Upload_Volume_MultiSSVM_Scenarios |
| """ |
| try: |
| |
| self.debug("========================= Test 34 Upload volume with Multiple SSVM=========================") |
| |
| testresult = self.uploadvolwithmultissvm() |
| if testresult == 0: |
| raise unittest.SkipTest("secstorage.session.max global config is not set to 1 which means Multiple SSVM's are not present") |
| elif testresult == 1: |
| raise unittest.SkipTest("only one SSVM is present") |
| |
| except Exception as e: |
| self.fail("Exception occurred : %s" % e) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_06_Browser_Upload_Volume_with_extended_file_extensions(self): |
| """ |
| Test Browser_Upload_Volume_with_extended_file_extensions |
| """ |
| |
| try: |
| self.debug("========================= Test 35 Upload volume with extended file extensions=========================") |
| if self.uploadvolumeformat == "OVA": |
| raise unittest.SkipTest("This test is need not be executed on VMWARE") |
| self.uploadwithextendedfileextentions() |
| |
| except Exception as e: |
| self.fail("Exception occurred : %s" % e) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_07_Browser_Upload_Volume_Storage_Cleanup_Config_Validation(self): |
| """ |
| Test Browser_Upload_Volume_Storage_Cleanup_Config_Validation |
| """ |
| self.debug("========================= Test 36 Validate storage.cleanup.enabled and storage.cleanup.interval ========================= ") |
| config1 = Configurations.list( |
| self.apiclient, |
| name='storage.cleanup.enabled' |
| ) |
| |
| config2 = Configurations.list( |
| self.apiclient, |
| name='storage.cleanup.interval' |
| ) |
| |
| cleanup_enabled = config1[0].value |
| cleanup_interval = int(config2[0].value) |
| |
| if cleanup_enabled == "false": |
| raise unittest.SkipTest("storage.cleanup.enabled is not set to true") |
| |
| if cleanup_interval > 600: |
| raise unittest.SkipTest("storage.cleanup.interval is set to wait for more than 10 mins before cleanup. Please reduce the interval to less than 10 mins") |
| |
| invaliduploadvolume = self.invalidposturl() |
| |
| self.validate_storage_cleanup(invaliduploadvolume, cleanup_interval) |
| |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_08_Browser_Upload_Volume_TamperedPostURL(self): |
| """ |
| Test Browser_Upload_Volume_Negative_Scenarios |
| """ |
| try: |
| self.debug("========================= Test 37 Upload Volume with tampered post URL=========================") |
| invaliduploadvolume = self.invalidposturl() |
| |
| except Exception as e: |
| self.fail("Exception occurred : %s" % e) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_09_Browser_Upload_Volume_PostURL_with_Deleted_Uploadvolume_Details(self): |
| """ |
| Test Browser_Upload_Volume_PostURL_with_Deleted_Uploadvolume_Details |
| """ |
| self.debug("========================= Test 38 PostURL_with_Deleted_Upload_Abondaned volume details=========================") |
| browse_up_vol = self.onlyupload() |
| res = self.posturlwithdeletedvolume(browse_up_vol) |
| |
| if res == "FAIL": |
| self.fail("Verify - PostURL_with_Deleted_Uploadvolume_Details ") |
| |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_10_Browser_Upload_Volume_API_with_imagepoolid(self): |
| """ |
| Test Browser_Upload_Volume_API_with_imagepoolid |
| """ |
| self.debug("========================= Test 39 Test Browser_Upload_Volume_API_with_imagepoolid=========================") |
| self.uploadwithimagestoreid() |
| |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_11_migrate_upload_volume(self): |
| """ |
| Test Browser_Upload_Volume_migrate_upload_volume |
| """ |
| self.debug("========================= Test 40 Test Browser_Upload_Volume_Migration=========================") |
| |
| browseup_vol = self.browse_upload_volume() |
| vm1details = self.deploy_vm() |
| self.attach_volume(vm1details, browseup_vol.id) |
| self.volume_migration(browseup_vol, vm1details) |
| self.debug("========================= Test 41 Test VM Operations after Browser_Upload_Volume_Migration=========================") |
| self.vmoperations(vm1details) |
| |
| self.debug("========================= Test 42 Detach Browser_Upload_Volume after Migration and attach to a new VM=========================") |
| self.detach_volume(vm1details, browseup_vol.id) |
| vm2details = self.deploy_vm() |
| self.attach_volume(vm2details, browseup_vol.id) |
| self.vmoperations(vm2details) |
| |
| self.debug("========================= Test 43 Detach Browser_Upload_Volume and Migrate to another storage=========================") |
| |
| self.detach_volume(vm2details, browseup_vol.id) |
| self.volume_migration(browseup_vol, "None") |
| |
| self.debug("========================= Test 44 Attach detached Browser_Upload_Volume after Migration =========================") |
| |
| self.attach_volume(vm2details, browseup_vol.id) |
| self.vmoperations(vm2details) |
| |
| self.debug("========================= Test 45 Detach ,Resize,Attach Browser_Upload_Volume after Migration =========================") |
| |
| self.detach_volume(vm2details, browseup_vol.id) |
| |
| if self.hypervisor.lower() != "hyperv": |
| self.resize_volume(browseup_vol.id) |
| |
| self.attach_volume(vm2details, browseup_vol.id) |
| self.vmoperations(vm2details) |
| |
| self.detach_volume(vm2details, browseup_vol.id) |
| |
| self.cleanup.append(browseup_vol) |
| self.cleanup.append(vm2details) |
| self.cleanup.append(vm1details) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_12_Browser_Upload_Volume_with_all_API_parameters(self): |
| """ |
| Test Browser_Upload_Volumewith all API parameters |
| """ |
| try: |
| |
| self.debug("========================= Test 46 & 47 Upload volume with account name and domainid========================") |
| |
| browseup_vol1 = self.browse_upload_volume() |
| |
| self.debug("========================= Test 48 Upload volume with projectid========================") |
| browseup_vol2 = self.browse_upload_volume_with_projectid(self.project.id) |
| |
| self.debug("========================= Test 49 Upload volume with out mandatory param zone id ========================") |
| |
| browseup_vol2 = self.browse_upload_volume_with_out_zoneid() |
| |
| self.debug("========================= Test 50 Upload volume with out mandatory param format ========================") |
| |
| browseup_vol3 = self.browse_upload_volume_with_out_format() |
| |
| except Exception as e: |
| self.fail("Exception occurred : %s" % e) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_13_Browser_Upload_Volume_volume_resource_limits(self): |
| """ |
| Test Browser_Upload_Volume Volume Resource limits |
| """ |
| try: |
| |
| self.debug("========================= Test 51 Upload volume and verify volume limits========================") |
| initialvolumelimit = self.getvolumelimts() |
| browseup_vol1 = self.browse_upload_volume() |
| afteruploadvolumelimit = self.getvolumelimts() |
| |
| if int(afteruploadvolumelimit) != (int(initialvolumelimit) + 1): |
| self.fail("Volume Resource Count is not updated") |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = deleted_browse_up_vol1.id |
| self.apiclient.deleteVolume(cmd) |
| |
| |
| except Exception as e: |
| self.fail("Exception occurred : %s" % e) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_14_Browser_Upload_Volume_secondary_storage_resource_limits(self): |
| """ |
| Test Browser_Upload_Volume Secondary Storage Resource limits |
| """ |
| try: |
| |
| self.debug("========================= Test 52 Upload volume and verify secondary storage limits========================") |
| |
| initialsecondarystoragelimit = self.getstoragelimts(11) |
| browseup_vol1 = self.browse_upload_volume() |
| volumedetails = Volume.list( |
| self.apiclient, |
| id=browseup_vol1.id) |
| afteruploadsecondarystoragelimit = self.getstoragelimts(11) |
| |
| if afteruploadsecondarystoragelimit != (initialsecondarystoragelimit + volumedetails[0].size): |
| self.fail("Secondary Storage Resource Count is not updated") |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = deleted_browse_up_vol1.id |
| self.apiclient.deleteVolume(cmd) |
| |
| |
| except Exception as e: |
| self.fail("Exception occurred : %s" % e) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_15_Browser_Upload_Volume_primary_storage_resource_limits(self): |
| """ |
| Test Browser_Upload_Volume Primary Storage Resource limits |
| """ |
| try: |
| |
| self.debug("========================= Test 53 Attach Upload volume and verify primary storage limits========================") |
| |
| initialprimarystoragelimit = self.getstoragelimts(10) |
| browseup_vol1 = self.browse_upload_volume() |
| volumedetails = Volume.list( |
| self.apiclient, |
| id=browseup_vol1.id) |
| afteruploadprimarystoragelimit = self.getstoragelimts(10) |
| |
| if afteruploadprimarystoragelimit != (initialprimarystoragelimit + volumedetails[0].size): |
| self.fail("Primary Storage Resource Count is not updated") |
| |
| except Exception as e: |
| self.fail("Exception occurred : %s" % e) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_16_Browser_Upload_volume_resource_limits_after_deletion(self): |
| """ |
| Test Browser_Upload_Volume resource_limits_after_deletion |
| """ |
| try: |
| self.debug("========================= Test 54 Delete Upload volume and verify volume limits========================") |
| browseup_vol1 = self.browse_upload_volume() |
| initialvolumelimit = self.getvolumelimts() |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = browseup_vol1.id |
| self.apiclient.deleteVolume(cmd) |
| |
| aftervolumelimit = self.getvolumelimts() |
| |
| if aftervolumelimit != (initialvolumelimit - 1): |
| self.fail("Volume Resource Count is not updated after deletion") |
| |
| except Exception as e: |
| self.fail("Exception occurred : %s" % e) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") |
| def test_17_Browser_Upload_Volume_secondary_storage_resource_limits_after_deletion(self): |
| """ |
| Test Browser_Upload_Volume secondary_storage_resource_limits_after_deletion |
| """ |
| try: |
| self.debug("========================= Test 55 Delete Upload volume and secondary storage limits========================") |
| |
| browseup_vol1 = self.browse_upload_volume() |
| |
| volumedetails = Volume.list( |
| self.apiclient, |
| id=browseup_vol1.id) |
| |
| initialuploadsecondarystoragelimit = self.getstoragelimts(11) |
| |
| cmd = deleteVolume.deleteVolumeCmd() |
| cmd.id = browseup_vol1.id |
| self.apiclient.deleteVolume(cmd) |
| |
| afteruploadsecondarystoragelimit = self.getstoragelimts(11) |
| |
| if afteruploadsecondarystoragelimit != (initialuploadsecondarystoragelimit - volumedetails[0].size): |
| self.fail("Secondary Storage Resource Count is not updated after deletion") |
| |
| except Exception as e: |
| self.fail("Exception occurred : %s" % e) |
| return |
| |
| @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="false") |
| def test_browser_upload_volume_incomplete(self): |
| """ |
| Test browser based incomplete volume upload, followed by SSVM destroy. Volume should go to UploadAbandoned/Error state and get cleaned up. |
| """ |
| try: |
| self.debug("========================= Test browser based incomplete volume upload ========================") |
| |
| # Only register volume, without uploading |
| cmd = getUploadParamsForVolume.getUploadParamsForVolumeCmd() |
| cmd.zoneid = self.zone.id |
| cmd.format = self.uploadvolumeformat |
| cmd.name = self.volname + self.account.name + (random.choice(string.ascii_uppercase)) |
| cmd.account = self.account.name |
| cmd.domainid = self.domain.id |
| upload_volume_response = self.apiclient.getUploadParamsForVolume(cmd) |
| |
| # Destroy SSVM, and wait for new one to start |
| self.destroy_ssvm() |
| |
| # Verify that the volume is cleaned up as part of sync-up during new SSVM start |
| self.validate_uploaded_volume(upload_volume_response.id, 'UploadAbandoned') |
| |
| except Exception as e: |
| self.fail("Exceptione occurred : %s" % e) |
| return |
| |
| @classmethod |
| def tearDownClass(self): |
| super(TestBrowseUploadVolume, self).tearDownClass() |
| |
| def setup(self): |
| cleanup = [] |
| |
| def tearDown(self): |
| super(TestBrowseUploadVolume, self).tearDown() |