add scenario tests

Change-Id: Ib07f9d4400998e3f7fb0f2809912ec66aefece49
This commit is contained in:
Andrey Pavlov 2015-02-18 23:00:50 +03:00
parent cc1ed0b32d
commit 8a9b4d53f5
13 changed files with 734 additions and 94 deletions

View File

@ -184,7 +184,7 @@ def register_image(context, name=None, image_location=None,
mappings = [instance_api._cloud_parse_block_device_mapping(context,
bdm)
for bdm in block_device_mapping]
properties['block_device_mapping'] = mappings
properties['block_device_mapping'] = json.dumps(mappings)
if architecture is not None:
properties['architecture'] = architecture
if kernel_id:

View File

@ -32,7 +32,7 @@ class InstanceWithEBSTest(base.EC2TestCase):
cls.image_id = CONF.aws.ebs_image_id
cls.zone = CONF.aws.aws_zone
def test_create_delete_ebs_instance(self):
def test_create_get_delete_ebs_instance(self):
"""Launch EBS-backed instance, check results, and terminate it."""
resp, data = self.client.RunInstances(
ImageId=self.image_id, InstanceType=CONF.aws.instance_type,
@ -62,14 +62,14 @@ class InstanceWithEBSTest(base.EC2TestCase):
self.assertEqual(1, len(bdt))
ebs = bdt[0]['Ebs']
self.assertIsNotNone(ebs)
volumeId = ebs.get('VolumeId')
self.assertIsNotNone(volumeId)
volume_id = ebs.get('VolumeId')
self.assertIsNotNone(volume_id)
self.assertEqual('attached', ebs.get('Status'))
if CONF.aws.run_incompatible_tests:
self.assertTrue(ebs.get('AttachTime'))
self.assertTrue(ebs.get('DeleteOnTermination'))
resp, data = self.client.DescribeVolumes(VolumeIds=[volumeId])
resp, data = self.client.DescribeVolumes(VolumeIds=[volume_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.assertEqual(1, len(data['Volumes']))
@ -91,27 +91,17 @@ class InstanceWithEBSTest(base.EC2TestCase):
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
resp, data = self.client.DescribeInstances(InstanceIds=[instance_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
reservations = data.get('Reservations', [])
self.assertNotEmpty(reservations)
instances = reservations[0].get('Instances', [])
self.assertNotEmpty(instances)
instance = instances[0]
self.assertEqual('ebs', instance.get('RootDeviceType'))
self.assertIsNotNone(instance.get('RootDeviceName'))
bdms = instance['BlockDeviceMappings']
rdn = instance['RootDeviceName']
bdt = [bdt for bdt in bdms if bdt['DeviceName'] == rdn]
volumeId = bdt[0]['Ebs'].get('VolumeId')
self.assertIsNotNone(volumeId)
bdt = self.get_instance_bdm(instance_id, None)
self.assertIsNotNone(bdt)
volume_id = bdt['Ebs'].get('VolumeId')
self.assertIsNotNone(volume_id)
resp, data = self.client.StopInstances(InstanceIds=[instance_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.get_instance_waiter().wait_available(instance_id,
final_set=('stopped'))
resp, data = self.client.DescribeVolumes(VolumeIds=[volumeId])
resp, data = self.client.DescribeVolumes(VolumeIds=[volume_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.assertEqual(1, len(data['Volumes']))

View File

@ -40,9 +40,7 @@ class InstanceInVPCTest(base.EC2TestCase):
raise cls.skipException('aws image_id does not provided')
resp, data = cls.client.CreateVpc(CidrBlock=cls.VPC_CIDR)
if resp.status_code != 200:
LOG.error(base.EC2ErrorConverter(data))
assert 200 == resp.status_code
cls.assertResultStatic(resp, data)
cls.vpc_id = data['Vpc']['VpcId']
cls.addResourceCleanUpStatic(cls.client.DeleteVpc, VpcId=cls.vpc_id)
cls.get_vpc_waiter().wait_available(cls.vpc_id)
@ -51,9 +49,7 @@ class InstanceInVPCTest(base.EC2TestCase):
resp, data = cls.client.CreateSubnet(VpcId=cls.vpc_id,
CidrBlock=cls.SUBNET_CIDR,
AvailabilityZone=aws_zone)
if resp.status_code != 200:
LOG.error(base.EC2ErrorConverter(data))
assert 200 == resp.status_code
cls.assertResultStatic(resp, data)
cls.subnet_id = data['Subnet']['SubnetId']
cls.addResourceCleanUpStatic(cls.client.DeleteSubnet,
SubnetId=cls.subnet_id)

View File

@ -40,17 +40,13 @@ class InternetGatewayTest(base.EC2TestCase):
raise cls.skipException('VPC is disabled')
resp, data = cls.client.CreateVpc(CidrBlock=cls.VPC_CIDR)
if resp.status_code != 200:
LOG.error(base.EC2ErrorConverter(data))
assert 200 == resp.status_code
cls.assertResultStatic(resp, data)
cls.vpc_id = data['Vpc']['VpcId']
cls.get_vpc_waiter().wait_available(cls.vpc_id)
cls.addResourceCleanUpStatic(cls.client.DeleteVpc, VpcId=cls.vpc_id)
resp, data = cls.client.CreateVpc(CidrBlock=cls.VPC_CIDR_ALT)
if resp.status_code != 200:
LOG.error(base.EC2ErrorConverter(data))
assert 200 == resp.status_code
cls.assertResultStatic(resp, data)
cls.vpc_id_alt = data['Vpc']['VpcId']
cls.get_vpc_waiter().wait_available(cls.vpc_id_alt)
cls.addResourceCleanUpStatic(cls.client.DeleteVpc,

View File

@ -40,9 +40,7 @@ class NetworkInterfaceTest(base.EC2TestCase):
raise cls.skipException('VPC is disabled')
resp, data = cls.client.CreateVpc(CidrBlock=cls.VPC_CIDR)
if resp.status_code != 200:
LOG.error(base.EC2ErrorConverter(data))
assert 200 == resp.status_code
cls.assertResultStatic(resp, data)
cls.vpc_id = data['Vpc']['VpcId']
cls.addResourceCleanUpStatic(cls.client.DeleteVpc, VpcId=cls.vpc_id)
cls.get_vpc_waiter().wait_available(cls.vpc_id)
@ -51,9 +49,7 @@ class NetworkInterfaceTest(base.EC2TestCase):
resp, data = cls.client.CreateSubnet(VpcId=cls.vpc_id,
CidrBlock=cls.SUBNET_CIDR,
AvailabilityZone=aws_zone)
if resp.status_code != 200:
LOG.error(base.EC2ErrorConverter(data))
assert 200 == resp.status_code
cls.assertResultStatic(resp, data)
cls.subnet_id = data['Subnet']['SubnetId']
cls.addResourceCleanUpStatic(cls.client.DeleteSubnet,
SubnetId=cls.subnet_id)

View File

@ -36,9 +36,7 @@ class RouteTest(base.EC2TestCase):
raise cls.skipException('VPC is disabled')
resp, data = cls.client.CreateVpc(CidrBlock=cls.VPC_CIDR)
if resp.status_code != 200:
LOG.error(base.EC2ErrorConverter(data))
assert 200 == resp.status_code
cls.assertResultStatic(resp, data)
cls.vpc_id = data['Vpc']['VpcId']
cls.addResourceCleanUpStatic(cls.client.DeleteVpc, VpcId=cls.vpc_id)
cls.get_vpc_waiter().wait_available(cls.vpc_id)

View File

@ -39,9 +39,7 @@ class SecurityGroupTest(base.EC2TestCase):
raise cls.skipException('VPC is disabled')
resp, data = cls.client.CreateVpc(CidrBlock=cls.VPC_CIDR)
if resp.status_code != 200:
LOG.error(base.EC2ErrorConverter(data))
assert 200 == resp.status_code
cls.assertResultStatic(resp, data)
cls.vpc_id = data['Vpc']['VpcId']
cls.addResourceCleanUpStatic(cls.client.DeleteVpc, VpcId=cls.vpc_id)
cls.get_vpc_waiter().wait_available(cls.vpc_id)

View File

@ -36,9 +36,7 @@ class SubnetTest(base.EC2TestCase):
raise cls.skipException('VPC is disabled')
resp, data = cls.client.CreateVpc(CidrBlock=cls.VPC_CIDR)
if resp.status_code != 200:
LOG.error(base.EC2ErrorConverter(data))
assert 200 == resp.status_code
cls.assertResultStatic(resp, data)
cls.vpc_id = data['Vpc']['VpcId']
cls.addResourceCleanUpStatic(cls.client.DeleteVpc, VpcId=cls.vpc_id)
cls.get_vpc_waiter().wait_available(cls.vpc_id)

View File

@ -108,7 +108,7 @@ class VolumeTest(base.EC2TestCase):
volume = data['Volumes'][0]
self.assertEqual(volume_id, volume['VolumeId'])
if CONF.aws.run_incompatible_tests:
self.assertEqual('standard', data['VolumeType'])
self.assertEqual('standard', volume['VolumeType'])
self.assertEqual(1, volume['Size'])
if 'Encrypted' in volume:
self.assertFalse(volume['Encrypted'])
@ -232,6 +232,68 @@ class VolumeTest(base.EC2TestCase):
self.cancelResourceCleanUp(clean_i)
self.get_instance_waiter().wait_delete(instance_id)
def test_attaching_stage(self):
instance_type = CONF.aws.instance_type
image_id = CONF.aws.image_id
if not image_id:
raise self.skipException('aws image_id does not provided')
kwargs = {
'ImageId': image_id,
'InstanceType': instance_type,
'MinCount': 1,
'MaxCount': 1,
'Placement': {'AvailabilityZone': CONF.aws.aws_zone}
}
resp, data = self.client.RunInstances(*[], **kwargs)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
instance_id = data['Instances'][0]['InstanceId']
clean_i = self.addResourceCleanUp(self.client.TerminateInstances,
InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
resp, data = self.client.CreateVolume(
AvailabilityZone=CONF.aws.aws_zone, Size=1)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
volume_id = data['VolumeId']
clean_v = self.addResourceCleanUp(self.client.DeleteVolume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
kwargs = {
'Device': '/dev/vdh',
'InstanceId': instance_id,
'VolumeId': volume_id,
}
resp, data = self.client.AttachVolume(*[], **kwargs)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
clean_vi = self.addResourceCleanUp(self.client.DetachVolume,
VolumeId=volume_id)
self.assertEqual('attaching', data['State'])
bdt = self.get_instance_bdm(instance_id, '/dev/vdh')
self.assertIsNotNone(bdt)
self.assertEqual('attaching', bdt['Ebs']['Status'])
self.get_volume_attachment_waiter().wait_available(
volume_id, final_set=('attached'))
resp, data = self.client.DetachVolume(VolumeId=volume_id)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(clean_vi)
self.get_volume_attachment_waiter().wait_delete(volume_id)
resp, data = self.client.DeleteVolume(VolumeId=volume_id)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(clean_v)
self.get_volume_waiter().wait_delete(volume_id)
resp, data = self.client.TerminateInstances(InstanceIds=[instance_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(clean_i)
self.get_instance_waiter().wait_delete(instance_id)
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"Volume statuses are not implemented")
def test_delete_detach_attached_volume(self):

View File

@ -84,11 +84,11 @@ class EC2Waiter(object):
self.default_check_interval = CONF.aws.build_interval
def _state_wait(self, f, f_args=None, f_kwargs=None,
final_set=set(), valid_set=None):
final_set=set(), error_set=('error')):
if not isinstance(final_set, set):
final_set = set((final_set,))
if not isinstance(valid_set, set) and valid_set is not None:
valid_set = set((valid_set,))
if not isinstance(error_set, set):
error_set = set((error_set,))
interval = self.default_check_interval
start_time = time.time()
args = f_args if f_args is not None else []
@ -103,14 +103,16 @@ class EC2Waiter(object):
old_status, status, time.time() - start_time)
if status in final_set:
return status
if valid_set is not None and status not in valid_set:
return status
if error_set is not None and status in error_set:
raise testtools.TestCase.failureException(
'State changes to error state! '
'While waiting for %s at "%s"' %
(final_set, status))
dtime = time.time() - start_time
if dtime > self.default_timeout:
raise testtools.TestCase.failureException(
"State change timeout exceeded!"
'(%ds) While waiting'
'for %s at "%s"' %
'State change timeout exceeded! '
'(%ds) While waiting for %s at "%s"' %
(dtime, final_set, status))
time.sleep(interval)
interval += self.default_check_interval
@ -172,19 +174,19 @@ def safe_setup(f):
"""A decorator used to wrap the setUpClass for safe setup."""
def decorator(cls):
try:
f(cls)
except Exception as se:
etype, value, trace = sys.exc_info()
LOG.exception("setUpClass failed: %s" % se)
try:
f(cls)
except Exception as se:
etype, value, trace = sys.exc_info()
LOG.exception("setUpClass failed: %s" % se)
try:
cls.tearDownClass()
except Exception as te:
LOG.exception("tearDownClass failed: %s" % te)
try:
raise etype(value), None, trace
finally:
del trace # for avoiding circular refs
cls.tearDownClass()
except Exception as te:
LOG.exception("tearDownClass failed: %s" % te)
try:
raise etype(value), None, trace
finally:
del trace # for avoiding circular refs
return decorator
@ -246,6 +248,12 @@ class EC2TestCase(base.BaseTestCase):
cls.client = botocoreclient.APIClientEC2()
TesterStateHolder().ec2_client = cls.client
@classmethod
def assertResultStatic(cls, resp, data):
if resp.status_code != 200:
LOG.error(EC2ErrorConverter(data))
assert 200 == resp.status_code
@classmethod
def addResourceCleanUpStatic(cls, function, *args, **kwargs):
"""Adds CleanUp callable, used by tearDownClass.
@ -280,9 +288,9 @@ class EC2TestCase(base.BaseTestCase):
self._sequence = self._sequence + 1
self._resource_trash_bin[self._sequence] = (function, args, kwargs, tb)
# LOG.debug("For cleaning up: %s\n From: %s" %
# (self.friendly_function_call_str(function, *args, **kwargs),
# str((tb[0], tb[1], tb[2]))))
LOG.debug("For cleaning up: %s\n From: %s" %
(self.friendly_function_call_str(function, *args, **kwargs),
str((tb[0], tb[1], tb[2]))))
return self._sequence
@ -318,6 +326,9 @@ class EC2TestCase(base.BaseTestCase):
'DeleteSnapshot': (
'get_snapshot_waiter',
lambda kwargs: kwargs['SnapshotId']),
'DeregisterImage': (
'get_image_waiter',
lambda kwargs: kwargs['ImageId']),
}
@classmethod
@ -343,25 +354,7 @@ class EC2TestCase(base.BaseTestCase):
(cls.friendly_function_call_str(function, *pos_args,
**kw_args),
str((tb[0], tb[1], tb[2]))))
resp, data = function(*pos_args, **kw_args)
if resp.status_code != 200:
error = data.get('Error', {})
error_code = error.get('Code')
for err in cls._VALID_CLEANUP_ERRORS:
if err in error_code:
break
else:
err_msg = (error if isinstance(error, basestring)
else error.get('Message'))
msg = ("Cleanup failed with status %d and message"
" '%s'(Code = %s)"
% (resp.status_code, err_msg, error_code))
LOG.error(msg)
elif function.__name__ in cls._CLEANUP_WAITERS:
(waiter, obj_id) = cls._CLEANUP_WAITERS[function.__name__]
waiter = getattr(cls, waiter)
obj_id = obj_id(kw_args)
waiter().wait_delete(obj_id)
cls.cleanUpItem(function, pos_args, kw_args)
except BaseException as exc:
fail_count += 1
LOG.exception(exc)
@ -369,6 +362,28 @@ class EC2TestCase(base.BaseTestCase):
del trash_bin[key]
return fail_count
@classmethod
def cleanUpItem(cls, function, pos_args, kw_args):
resp, data = function(*pos_args, **kw_args)
if resp.status_code != 200:
error = data.get('Error', {})
error_code = error.get('Code')
for err in cls._VALID_CLEANUP_ERRORS:
if err in error_code:
break
else:
err_msg = (error if isinstance(error, basestring)
else error.get('Message'))
msg = ("Cleanup failed with status %d and message"
" '%s'(Code = %s)"
% (resp.status_code, err_msg, error_code))
LOG.error(msg)
elif function.__name__ in cls._CLEANUP_WAITERS:
(waiter, obj_id) = cls._CLEANUP_WAITERS[function.__name__]
waiter = getattr(cls, waiter)
obj_id = obj_id(kw_args)
waiter().wait_delete(obj_id)
@classmethod
def friendly_function_name_simple(cls, call_able):
name = ""
@ -514,8 +529,45 @@ class EC2TestCase(base.BaseTestCase):
def get_snapshot_waiter(cls):
return EC2Waiter(cls._snapshot_get_state)
@classmethod
def _image_get_state(cls, image_id):
resp, data = cls.client.DescribeImages(ImageIds=[image_id])
if resp.status_code == 200:
return data['Images'][0]['State']
if resp.status_code == 400:
error = data['Error']
if error['Code'] == 'InvalidAMIID.NotFound':
raise exceptions.NotFound()
raise EC2ResponceException(resp, data)
@classmethod
def get_image_waiter(cls):
return EC2Waiter(cls._image_get_state)
def assertEmpty(self, list_obj, msg=None):
self.assertTrue(len(list_obj) == 0, msg)
def assertNotEmpty(self, list_obj, msg=None):
self.assertTrue(len(list_obj) > 0, msg)
# NOTE(andrey-mp): Helpers zone
def get_instance_bdm(self, instance_id, device_name):
"""
device_name=None means getting bdm of root instance device
"""
resp, data = self.client.DescribeInstances(
InstanceIds=[instance_id])
self.assertEqual(200, resp.status_code, EC2ErrorConverter(data))
self.assertEqual(1, len(data.get('Reservations', [])))
instances = data['Reservations'][0].get('Instances', [])
self.assertEqual(1, len(instances))
instance = instances[0]
if not device_name:
device_name = instance['RootDeviceName']
bdms = instance['BlockDeviceMappings']
bdt = [bdt for bdt in bdms if bdt['DeviceName'] == device_name]
return None if len(bdt) == 0 else bdt[0]

View File

@ -0,0 +1,553 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed 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.
import math
from tempest_lib.openstack.common import log
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
def _get_device_name_prefix(device_name):
dev_num_pos = 0
while '0' <= device_name[dev_num_pos - 1] <= '9':
dev_num_pos -= 1
return device_name[:dev_num_pos - 1]
class EC2_EBSInstanceTuneBDM(base.EC2TestCase):
"""Test change root device attributes at instance launch."""
@classmethod
@base.safe_setup
def setUpClass(cls):
super(EC2_EBSInstanceTuneBDM, cls).setUpClass()
if not CONF.aws.ebs_image_id:
raise cls.skipException('aws EBS image does not provided')
cls.image_id = CONF.aws.ebs_image_id
cls.zone = CONF.aws.aws_zone
resp, data = cls.client.DescribeImages(ImageIds=[cls.image_id])
cls.assertResultStatic(resp, data)
assert 1 == len(data['Images'])
image = data['Images'][0]
cls.root_device_name = image['RootDeviceName']
bdm = image['BlockDeviceMappings']
bdm = [v for v in bdm if v['DeviceName'] == cls.root_device_name]
assert 1 == len(bdm)
ebs = bdm[0]['Ebs']
cls.root_device_size = ebs.get('VolumeSize')
if not cls.root_device_size:
snapshotId = ebs.get('SnapshotId')
resp, data = cls.client.DescribeSnapshots(SnapshotIds=[snapshotId])
cls.assertResultStatic(resp, data)
assert 1 == len(data['Snapshots'])
cls.root_device_size = data['Snapshots'][0]['VolumeSize']
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"Error from nova: "
"Block Device Mapping is Invalid: Unrecognized legacy format.")
def test_launch_ebs_instance_with_persistent_root_device(self):
"""
Launch EBS-backed instance with left root device after termination
"""
instance_type = CONF.aws.instance_type
resp, data = self.client.RunInstances(
ImageId=self.image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': self.zone}, MinCount=1, MaxCount=1,
BlockDeviceMappings=[{'DeviceName': self.root_device_name,
'Ebs': {'DeleteOnTermination': False}}])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
instance_id = data['Instances'][0]['InstanceId']
res_clean = self.addResourceCleanUp(self.client.TerminateInstances,
InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
bdt = self.get_instance_bdm(instance_id, self.root_device_name)
self.assertIsNotNone(bdt)
volume_id = bdt['Ebs'].get('VolumeId')
res_clean_vol = self.addResourceCleanUp(self.client.DeleteVolume,
VolumeId=volume_id)
self.assertIsNotNone(volume_id)
self.assertFalse(bdt['Ebs']['DeleteOnTermination'])
resp, data = self.client.DescribeVolumes(VolumeIds=[volume_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.assertEqual(1, len(data['Volumes']))
resp, data = self.client.TerminateInstances(InstanceIds=[instance_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)
self.get_volume_waiter().wait_available(volume_id)
resp, data = self.client.DeleteVolume(VolumeId=volume_id)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(res_clean_vol)
self.get_volume_waiter().wait_delete(volume_id)
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"Error from nova: "
"Block Device Mapping is Invalid: Unrecognized legacy format.")
def test_launch_ebs_instance_with_resized_root_device(self):
"""Launch EBS-backed instance with resizing root device."""
new_size = int(math.ceil(self.root_device_size * 1.1))
instance_type = CONF.aws.instance_type
resp, data = self.client.RunInstances(
ImageId=self.image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': self.zone}, MinCount=1, MaxCount=1,
BlockDeviceMappings=[{'DeviceName': self.root_device_name,
'Ebs': {'VolumeSize': new_size}}])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
instance_id = data['Instances'][0]['InstanceId']
res_clean = self.addResourceCleanUp(self.client.TerminateInstances,
InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
bdt = self.get_instance_bdm(instance_id, self.root_device_name)
self.assertIsNotNone(bdt)
volume_id = bdt['Ebs'].get('VolumeId')
self.assertIsNotNone(volume_id)
self.assertTrue(bdt['Ebs']['DeleteOnTermination'])
resp, data = self.client.DescribeVolumes(VolumeIds=[volume_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.assertEqual(1, len(data['Volumes']))
volume = data['Volumes'][0]
self.assertEqual(new_size, volume['Size'])
resp, data = self.client.TerminateInstances(InstanceIds=[instance_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"Error from nova: "
"Block Device Mapping is Invalid: Unrecognized legacy format.")
def test_launch_ebs_instance_with_creating_blank_volume(self):
"""Launch instance with creating blank volume."""
device_name_prefix = _get_device_name_prefix(self.root_device_name)
device_name = device_name_prefix + 'd'
instance_type = CONF.aws.instance_type
resp, data = self.client.RunInstances(
ImageId=self.image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': self.zone}, MinCount=1, MaxCount=1,
BlockDeviceMappings=[{'DeviceName': device_name,
'Ebs': {'VolumeSize': 1}}])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
instance_id = data['Instances'][0]['InstanceId']
res_clean = self.addResourceCleanUp(self.client.TerminateInstances,
InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
bdt = self.get_instance_bdm(instance_id, device_name)
self.assertIsNotNone(bdt)
volume_id = bdt['Ebs'].get('VolumeId')
self.assertIsNotNone(volume_id)
self.assertTrue(bdt['Ebs']['DeleteOnTermination'])
resp, data = self.client.DescribeVolumes(VolumeIds=[volume_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.assertEqual(1, len(data['Volumes']))
volume = data['Volumes'][0]
self.assertEqual(1, volume['Size'])
resp, data = self.client.TerminateInstances(InstanceIds=[instance_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)
class EC2_EBSInstanceAttaching(base.EC2TestCase):
"""
Launch instance with two attached volumes. One at first free slot (xxdb,
other at some free slot (xxdh). Use full device name for the first and
short device name for the second. Check used device names.
Detach devices and reattach their back with same names. Check used device
names again.
Detach devices and attach their in next slots (xxdc and xxdi). First with
full name, and second with short. Check useed device names.
Sometimes this test case failed in AWS because volumes get attach state
'busy'. Then it's need to give a pause and rerun test case.
Some dublicate tests are hidden to less output information.
"""
@classmethod
@base.safe_setup
def setUpClass(cls):
super(EC2_EBSInstanceAttaching, cls).setUpClass()
if not CONF.aws.run_incompatible_tests:
raise cls.skipException('Decsribe returns full device name while '
'we boot with short name.')
if not CONF.aws.ebs_image_id:
raise cls.skipException('aws EBS image does not provided')
cls.image_id = CONF.aws.ebs_image_id
cls.zone = CONF.aws.aws_zone
resp, data = cls.client.DescribeImages(ImageIds=[cls.image_id])
cls.assertResultStatic(resp, data)
assert 1 == len(data['Images'])
image = data['Images'][0]
root_device_name = image['RootDeviceName']
device_name_prefix = _get_device_name_prefix(root_device_name)
cls.full_device_name_prefix = device_name_prefix
cls.short_device_name_prefix = device_name_prefix[len("/dev/"):]
resp, data = cls.client.CreateVolume(AvailabilityZone=cls.zone,
Size=1)
cls.assertResultStatic(resp, data)
cls.volume_id = data['VolumeId']
cls.addResourceCleanUpStatic(cls.client.DeleteVolume,
VolumeId=cls.volume_id)
cls.get_volume_waiter().wait_available(cls.volume_id)
resp, data = cls.client.CreateSnapshot(VolumeId=cls.volume_id)
cls.assertResultStatic(resp, data)
cls.snapshot_id = data['SnapshotId']
cls.addResourceCleanUpStatic(cls.client.DeleteSnapshot,
SnapshotId=cls.snapshot_id)
cls.get_snapshot_waiter().wait_available(cls.snapshot_id,
final_set=('completed'))
instance_type = CONF.aws.instance_type
cls.device1_name = cls.full_device_name_prefix + "d"
cls.device2_name = cls.short_device_name_prefix + "h"
resp, data = cls.client.RunInstances(
ImageId=cls.image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': cls.zone}, MinCount=1, MaxCount=1,
BlockDeviceMappings=[{'DeviceName': cls.device1_name,
'Ebs': {'SnapshotId': cls.snapshot_id,
'DeleteOnTermination': True}},
{'DeviceName': cls.device2_name,
'Ebs': {'SnapshotId': cls.snapshot_id,
'DeleteOnTermination': True}}])
cls.assertResultStatic(resp, data)
instance_id = data['Instances'][0]['InstanceId']
cls.instance_id = instance_id
cls.addResourceCleanUpStatic(cls.client.TerminateInstances,
InstanceIds=[instance_id])
cls.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
resp, data = cls.client.DescribeInstances(InstanceIds=[instance_id])
cls.assertResultStatic(resp, data)
assert 1 == len(data.get('Reservations', []))
instances = data['Reservations'][0].get('Instances', [])
assert 1 == len(instances)
instance = instances[0]
bdms = instance['BlockDeviceMappings']
for bdt in bdms:
if bdt['DeviceName'] == cls.device1_name:
cls.volume_id1 = bdt['Ebs']['VolumeId']
if bdt['DeviceName'] == cls.device2_name:
cls.volume_id2 = bdt['Ebs']['VolumeId']
assert cls.volume_id1
assert cls.volume_id2
@classmethod
def tearDownClass(cls):
super(EC2_EBSInstanceAttaching, cls).tearDownClass()
# NOTE(andrey-mp): Amazon resets flag DeleteOnTermination after
# reattaching volume, so we need delete them manually
for volume_id in [cls.volume_id1, cls.volume_id2]:
try:
cls.cleanUpItem(cls.client.DeleteVolume, [],
{'VolumeId': volume_id})
except BaseException as exc:
LOG.exception(exc)
def _test_attaching(self, volume_id, device_name, device_prefix,
new_device_name_letter):
resp, data = self.client.DetachVolume(VolumeId=volume_id)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
clean_v = self.addResourceCleanUp(self.client.DeleteVolume,
VolumeId=volume_id)
self.get_volume_attachment_waiter().wait_delete(volume_id)
bdt = self.get_instance_bdm(self.instance_id, device_name)
self.assertIsNone(bdt)
resp, data = self.client.AttachVolume(InstanceId=self.instance_id,
VolumeId=volume_id,
Device=device_name)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(clean_v)
self.get_volume_attachment_waiter().wait_available(
volume_id, final_set=('attached'))
resp, data = self.client.DescribeVolumes(VolumeIds=[volume_id])
self.assertEqual(200, resp.status_code)
self.assertEqual(1, len(data['Volumes']))
self.assertEqual('in-use', data['Volumes'][0]['State'])
bdt = self.get_instance_bdm(self.instance_id, device_name)
self.assertIsNotNone(bdt)
resp, data = self.client.DetachVolume(VolumeId=volume_id)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
clean_v = self.addResourceCleanUp(self.client.DeleteVolume,
VolumeId=volume_id)
self.get_volume_attachment_waiter().wait_delete(volume_id)
bdt = self.get_instance_bdm(self.instance_id, device_name)
self.assertIsNone(bdt)
new_device_name = device_prefix + new_device_name_letter
resp, data = self.client.AttachVolume(InstanceId=self.instance_id,
VolumeId=volume_id,
Device=new_device_name)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(clean_v)
self.get_volume_attachment_waiter().wait_available(
volume_id, final_set=('attached'))
resp, data = self.client.DescribeVolumes(VolumeIds=[volume_id])
self.assertEqual(200, resp.status_code)
self.assertEqual(1, len(data['Volumes']))
self.assertEqual('in-use', data['Volumes'][0]['State'])
bdt = self.get_instance_bdm(self.instance_id, new_device_name)
self.assertIsNotNone(bdt)
def test_attaching_by_full_name(self):
"""Attach and reattach device by full name."""
self._test_attaching(self.volume_id1, self.device1_name,
self.full_device_name_prefix, "e")
def test_attaching_by_short_name(self):
"""Attach and reattach device by short name."""
self._test_attaching(self.volume_id2, self.device2_name,
self.short_device_name_prefix, "i")
class EC2_EBSInstanceSnapshot(base.EC2TestCase):
"""
Launch EBS-backed image, snapshot root device, register image,
and launch another instance from the image
(http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/
instance-launch-snapshot.html)
"""
@classmethod
@base.safe_setup
def setUpClass(cls):
super(EC2_EBSInstanceSnapshot, cls).setUpClass()
if not CONF.aws.ebs_image_id:
raise cls.skipException('aws EBS image does not provided')
cls.image_id = CONF.aws.ebs_image_id
cls.zone = CONF.aws.aws_zone
def test_create_ebs_instance_snapshot(self):
"""Create snapshot of EBS-backed instance and check it."""
instance_type = CONF.aws.instance_type
resp, data = self.client.RunInstances(
ImageId=self.image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': self.zone}, MinCount=1, MaxCount=1)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
instance = data['Instances'][0]
instance_id = data['Instances'][0]['InstanceId']
res_clean = self.addResourceCleanUp(self.client.TerminateInstances,
InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
bdt = self.get_instance_bdm(instance_id, None)
self.assertIsNotNone(bdt)
volume_id = bdt['Ebs'].get('VolumeId')
self.assertIsNotNone(volume_id)
resp, data = self.client.StopInstances(InstanceIds=[instance_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.get_instance_waiter().wait_available(instance_id,
final_set=('stopped'))
resp, data = self.client.TerminateInstances(InstanceIds=[instance_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)
resp, data = self.client.CreateSnapshot(VolumeId=volume_id)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
snapshot_id = data['SnapshotId']
clean_s = self.addResourceCleanUp(self.client.DeleteSnapshot,
SnapshotId=snapshot_id)
self.get_snapshot_waiter().wait_available(snapshot_id,
final_set=('completed'))
kwargs = {
'Name': base.rand_name('ebs-ami'),
'RootDeviceName': instance['RootDeviceName'],
'BlockDeviceMappings': [{'DeviceName': instance['RootDeviceName'],
'Ebs': {'SnapshotId': snapshot_id,
'DeleteOnTermination': True}}]
}
if 'Architecture' in instance:
kwargs['Architecture'] = instance['Architecture']
if CONF.aws.run_incompatible_tests:
if 'KernelId' in instance:
kwargs['KernelId'] = instance['KernelId']
if 'RamdiskId' in instance:
kwargs['RamdiskId'] = instance['RamdiskId']
resp, data = self.client.RegisterImage(*[], **kwargs)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
image_id = data['ImageId']
clean_i = self.addResourceCleanUp(self.client.DeregisterImage,
ImageId=image_id)
self.get_image_waiter().wait_available(image_id)
resp, data = self.client.RunInstances(
ImageId=image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': self.zone}, MinCount=1, MaxCount=1)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
instance_id = data['Instances'][0]['InstanceId']
res_clean = self.addResourceCleanUp(self.client.TerminateInstances,
InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
# NOTE(andrey-mp): if instance will run then test will pass
resp, data = self.client.TerminateInstances(InstanceIds=[instance_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)
resp, data = self.client.DeregisterImage(ImageId=image_id)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(clean_i)
resp, data = self.client.DeleteSnapshot(SnapshotId=snapshot_id)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(clean_s)
class EC2_EBSInstanceResizeRootDevice(base.EC2TestCase):
"""
Launch EBS-backed instance, stop instance, detach root volume, snapshot it,
create volume from snapshot with increased size, attach new root volume,
start instance
(http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-expand-volume.html)
"""
@classmethod
@base.safe_setup
def setUpClass(cls):
super(EC2_EBSInstanceResizeRootDevice, cls).setUpClass()
if not CONF.aws.ebs_image_id:
raise cls.skipException('aws EBS image does not provided')
cls.image_id = CONF.aws.ebs_image_id
cls.zone = CONF.aws.aws_zone
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"Error from nova: "
"Unexpected Forbidden raised: Can't detach root device volume")
def test_resize_root_ebs_device(self):
"""Resize root device of launched instance."""
instance_type = CONF.aws.instance_type
resp, data = self.client.RunInstances(
ImageId=self.image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': self.zone}, MinCount=1, MaxCount=1)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
instance = data['Instances'][0]
instance_id = data['Instances'][0]['InstanceId']
res_clean = self.addResourceCleanUp(self.client.TerminateInstances,
InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
bdt = self.get_instance_bdm(instance_id, None)
self.assertIsNotNone(bdt)
volume_id = bdt['Ebs'].get('VolumeId')
self.assertIsNotNone(volume_id)
resp, data = self.client.StopInstances(InstanceIds=[instance_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.get_instance_waiter().wait_available(instance_id,
final_set=('stopped'))
resp, data = self.client.DetachVolume(VolumeId=volume_id)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
clean_v = self.addResourceCleanUp(self.client.DeleteVolume,
VolumeId=volume_id)
self.get_volume_attachment_waiter().wait_delete(volume_id)
resp, data = self.client.CreateSnapshot(VolumeId=volume_id)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
snapshot_id = data['SnapshotId']
clean_s = self.addResourceCleanUp(self.client.DeleteSnapshot,
SnapshotId=snapshot_id)
self.get_snapshot_waiter().wait_available(snapshot_id,
final_set=('completed'))
new_size = int(math.ceil(data['VolumeSize'] * 1.1))
resp, data = self.client.CreateVolume(AvailabilityZone=self.zone,
Size=new_size,
SnapshotId=snapshot_id)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
volume_id2 = data['VolumeId']
clean_v2 = self.addResourceCleanUp(self.client.DeleteVolume,
VolumeId=volume_id2)
self.get_volume_waiter().wait_available(volume_id2)
resp, data = self.client.DeleteSnapshot(SnapshotId=snapshot_id)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(clean_s)
resp, data = self.client.DeleteVolume(VolumeId=volume_id)
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(clean_v)
self.get_volume_waiter().wait_delete(volume_id)
resp, data = self.client.AttachVolume(
InstanceId=instance_id, VolumeId=volume_id2,
Device=instance['RootDeviceName'])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.get_volume_attachment_waiter().wait_available(
volume_id2, final_set=('attached'))
# NOTE(andrey-mp): move this cleanup operation to the end of trash
self.cancelResourceCleanUp(res_clean)
res_clean = self.addResourceCleanUp(self.client.TerminateInstances,
InstanceIds=[instance_id])
resp, data = self.client.StartInstances(InstanceIds=[instance_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
# NOTE(andrey-mp): if instance will run then test will pass
resp, data = self.client.TerminateInstances(InstanceIds=[instance_id])
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)
self.client.DeleteVolume(VolumeId=volume_id)
self.cancelResourceCleanUp(clean_v2)

View File

@ -13,6 +13,7 @@
# limitations under the License.
import copy
import json
import os
import tempfile
@ -204,10 +205,10 @@ class ImageTestCase(base.ApiTestCase):
self.glance.images.create.assert_called_once_with(
is_public=False, size=0, name='fake_name',
properties={'root_device_name': fakes.ROOT_DEVICE_NAME_IMAGE_2,
'block_device_mapping': [
{'snapshot_id': fakes.ID_OS_SNAPSHOT_1,
'delete_on_termination': True,
'device_name': fakes.ROOT_DEVICE_NAME_IMAGE_2}]})
'block_device_mapping': json.dumps(
[{'device_name': fakes.ROOT_DEVICE_NAME_IMAGE_2,
'delete_on_termination': True,
'snapshot_id': fakes.ID_OS_SNAPSHOT_1}])})
def test_register_image_invalid_parameters(self):
resp = self.execute('RegisterImage', {})