blob: 7b9531a3433b10fa8a3737b93786249ff54977e7 [file] [log] [blame]
# 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