mirror of https://github.com/apache/cloudstack.git
352 lines
15 KiB
Python
352 lines
15 KiB
Python
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
""" BVT tests for volume snapshot copy functionality
|
|
"""
|
|
# Import Local Modules
|
|
from marvin.cloudstackTestCase import cloudstackTestCase
|
|
from marvin.cloudstackAPI import (createSnapshot,
|
|
deleteSnapshot,
|
|
copySnapshot,
|
|
createVolume,
|
|
createTemplate,
|
|
listOsTypes)
|
|
from marvin.lib.utils import (cleanup_resources,
|
|
random_gen)
|
|
from marvin.lib.base import (Account,
|
|
Zone,
|
|
ServiceOffering,
|
|
DiskOffering,
|
|
VirtualMachine,
|
|
Volume,
|
|
Snapshot,
|
|
Template)
|
|
from marvin.lib.common import (get_domain,
|
|
get_zone,
|
|
get_template)
|
|
from marvin.lib.decoratorGenerators import skipTestIf
|
|
from marvin.codes import FAILED, PASS
|
|
from nose.plugins.attrib import attr
|
|
import logging
|
|
# Import System modules
|
|
import math
|
|
|
|
|
|
_multiprocess_shared_ = True
|
|
|
|
|
|
class TestSnapshotCopy(cloudstackTestCase):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
testClient = super(TestSnapshotCopy, cls).getClsTestClient()
|
|
cls.apiclient = testClient.getApiClient()
|
|
cls.services = testClient.getParsedTestDataConfig()
|
|
|
|
# Get Zone, Domain and templates
|
|
cls.domain = get_domain(cls.apiclient)
|
|
cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
|
|
cls.services['mode'] = cls.zone.networktype
|
|
|
|
cls._cleanup = []
|
|
cls.logger = logging.getLogger('TestSnapshotCopy')
|
|
cls.testsNotSupported = False
|
|
cls.zones = Zone.list(cls.apiclient)
|
|
enabled_core_zones = []
|
|
if not isinstance(cls.zones, list):
|
|
cls.testsNotSupported = True
|
|
elif len(cls.zones) < 2:
|
|
cls.testsNotSupported = True
|
|
else:
|
|
for z in cls.zones:
|
|
if z.type == 'Core' and z.allocationstate == 'Enabled':
|
|
enabled_core_zones.append(z)
|
|
if len(enabled_core_zones) < 2:
|
|
cls.testsNotSupported = True
|
|
|
|
if cls.testsNotSupported == True:
|
|
self.logger.info("Unsupported")
|
|
return
|
|
|
|
cls.additional_zone = None
|
|
for z in enabled_core_zones:
|
|
if z.id != cls.zone.id:
|
|
cls.additional_zone = z
|
|
|
|
template = get_template(
|
|
cls.apiclient,
|
|
cls.zone.id,
|
|
cls.services["ostype"])
|
|
if template == FAILED:
|
|
assert False, "get_template() failed to return template with description %s" % cls.services["ostype"]
|
|
|
|
# Set Zones and disk offerings
|
|
cls.services["small"]["zoneid"] = cls.zone.id
|
|
cls.services["small"]["template"] = template.id
|
|
cls.services["iso"]["zoneid"] = cls.zone.id
|
|
|
|
cls.account = Account.create(
|
|
cls.apiclient,
|
|
cls.services["account"],
|
|
domainid=cls.domain.id)
|
|
cls._cleanup.append(cls.account)
|
|
|
|
compute_offering_service = cls.services["service_offerings"]["tiny"].copy()
|
|
cls.service_offering = ServiceOffering.create(
|
|
cls.apiclient,
|
|
compute_offering_service)
|
|
cls._cleanup.append(cls.service_offering)
|
|
cls.services["virtual_machine"]["zoneid"] = cls.zone.id
|
|
cls.services["virtual_machine"]["template"] = template.id
|
|
cls.virtual_machine = VirtualMachine.create(
|
|
cls.apiclient,
|
|
cls.services["virtual_machine"],
|
|
accountid=cls.account.name,
|
|
domainid=cls.account.domainid,
|
|
serviceofferingid=cls.service_offering.id,
|
|
mode=cls.services["mode"]
|
|
)
|
|
cls._cleanup.append(cls.virtual_machine)
|
|
cls.volume = Volume.list(
|
|
cls.apiclient,
|
|
virtualmachineid=cls.virtual_machine.id,
|
|
type='ROOT',
|
|
listall=True
|
|
)[0]
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
super(TestSnapshotCopy, cls).tearDownClass()
|
|
|
|
def setUp(self):
|
|
self.apiclient = self.testClient.getApiClient()
|
|
self.userapiclient = self.testClient.getUserApiClient(
|
|
UserName=self.account.name,
|
|
DomainName=self.account.domain
|
|
)
|
|
self.dbclient = self.testClient.getDbConnection()
|
|
self.snapshot_id = None
|
|
self.cleanup = []
|
|
|
|
def tearDown(self):
|
|
super(TestSnapshotCopy, self).tearDown()
|
|
|
|
def create_snapshot(self, apiclient, zoneids):
|
|
cmd = createSnapshot.createSnapshotCmd()
|
|
cmd.volumeid = self.volume.id
|
|
cmd.account = self.account.name
|
|
cmd.domainid = self.account.domainid
|
|
if zoneids:
|
|
cmd.zoneids = zoneids
|
|
snapshot = Snapshot(apiclient.createSnapshot(cmd).__dict__)
|
|
self.cleanup.append(snapshot)
|
|
return snapshot
|
|
|
|
def delete_snapshot(self, apiclient, snapshot_id, zone_id=None):
|
|
cmd = deleteSnapshot.deleteSnapshotCmd()
|
|
cmd.id = snapshot_id
|
|
if zone_id:
|
|
cmd.zoneid = zone_id
|
|
apiclient.deleteSnapshot(cmd)
|
|
|
|
def copy_snapshot(self, apiclient, snapshot_id, zone_ids, source_zone_id=None):
|
|
cmd = copySnapshot.copySnapshotCmd()
|
|
cmd.id = snapshot_id
|
|
cmd.destzoneids = zone_ids
|
|
if source_zone_id:
|
|
cmd.sourcezoneid = source_zone_id
|
|
return apiclient.copySnapshot(cmd)
|
|
|
|
def create_snapshot_volume(self, apiclient, snapshot_id, zone_id=None, disk_offering_id=None):
|
|
cmd = createVolume.createVolumeCmd()
|
|
cmd.name = "-".join(["VolumeFromSnap", random_gen()])
|
|
cmd.snapshotid = snapshot_id
|
|
if zone_id:
|
|
cmd.zoneid = zone_id
|
|
if disk_offering_id:
|
|
cmd.diskofferingid = disk_offering_id
|
|
volume_from_snapshot = Volume(apiclient.createVolume(cmd).__dict__)
|
|
self.cleanup.append(volume_from_snapshot)
|
|
return volume_from_snapshot
|
|
|
|
def create_snapshot_template(self, apiclient, services, snapshot_id, zone_id):
|
|
cmd = createTemplate.createTemplateCmd()
|
|
cmd.displaytext = "TemplateFromSnap"
|
|
name = "-".join([cmd.displaytext, random_gen()])
|
|
cmd.name = name
|
|
if "ostypeid" in services:
|
|
cmd.ostypeid = services["ostypeid"]
|
|
elif "ostype" in services:
|
|
# Find OSTypeId from Os type
|
|
sub_cmd = listOsTypes.listOsTypesCmd()
|
|
sub_cmd.description = services["ostype"]
|
|
ostypes = apiclient.listOsTypes(sub_cmd)
|
|
|
|
if not isinstance(ostypes, list):
|
|
self.fail("Unable to find Ostype id with desc: %s" %
|
|
services["ostype"])
|
|
cmd.ostypeid = ostypes[0].id
|
|
else:
|
|
self.fail("Unable to find Ostype is required for creating template")
|
|
|
|
cmd.isfeatured = True
|
|
cmd.ispublic = True
|
|
cmd.isextractable = False
|
|
|
|
cmd.snapshotid = snapshot_id
|
|
cmd.zoneid = zone_id
|
|
apiclient.createTemplate(cmd)
|
|
templates = Template.list(apiclient, name=name, templatefilter="self")
|
|
if not isinstance(templates, list) and len(templates) < 0:
|
|
self.fail("Unable to find created template with name %s" % name)
|
|
template = Template(templates[0].__dict__)
|
|
self.cleanup.append(template)
|
|
return template
|
|
|
|
def verify_snapshot_copies(self, snapshot_id, zone_ids):
|
|
snapshot_entries = Snapshot.list(self.userapiclient, id=snapshot_id, showunique=False, locationtype="Secondary")
|
|
if not isinstance(snapshot_entries, list):
|
|
self.fail("Unable to list snapshot for multiple zones")
|
|
elif len(snapshot_entries) != len(zone_ids):
|
|
self.fail("Undesired list snapshot size for multiple zones")
|
|
for zone_id in zone_ids:
|
|
zone_found = False
|
|
for entry in snapshot_entries:
|
|
if entry.zoneid == zone_id:
|
|
zone_found = True
|
|
break
|
|
if zone_found == False:
|
|
self.fail("Unable to find snapshot entry for the zone ID: %s" % zone_id)
|
|
|
|
@skipTestIf("testsNotSupported")
|
|
@attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
|
|
def test_01_take_snapshot_multi_zone(self):
|
|
"""Test to take volume snapshot in multiple zones
|
|
"""
|
|
# Validate the following:
|
|
# 1. Take snapshot in multiple zone
|
|
# 2. Verify
|
|
|
|
snapshot = self.create_snapshot(self.userapiclient, [str(self.additional_zone.id)])
|
|
self.snapshot_id = snapshot.id
|
|
self.verify_snapshot_copies(self.snapshot_id, [self.zone.id, self.additional_zone.id])
|
|
return
|
|
|
|
@skipTestIf("testsNotSupported")
|
|
@attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
|
|
def test_02_copy_snapshot_multi_zone(self):
|
|
"""Test to take volume snapshot in a zone and then copy
|
|
"""
|
|
# Validate the following:
|
|
# 1. Take snapshot in the native zone
|
|
# 2. Copy snapshot in the additional zone
|
|
# 3. Verify
|
|
|
|
snapshot = self.create_snapshot(self.userapiclient, None)
|
|
self.snapshot_id = snapshot.id
|
|
self.copy_snapshot(self.userapiclient, self.snapshot_id, [str(self.additional_zone.id)], self.zone.id)
|
|
self.verify_snapshot_copies(self.snapshot_id, [self.zone.id, self.additional_zone.id])
|
|
return
|
|
|
|
@skipTestIf("testsNotSupported")
|
|
@attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
|
|
def test_03_take_snapshot_multi_zone_delete_single_zone(self):
|
|
"""Test to take volume snapshot in multiple zones and delete from one zone
|
|
"""
|
|
# Validate the following:
|
|
# 1. Take snapshot in multiple zone
|
|
# 2. Verify
|
|
# 3. Delete from one zone
|
|
# 4. Verify
|
|
|
|
snapshot = self.create_snapshot(self.userapiclient, [str(self.additional_zone.id)])
|
|
self.snapshot_id = snapshot.id
|
|
self.verify_snapshot_copies(self.snapshot_id, [self.zone.id, self.additional_zone.id])
|
|
self.delete_snapshot(self.userapiclient, self.snapshot_id, self.zone.id)
|
|
self.verify_snapshot_copies(self.snapshot_id, [self.additional_zone.id])
|
|
return
|
|
|
|
@skipTestIf("testsNotSupported")
|
|
@attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
|
|
def test_04_copy_snapshot_multi_zone_delete_all(self):
|
|
"""Test to take volume snapshot in a zone, copy in another zone and delete for all
|
|
"""
|
|
# Validate the following:
|
|
# 1. Take snapshot in the native zone
|
|
# 2. Copy snapshot in the additional zone
|
|
# 3. Verify
|
|
# 4. Delete for all zones
|
|
# 5. Verify
|
|
|
|
snapshot = self.create_snapshot(self.userapiclient, None)
|
|
self.snapshot_id = snapshot.id
|
|
self.copy_snapshot(self.userapiclient, self.snapshot_id, [str(self.additional_zone.id)], self.zone.id)
|
|
self.verify_snapshot_copies(self.snapshot_id, [self.zone.id, self.additional_zone.id])
|
|
self.delete_snapshot(self.userapiclient, self.snapshot_id)
|
|
snapshot_entries = Snapshot.list(self.userapiclient, id=snapshot.id)
|
|
if snapshot_entries and isinstance(snapshot_entries, list) and len(snapshot_entries) > 0:
|
|
self.fail("Snapshot delete for all zones failed")
|
|
self.cleanup.remove(snapshot)
|
|
return
|
|
|
|
@skipTestIf("testsNotSupported")
|
|
@attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
|
|
def test_05_take_snapshot_multi_zone_create_volume_additional_zone(self):
|
|
"""Test to take volume snapshot in multiple zones and create a volume in one of the additional zones
|
|
"""
|
|
# Validate the following:
|
|
# 1. Take snapshot in multiple zone
|
|
# 2. Verify
|
|
# 3. Create volume in the additional zone
|
|
# 4. Verify volume zone
|
|
|
|
snapshot = self.create_snapshot(self.userapiclient, [str(self.additional_zone.id)])
|
|
self.snapshot_id = snapshot.id
|
|
self.verify_snapshot_copies(self.snapshot_id, [self.zone.id, self.additional_zone.id])
|
|
disk_offering_id = None
|
|
if snapshot.volumetype == 'ROOT':
|
|
service = self.services["disk_offering"]
|
|
service["disksize"] = math.ceil(snapshot.virtualsize/(1024*1024*1024))
|
|
self.disk_offering = DiskOffering.create(
|
|
self.apiclient,
|
|
service
|
|
)
|
|
self.cleanup.append(self.disk_offering)
|
|
disk_offering_id = self.disk_offering.id
|
|
self.volume = self.create_snapshot_volume(self.userapiclient, self.snapshot_id, self.additional_zone.id, disk_offering_id)
|
|
if self.additional_zone.id != self.volume.zoneid:
|
|
self.fail("Volume from snapshot not created in the additional zone")
|
|
return
|
|
|
|
@skipTestIf("testsNotSupported")
|
|
@attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
|
|
def test_06_take_snapshot_multi_zone_create_template_additional_zone(self):
|
|
"""Test to take volume snapshot in multiple zones and create a volume in one of the additional zones
|
|
"""
|
|
# Validate the following:
|
|
# 1. Take snapshot in multiple zone
|
|
# 2. Verify
|
|
# 3. Create template in the additional zone
|
|
# 4. Verify template zone
|
|
|
|
snapshot = self.create_snapshot(self.userapiclient, [str(self.additional_zone.id)])
|
|
self.snapshot_id = snapshot.id
|
|
self.verify_snapshot_copies(self.snapshot_id, [self.zone.id, self.additional_zone.id])
|
|
self.template = self.create_snapshot_template(self.userapiclient, self.services, self.snapshot_id, self.additional_zone.id)
|
|
if self.additional_zone.id != self.template.zoneid:
|
|
self.fail("Template from snapshot not created in the additional zone")
|
|
return
|