Merge from trunk
This commit is contained in:
@@ -92,7 +92,9 @@ class XmlConversionTestCase(test.TestCase):
|
||||
conv = ec2utils._try_convert
|
||||
self.assertEqual(conv('None'), None)
|
||||
self.assertEqual(conv('True'), True)
|
||||
self.assertEqual(conv('true'), True)
|
||||
self.assertEqual(conv('False'), False)
|
||||
self.assertEqual(conv('false'), False)
|
||||
self.assertEqual(conv('0'), 0)
|
||||
self.assertEqual(conv('42'), 42)
|
||||
self.assertEqual(conv('3.14'), 3.14)
|
||||
@@ -107,6 +109,8 @@ class Ec2utilsTestCase(test.TestCase):
|
||||
def test_ec2_id_to_id(self):
|
||||
self.assertEqual(ec2utils.ec2_id_to_id('i-0000001e'), 30)
|
||||
self.assertEqual(ec2utils.ec2_id_to_id('ami-1d'), 29)
|
||||
self.assertEqual(ec2utils.ec2_id_to_id('snap-0000001c'), 28)
|
||||
self.assertEqual(ec2utils.ec2_id_to_id('vol-0000001b'), 27)
|
||||
|
||||
def test_bad_ec2_id(self):
|
||||
self.assertRaises(exception.InvalidEc2Id,
|
||||
@@ -116,6 +120,72 @@ class Ec2utilsTestCase(test.TestCase):
|
||||
def test_id_to_ec2_id(self):
|
||||
self.assertEqual(ec2utils.id_to_ec2_id(30), 'i-0000001e')
|
||||
self.assertEqual(ec2utils.id_to_ec2_id(29, 'ami-%08x'), 'ami-0000001d')
|
||||
self.assertEqual(ec2utils.id_to_ec2_snap_id(28), 'snap-0000001c')
|
||||
self.assertEqual(ec2utils.id_to_ec2_vol_id(27), 'vol-0000001b')
|
||||
|
||||
def test_dict_from_dotted_str(self):
|
||||
in_str = [('BlockDeviceMapping.1.DeviceName', '/dev/sda1'),
|
||||
('BlockDeviceMapping.1.Ebs.SnapshotId', 'snap-0000001c'),
|
||||
('BlockDeviceMapping.1.Ebs.VolumeSize', '80'),
|
||||
('BlockDeviceMapping.1.Ebs.DeleteOnTermination', 'false'),
|
||||
('BlockDeviceMapping.2.DeviceName', '/dev/sdc'),
|
||||
('BlockDeviceMapping.2.VirtualName', 'ephemeral0')]
|
||||
expected_dict = {
|
||||
'block_device_mapping': {
|
||||
'1': {'device_name': '/dev/sda1',
|
||||
'ebs': {'snapshot_id': 'snap-0000001c',
|
||||
'volume_size': 80,
|
||||
'delete_on_termination': False}},
|
||||
'2': {'device_name': '/dev/sdc',
|
||||
'virtual_name': 'ephemeral0'}}}
|
||||
out_dict = ec2utils.dict_from_dotted_str(in_str)
|
||||
|
||||
self.assertDictMatch(out_dict, expected_dict)
|
||||
|
||||
def test_properties_root_defice_name(self):
|
||||
mappings = [{"device": "/dev/sda1", "virtual": "root"}]
|
||||
properties0 = {'mappings': mappings}
|
||||
properties1 = {'root_device_name': '/dev/sdb', 'mappings': mappings}
|
||||
|
||||
root_device_name = ec2utils.properties_root_device_name(properties0)
|
||||
self.assertEqual(root_device_name, '/dev/sda1')
|
||||
|
||||
root_device_name = ec2utils.properties_root_device_name(properties1)
|
||||
self.assertEqual(root_device_name, '/dev/sdb')
|
||||
|
||||
def test_mapping_prepend_dev(self):
|
||||
mappings = [
|
||||
{'virtual': 'ami',
|
||||
'device': 'sda1'},
|
||||
{'virtual': 'root',
|
||||
'device': '/dev/sda1'},
|
||||
|
||||
{'virtual': 'swap',
|
||||
'device': 'sdb1'},
|
||||
{'virtual': 'swap',
|
||||
'device': '/dev/sdb2'},
|
||||
|
||||
{'virtual': 'ephemeral0',
|
||||
'device': 'sdc1'},
|
||||
{'virtual': 'ephemeral1',
|
||||
'device': '/dev/sdc1'}]
|
||||
expected_result = [
|
||||
{'virtual': 'ami',
|
||||
'device': 'sda1'},
|
||||
{'virtual': 'root',
|
||||
'device': '/dev/sda1'},
|
||||
|
||||
{'virtual': 'swap',
|
||||
'device': '/dev/sdb1'},
|
||||
{'virtual': 'swap',
|
||||
'device': '/dev/sdb2'},
|
||||
|
||||
{'virtual': 'ephemeral0',
|
||||
'device': '/dev/sdc1'},
|
||||
{'virtual': 'ephemeral1',
|
||||
'device': '/dev/sdc1'}]
|
||||
self.assertDictListMatch(ec2utils.mappings_prepend_dev(mappings),
|
||||
expected_result)
|
||||
|
||||
|
||||
class ApiEc2TestCase(test.TestCase):
|
||||
|
@@ -45,7 +45,8 @@ LOG = logging.getLogger('nova.tests.cloud')
|
||||
class CloudTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(CloudTestCase, self).setUp()
|
||||
self.flags(connection_type='fake')
|
||||
self.flags(connection_type='fake',
|
||||
stub_network=True)
|
||||
|
||||
self.conn = rpc.Connection.instance()
|
||||
|
||||
@@ -290,7 +291,7 @@ class CloudTestCase(test.TestCase):
|
||||
vol2 = db.volume_create(self.context, {})
|
||||
result = self.cloud.describe_volumes(self.context)
|
||||
self.assertEqual(len(result['volumeSet']), 2)
|
||||
volume_id = ec2utils.id_to_ec2_id(vol2['id'], 'vol-%08x')
|
||||
volume_id = ec2utils.id_to_ec2_vol_id(vol2['id'])
|
||||
result = self.cloud.describe_volumes(self.context,
|
||||
volume_id=[volume_id])
|
||||
self.assertEqual(len(result['volumeSet']), 1)
|
||||
@@ -306,7 +307,7 @@ class CloudTestCase(test.TestCase):
|
||||
snap = db.snapshot_create(self.context, {'volume_id': vol['id'],
|
||||
'volume_size': vol['size'],
|
||||
'status': "available"})
|
||||
snapshot_id = ec2utils.id_to_ec2_id(snap['id'], 'snap-%08x')
|
||||
snapshot_id = ec2utils.id_to_ec2_snap_id(snap['id'])
|
||||
|
||||
result = self.cloud.create_volume(self.context,
|
||||
snapshot_id=snapshot_id)
|
||||
@@ -345,7 +346,7 @@ class CloudTestCase(test.TestCase):
|
||||
snap2 = db.snapshot_create(self.context, {'volume_id': vol['id']})
|
||||
result = self.cloud.describe_snapshots(self.context)
|
||||
self.assertEqual(len(result['snapshotSet']), 2)
|
||||
snapshot_id = ec2utils.id_to_ec2_id(snap2['id'], 'snap-%08x')
|
||||
snapshot_id = ec2utils.id_to_ec2_snap_id(snap2['id'])
|
||||
result = self.cloud.describe_snapshots(self.context,
|
||||
snapshot_id=[snapshot_id])
|
||||
self.assertEqual(len(result['snapshotSet']), 1)
|
||||
@@ -359,7 +360,7 @@ class CloudTestCase(test.TestCase):
|
||||
def test_create_snapshot(self):
|
||||
"""Makes sure create_snapshot works."""
|
||||
vol = db.volume_create(self.context, {'status': "available"})
|
||||
volume_id = ec2utils.id_to_ec2_id(vol['id'], 'vol-%08x')
|
||||
volume_id = ec2utils.id_to_ec2_vol_id(vol['id'])
|
||||
|
||||
result = self.cloud.create_snapshot(self.context,
|
||||
volume_id=volume_id)
|
||||
@@ -376,7 +377,7 @@ class CloudTestCase(test.TestCase):
|
||||
vol = db.volume_create(self.context, {'status': "available"})
|
||||
snap = db.snapshot_create(self.context, {'volume_id': vol['id'],
|
||||
'status': "available"})
|
||||
snapshot_id = ec2utils.id_to_ec2_id(snap['id'], 'snap-%08x')
|
||||
snapshot_id = ec2utils.id_to_ec2_snap_id(snap['id'])
|
||||
|
||||
result = self.cloud.delete_snapshot(self.context,
|
||||
snapshot_id=snapshot_id)
|
||||
@@ -415,6 +416,185 @@ class CloudTestCase(test.TestCase):
|
||||
db.service_destroy(self.context, comp1['id'])
|
||||
db.service_destroy(self.context, comp2['id'])
|
||||
|
||||
def _block_device_mapping_create(self, instance_id, mappings):
|
||||
volumes = []
|
||||
for bdm in mappings:
|
||||
db.block_device_mapping_create(self.context, bdm)
|
||||
if 'volume_id' in bdm:
|
||||
values = {'id': bdm['volume_id']}
|
||||
for bdm_key, vol_key in [('snapshot_id', 'snapshot_id'),
|
||||
('snapshot_size', 'volume_size'),
|
||||
('delete_on_termination',
|
||||
'delete_on_termination')]:
|
||||
if bdm_key in bdm:
|
||||
values[vol_key] = bdm[bdm_key]
|
||||
vol = db.volume_create(self.context, values)
|
||||
db.volume_attached(self.context, vol['id'],
|
||||
instance_id, bdm['device_name'])
|
||||
volumes.append(vol)
|
||||
return volumes
|
||||
|
||||
def _setUpBlockDeviceMapping(self):
|
||||
inst1 = db.instance_create(self.context,
|
||||
{'image_ref': 1,
|
||||
'root_device_name': '/dev/sdb1'})
|
||||
inst2 = db.instance_create(self.context,
|
||||
{'image_ref': 2,
|
||||
'root_device_name': '/dev/sdc1'})
|
||||
|
||||
instance_id = inst1['id']
|
||||
mappings0 = [
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb1',
|
||||
'snapshot_id': '1',
|
||||
'volume_id': '2'},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb2',
|
||||
'volume_id': '3',
|
||||
'volume_size': 1},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb3',
|
||||
'delete_on_termination': True,
|
||||
'snapshot_id': '4',
|
||||
'volume_id': '5'},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb4',
|
||||
'delete_on_termination': False,
|
||||
'snapshot_id': '6',
|
||||
'volume_id': '7'},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb5',
|
||||
'snapshot_id': '8',
|
||||
'volume_id': '9',
|
||||
'volume_size': 0},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb6',
|
||||
'snapshot_id': '10',
|
||||
'volume_id': '11',
|
||||
'volume_size': 1},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb7',
|
||||
'no_device': True},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb8',
|
||||
'virtual_name': 'swap'},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb9',
|
||||
'virtual_name': 'ephemeral3'}]
|
||||
|
||||
volumes = self._block_device_mapping_create(instance_id, mappings0)
|
||||
return (inst1, inst2, volumes)
|
||||
|
||||
def _tearDownBlockDeviceMapping(self, inst1, inst2, volumes):
|
||||
for vol in volumes:
|
||||
db.volume_destroy(self.context, vol['id'])
|
||||
for id in (inst1['id'], inst2['id']):
|
||||
for bdm in db.block_device_mapping_get_all_by_instance(
|
||||
self.context, id):
|
||||
db.block_device_mapping_destroy(self.context, bdm['id'])
|
||||
db.instance_destroy(self.context, inst2['id'])
|
||||
db.instance_destroy(self.context, inst1['id'])
|
||||
|
||||
_expected_instance_bdm1 = {
|
||||
'instanceId': 'i-00000001',
|
||||
'rootDeviceName': '/dev/sdb1',
|
||||
'rootDeviceType': 'ebs'}
|
||||
|
||||
_expected_block_device_mapping0 = [
|
||||
{'deviceName': '/dev/sdb1',
|
||||
'ebs': {'status': 'in-use',
|
||||
'deleteOnTermination': False,
|
||||
'volumeId': 2,
|
||||
}},
|
||||
{'deviceName': '/dev/sdb2',
|
||||
'ebs': {'status': 'in-use',
|
||||
'deleteOnTermination': False,
|
||||
'volumeId': 3,
|
||||
}},
|
||||
{'deviceName': '/dev/sdb3',
|
||||
'ebs': {'status': 'in-use',
|
||||
'deleteOnTermination': True,
|
||||
'volumeId': 5,
|
||||
}},
|
||||
{'deviceName': '/dev/sdb4',
|
||||
'ebs': {'status': 'in-use',
|
||||
'deleteOnTermination': False,
|
||||
'volumeId': 7,
|
||||
}},
|
||||
{'deviceName': '/dev/sdb5',
|
||||
'ebs': {'status': 'in-use',
|
||||
'deleteOnTermination': False,
|
||||
'volumeId': 9,
|
||||
}},
|
||||
{'deviceName': '/dev/sdb6',
|
||||
'ebs': {'status': 'in-use',
|
||||
'deleteOnTermination': False,
|
||||
'volumeId': 11, }}]
|
||||
# NOTE(yamahata): swap/ephemeral device case isn't supported yet.
|
||||
|
||||
_expected_instance_bdm2 = {
|
||||
'instanceId': 'i-00000002',
|
||||
'rootDeviceName': '/dev/sdc1',
|
||||
'rootDeviceType': 'instance-store'}
|
||||
|
||||
def test_format_instance_bdm(self):
|
||||
(inst1, inst2, volumes) = self._setUpBlockDeviceMapping()
|
||||
|
||||
result = {}
|
||||
self.cloud._format_instance_bdm(self.context, inst1['id'], '/dev/sdb1',
|
||||
result)
|
||||
self.assertSubDictMatch(
|
||||
{'rootDeviceType': self._expected_instance_bdm1['rootDeviceType']},
|
||||
result)
|
||||
self._assertEqualBlockDeviceMapping(
|
||||
self._expected_block_device_mapping0, result['blockDeviceMapping'])
|
||||
|
||||
result = {}
|
||||
self.cloud._format_instance_bdm(self.context, inst2['id'], '/dev/sdc1',
|
||||
result)
|
||||
self.assertSubDictMatch(
|
||||
{'rootDeviceType': self._expected_instance_bdm2['rootDeviceType']},
|
||||
result)
|
||||
|
||||
self._tearDownBlockDeviceMapping(inst1, inst2, volumes)
|
||||
|
||||
def _assertInstance(self, instance_id):
|
||||
ec2_instance_id = ec2utils.id_to_ec2_id(instance_id)
|
||||
result = self.cloud.describe_instances(self.context,
|
||||
instance_id=[ec2_instance_id])
|
||||
result = result['reservationSet'][0]
|
||||
self.assertEqual(len(result['instancesSet']), 1)
|
||||
result = result['instancesSet'][0]
|
||||
self.assertEqual(result['instanceId'], ec2_instance_id)
|
||||
return result
|
||||
|
||||
def _assertEqualBlockDeviceMapping(self, expected, result):
|
||||
self.assertEqual(len(expected), len(result))
|
||||
for x in expected:
|
||||
found = False
|
||||
for y in result:
|
||||
if x['deviceName'] == y['deviceName']:
|
||||
self.assertSubDictMatch(x, y)
|
||||
found = True
|
||||
break
|
||||
self.assertTrue(found)
|
||||
|
||||
def test_describe_instances_bdm(self):
|
||||
"""Make sure describe_instances works with root_device_name and
|
||||
block device mappings
|
||||
"""
|
||||
(inst1, inst2, volumes) = self._setUpBlockDeviceMapping()
|
||||
|
||||
result = self._assertInstance(inst1['id'])
|
||||
self.assertSubDictMatch(self._expected_instance_bdm1, result)
|
||||
self._assertEqualBlockDeviceMapping(
|
||||
self._expected_block_device_mapping0, result['blockDeviceMapping'])
|
||||
|
||||
result = self._assertInstance(inst2['id'])
|
||||
self.assertSubDictMatch(self._expected_instance_bdm2, result)
|
||||
|
||||
self._tearDownBlockDeviceMapping(inst1, inst2, volumes)
|
||||
|
||||
def test_describe_images(self):
|
||||
describe_images = self.cloud.describe_images
|
||||
|
||||
@@ -445,6 +625,161 @@ class CloudTestCase(test.TestCase):
|
||||
self.assertRaises(exception.ImageNotFound, describe_images,
|
||||
self.context, ['ami-fake'])
|
||||
|
||||
def assertDictListUnorderedMatch(self, L1, L2, key):
|
||||
self.assertEqual(len(L1), len(L2))
|
||||
for d1 in L1:
|
||||
self.assertTrue(key in d1)
|
||||
for d2 in L2:
|
||||
self.assertTrue(key in d2)
|
||||
if d1[key] == d2[key]:
|
||||
self.assertDictMatch(d1, d2)
|
||||
|
||||
def _setUpImageSet(self, create_volumes_and_snapshots=False):
|
||||
mappings1 = [
|
||||
{'device': '/dev/sda1', 'virtual': 'root'},
|
||||
|
||||
{'device': 'sdb0', 'virtual': 'ephemeral0'},
|
||||
{'device': 'sdb1', 'virtual': 'ephemeral1'},
|
||||
{'device': 'sdb2', 'virtual': 'ephemeral2'},
|
||||
{'device': 'sdb3', 'virtual': 'ephemeral3'},
|
||||
{'device': 'sdb4', 'virtual': 'ephemeral4'},
|
||||
|
||||
{'device': 'sdc0', 'virtual': 'swap'},
|
||||
{'device': 'sdc1', 'virtual': 'swap'},
|
||||
{'device': 'sdc2', 'virtual': 'swap'},
|
||||
{'device': 'sdc3', 'virtual': 'swap'},
|
||||
{'device': 'sdc4', 'virtual': 'swap'}]
|
||||
block_device_mapping1 = [
|
||||
{'device_name': '/dev/sdb1', 'snapshot_id': 01234567},
|
||||
{'device_name': '/dev/sdb2', 'volume_id': 01234567},
|
||||
{'device_name': '/dev/sdb3', 'virtual_name': 'ephemeral5'},
|
||||
{'device_name': '/dev/sdb4', 'no_device': True},
|
||||
|
||||
{'device_name': '/dev/sdc1', 'snapshot_id': 12345678},
|
||||
{'device_name': '/dev/sdc2', 'volume_id': 12345678},
|
||||
{'device_name': '/dev/sdc3', 'virtual_name': 'ephemeral6'},
|
||||
{'device_name': '/dev/sdc4', 'no_device': True}]
|
||||
image1 = {
|
||||
'id': 1,
|
||||
'properties': {
|
||||
'kernel_id': 1,
|
||||
'type': 'machine',
|
||||
'image_state': 'available',
|
||||
'mappings': mappings1,
|
||||
'block_device_mapping': block_device_mapping1,
|
||||
}
|
||||
}
|
||||
|
||||
mappings2 = [{'device': '/dev/sda1', 'virtual': 'root'}]
|
||||
block_device_mapping2 = [{'device_name': '/dev/sdb1',
|
||||
'snapshot_id': 01234567}]
|
||||
image2 = {
|
||||
'id': 2,
|
||||
'properties': {
|
||||
'kernel_id': 2,
|
||||
'type': 'machine',
|
||||
'root_device_name': '/dev/sdb1',
|
||||
'mappings': mappings2,
|
||||
'block_device_mapping': block_device_mapping2}}
|
||||
|
||||
def fake_show(meh, context, image_id):
|
||||
for i in [image1, image2]:
|
||||
if i['id'] == image_id:
|
||||
return i
|
||||
raise exception.ImageNotFound(image_id=image_id)
|
||||
|
||||
def fake_detail(meh, context):
|
||||
return [image1, image2]
|
||||
|
||||
self.stubs.Set(fake._FakeImageService, 'show', fake_show)
|
||||
self.stubs.Set(fake._FakeImageService, 'detail', fake_detail)
|
||||
|
||||
volumes = []
|
||||
snapshots = []
|
||||
if create_volumes_and_snapshots:
|
||||
for bdm in block_device_mapping1:
|
||||
if 'volume_id' in bdm:
|
||||
vol = self._volume_create(bdm['volume_id'])
|
||||
volumes.append(vol['id'])
|
||||
if 'snapshot_id' in bdm:
|
||||
snap = db.snapshot_create(self.context,
|
||||
{'id': bdm['snapshot_id'],
|
||||
'volume_id': 76543210,
|
||||
'status': "available",
|
||||
'volume_size': 1})
|
||||
snapshots.append(snap['id'])
|
||||
return (volumes, snapshots)
|
||||
|
||||
def _assertImageSet(self, result, root_device_type, root_device_name):
|
||||
self.assertEqual(1, len(result['imagesSet']))
|
||||
result = result['imagesSet'][0]
|
||||
self.assertTrue('rootDeviceType' in result)
|
||||
self.assertEqual(result['rootDeviceType'], root_device_type)
|
||||
self.assertTrue('rootDeviceName' in result)
|
||||
self.assertEqual(result['rootDeviceName'], root_device_name)
|
||||
self.assertTrue('blockDeviceMapping' in result)
|
||||
|
||||
return result
|
||||
|
||||
_expected_root_device_name1 = '/dev/sda1'
|
||||
# NOTE(yamahata): noDevice doesn't make sense when returning mapping
|
||||
# It makes sense only when user overriding existing
|
||||
# mapping.
|
||||
_expected_bdms1 = [
|
||||
{'deviceName': '/dev/sdb0', 'virtualName': 'ephemeral0'},
|
||||
{'deviceName': '/dev/sdb1', 'ebs': {'snapshotId':
|
||||
'snap-00053977'}},
|
||||
{'deviceName': '/dev/sdb2', 'ebs': {'snapshotId':
|
||||
'vol-00053977'}},
|
||||
{'deviceName': '/dev/sdb3', 'virtualName': 'ephemeral5'},
|
||||
# {'deviceName': '/dev/sdb4', 'noDevice': True},
|
||||
|
||||
{'deviceName': '/dev/sdc0', 'virtualName': 'swap'},
|
||||
{'deviceName': '/dev/sdc1', 'ebs': {'snapshotId':
|
||||
'snap-00bc614e'}},
|
||||
{'deviceName': '/dev/sdc2', 'ebs': {'snapshotId':
|
||||
'vol-00bc614e'}},
|
||||
{'deviceName': '/dev/sdc3', 'virtualName': 'ephemeral6'},
|
||||
# {'deviceName': '/dev/sdc4', 'noDevice': True}
|
||||
]
|
||||
|
||||
_expected_root_device_name2 = '/dev/sdb1'
|
||||
_expected_bdms2 = [{'deviceName': '/dev/sdb1',
|
||||
'ebs': {'snapshotId': 'snap-00053977'}}]
|
||||
|
||||
# NOTE(yamahata):
|
||||
# InstanceBlockDeviceMappingItemType
|
||||
# rootDeviceType
|
||||
# rootDeviceName
|
||||
# blockDeviceMapping
|
||||
# deviceName
|
||||
# virtualName
|
||||
# ebs
|
||||
# snapshotId
|
||||
# volumeSize
|
||||
# deleteOnTermination
|
||||
# noDevice
|
||||
def test_describe_image_mapping(self):
|
||||
"""test for rootDeviceName and blockDeiceMapping"""
|
||||
describe_images = self.cloud.describe_images
|
||||
self._setUpImageSet()
|
||||
|
||||
result = describe_images(self.context, ['ami-00000001'])
|
||||
result = self._assertImageSet(result, 'instance-store',
|
||||
self._expected_root_device_name1)
|
||||
|
||||
self.assertDictListUnorderedMatch(result['blockDeviceMapping'],
|
||||
self._expected_bdms1, 'deviceName')
|
||||
|
||||
result = describe_images(self.context, ['ami-00000002'])
|
||||
result = self._assertImageSet(result, 'ebs',
|
||||
self._expected_root_device_name2)
|
||||
|
||||
self.assertDictListUnorderedMatch(result['blockDeviceMapping'],
|
||||
self._expected_bdms2, 'deviceName')
|
||||
|
||||
self.stubs.UnsetAll()
|
||||
|
||||
def test_describe_image_attribute(self):
|
||||
describe_image_attribute = self.cloud.describe_image_attribute
|
||||
|
||||
@@ -459,6 +794,32 @@ class CloudTestCase(test.TestCase):
|
||||
'launchPermission')
|
||||
self.assertEqual([{'group': 'all'}], result['launchPermission'])
|
||||
|
||||
def test_describe_image_attribute_root_device_name(self):
|
||||
describe_image_attribute = self.cloud.describe_image_attribute
|
||||
self._setUpImageSet()
|
||||
|
||||
result = describe_image_attribute(self.context, 'ami-00000001',
|
||||
'rootDeviceName')
|
||||
self.assertEqual(result['rootDeviceName'],
|
||||
self._expected_root_device_name1)
|
||||
result = describe_image_attribute(self.context, 'ami-00000002',
|
||||
'rootDeviceName')
|
||||
self.assertEqual(result['rootDeviceName'],
|
||||
self._expected_root_device_name2)
|
||||
|
||||
def test_describe_image_attribute_block_device_mapping(self):
|
||||
describe_image_attribute = self.cloud.describe_image_attribute
|
||||
self._setUpImageSet()
|
||||
|
||||
result = describe_image_attribute(self.context, 'ami-00000001',
|
||||
'blockDeviceMapping')
|
||||
self.assertDictListUnorderedMatch(result['blockDeviceMapping'],
|
||||
self._expected_bdms1, 'deviceName')
|
||||
result = describe_image_attribute(self.context, 'ami-00000002',
|
||||
'blockDeviceMapping')
|
||||
self.assertDictListUnorderedMatch(result['blockDeviceMapping'],
|
||||
self._expected_bdms2, 'deviceName')
|
||||
|
||||
def test_modify_image_attribute(self):
|
||||
modify_image_attribute = self.cloud.modify_image_attribute
|
||||
|
||||
@@ -699,7 +1060,7 @@ class CloudTestCase(test.TestCase):
|
||||
def test_update_of_volume_display_fields(self):
|
||||
vol = db.volume_create(self.context, {})
|
||||
self.cloud.update_volume(self.context,
|
||||
ec2utils.id_to_ec2_id(vol['id'], 'vol-%08x'),
|
||||
ec2utils.id_to_ec2_vol_id(vol['id']),
|
||||
display_name='c00l v0lum3')
|
||||
vol = db.volume_get(self.context, vol['id'])
|
||||
self.assertEqual('c00l v0lum3', vol['display_name'])
|
||||
@@ -708,7 +1069,7 @@ class CloudTestCase(test.TestCase):
|
||||
def test_update_of_volume_wont_update_private_fields(self):
|
||||
vol = db.volume_create(self.context, {})
|
||||
self.cloud.update_volume(self.context,
|
||||
ec2utils.id_to_ec2_id(vol['id'], 'vol-%08x'),
|
||||
ec2utils.id_to_ec2_vol_id(vol['id']),
|
||||
mountpoint='/not/here')
|
||||
vol = db.volume_get(self.context, vol['id'])
|
||||
self.assertEqual(None, vol['mountpoint'])
|
||||
@@ -786,11 +1147,13 @@ class CloudTestCase(test.TestCase):
|
||||
|
||||
self._restart_compute_service()
|
||||
|
||||
def _volume_create(self):
|
||||
def _volume_create(self, volume_id=None):
|
||||
kwargs = {'status': 'available',
|
||||
'host': self.volume.host,
|
||||
'size': 1,
|
||||
'attach_status': 'detached', }
|
||||
if volume_id:
|
||||
kwargs['id'] = volume_id
|
||||
return db.volume_create(self.context, kwargs)
|
||||
|
||||
def _assert_volume_attached(self, vol, instance_id, mountpoint):
|
||||
@@ -819,10 +1182,10 @@ class CloudTestCase(test.TestCase):
|
||||
'max_count': 1,
|
||||
'block_device_mapping': [{'device_name': '/dev/vdb',
|
||||
'volume_id': vol1['id'],
|
||||
'delete_on_termination': False, },
|
||||
'delete_on_termination': False},
|
||||
{'device_name': '/dev/vdc',
|
||||
'volume_id': vol2['id'],
|
||||
'delete_on_termination': True, },
|
||||
'delete_on_termination': True},
|
||||
]}
|
||||
ec2_instance_id = self._run_instance_wait(**kwargs)
|
||||
instance_id = ec2utils.ec2_id_to_id(ec2_instance_id)
|
||||
@@ -954,7 +1317,7 @@ class CloudTestCase(test.TestCase):
|
||||
def test_run_with_snapshot(self):
|
||||
"""Makes sure run/stop/start instance with snapshot works."""
|
||||
vol = self._volume_create()
|
||||
ec2_volume_id = ec2utils.id_to_ec2_id(vol['id'], 'vol-%08x')
|
||||
ec2_volume_id = ec2utils.id_to_ec2_vol_id(vol['id'])
|
||||
|
||||
ec2_snapshot1_id = self._create_snapshot(ec2_volume_id)
|
||||
snapshot1_id = ec2utils.ec2_id_to_id(ec2_snapshot1_id)
|
||||
@@ -1013,3 +1376,33 @@ class CloudTestCase(test.TestCase):
|
||||
self.cloud.delete_snapshot(self.context, snapshot_id)
|
||||
greenthread.sleep(0.3)
|
||||
db.volume_destroy(self.context, vol['id'])
|
||||
|
||||
def test_create_image(self):
|
||||
"""Make sure that CreateImage works"""
|
||||
# enforce periodic tasks run in short time to avoid wait for 60s.
|
||||
self._restart_compute_service(periodic_interval=0.3)
|
||||
|
||||
(volumes, snapshots) = self._setUpImageSet(
|
||||
create_volumes_and_snapshots=True)
|
||||
|
||||
kwargs = {'image_id': 'ami-1',
|
||||
'instance_type': FLAGS.default_instance_type,
|
||||
'max_count': 1}
|
||||
ec2_instance_id = self._run_instance_wait(**kwargs)
|
||||
|
||||
# TODO(yamahata): s3._s3_create() can't be tested easily by unit test
|
||||
# as there is no unit test for s3.create()
|
||||
## result = self.cloud.create_image(self.context, ec2_instance_id,
|
||||
## no_reboot=True)
|
||||
## ec2_image_id = result['imageId']
|
||||
## created_image = self.cloud.describe_images(self.context,
|
||||
## [ec2_image_id])
|
||||
|
||||
self.cloud.terminate_instances(self.context, [ec2_instance_id])
|
||||
for vol in volumes:
|
||||
db.volume_destroy(self.context, vol)
|
||||
for snap in snapshots:
|
||||
db.snapshot_destroy(self.context, snap)
|
||||
# TODO(yamahata): clean up snapshot created by CreateImage.
|
||||
|
||||
self._restart_compute_service()
|
||||
|
@@ -829,3 +829,114 @@ class ComputeTestCase(test.TestCase):
|
||||
LOG.info(_("After force-killing instances: %s"), instances)
|
||||
self.assertEqual(len(instances), 1)
|
||||
self.assertEqual(power_state.SHUTOFF, instances[0]['state'])
|
||||
|
||||
@staticmethod
|
||||
def _parse_db_block_device_mapping(bdm_ref):
|
||||
attr_list = ('delete_on_termination', 'device_name', 'no_device',
|
||||
'virtual_name', 'volume_id', 'volume_size', 'snapshot_id')
|
||||
bdm = {}
|
||||
for attr in attr_list:
|
||||
val = bdm_ref.get(attr, None)
|
||||
if val:
|
||||
bdm[attr] = val
|
||||
|
||||
return bdm
|
||||
|
||||
def test_update_block_device_mapping(self):
|
||||
instance_id = self._create_instance()
|
||||
mappings = [
|
||||
{'virtual': 'ami', 'device': 'sda1'},
|
||||
{'virtual': 'root', 'device': '/dev/sda1'},
|
||||
|
||||
{'virtual': 'swap', 'device': 'sdb1'},
|
||||
{'virtual': 'swap', 'device': 'sdb2'},
|
||||
{'virtual': 'swap', 'device': 'sdb3'},
|
||||
{'virtual': 'swap', 'device': 'sdb4'},
|
||||
|
||||
{'virtual': 'ephemeral0', 'device': 'sdc1'},
|
||||
{'virtual': 'ephemeral1', 'device': 'sdc2'},
|
||||
{'virtual': 'ephemeral2', 'device': 'sdc3'}]
|
||||
block_device_mapping = [
|
||||
# root
|
||||
{'device_name': '/dev/sda1',
|
||||
'snapshot_id': 0x12345678,
|
||||
'delete_on_termination': False},
|
||||
|
||||
|
||||
# overwrite swap
|
||||
{'device_name': '/dev/sdb2',
|
||||
'snapshot_id': 0x23456789,
|
||||
'delete_on_termination': False},
|
||||
{'device_name': '/dev/sdb3',
|
||||
'snapshot_id': 0x3456789A},
|
||||
{'device_name': '/dev/sdb4',
|
||||
'no_device': True},
|
||||
|
||||
# overwrite ephemeral
|
||||
{'device_name': '/dev/sdc2',
|
||||
'snapshot_id': 0x456789AB,
|
||||
'delete_on_termination': False},
|
||||
{'device_name': '/dev/sdc3',
|
||||
'snapshot_id': 0x56789ABC},
|
||||
{'device_name': '/dev/sdc4',
|
||||
'no_device': True},
|
||||
|
||||
# volume
|
||||
{'device_name': '/dev/sdd1',
|
||||
'snapshot_id': 0x87654321,
|
||||
'delete_on_termination': False},
|
||||
{'device_name': '/dev/sdd2',
|
||||
'snapshot_id': 0x98765432},
|
||||
{'device_name': '/dev/sdd3',
|
||||
'snapshot_id': 0xA9875463},
|
||||
{'device_name': '/dev/sdd4',
|
||||
'no_device': True}]
|
||||
|
||||
self.compute_api._update_image_block_device_mapping(
|
||||
self.context, instance_id, mappings)
|
||||
|
||||
bdms = [self._parse_db_block_device_mapping(bdm_ref)
|
||||
for bdm_ref in db.block_device_mapping_get_all_by_instance(
|
||||
self.context, instance_id)]
|
||||
expected_result = [
|
||||
{'virtual_name': 'swap', 'device_name': '/dev/sdb1'},
|
||||
{'virtual_name': 'swap', 'device_name': '/dev/sdb2'},
|
||||
{'virtual_name': 'swap', 'device_name': '/dev/sdb3'},
|
||||
{'virtual_name': 'swap', 'device_name': '/dev/sdb4'},
|
||||
{'virtual_name': 'ephemeral0', 'device_name': '/dev/sdc1'},
|
||||
{'virtual_name': 'ephemeral1', 'device_name': '/dev/sdc2'},
|
||||
{'virtual_name': 'ephemeral2', 'device_name': '/dev/sdc3'}]
|
||||
bdms.sort()
|
||||
expected_result.sort()
|
||||
self.assertDictListMatch(bdms, expected_result)
|
||||
|
||||
self.compute_api._update_block_device_mapping(
|
||||
self.context, instance_id, block_device_mapping)
|
||||
bdms = [self._parse_db_block_device_mapping(bdm_ref)
|
||||
for bdm_ref in db.block_device_mapping_get_all_by_instance(
|
||||
self.context, instance_id)]
|
||||
expected_result = [
|
||||
{'snapshot_id': 0x12345678, 'device_name': '/dev/sda1'},
|
||||
|
||||
{'virtual_name': 'swap', 'device_name': '/dev/sdb1'},
|
||||
{'snapshot_id': 0x23456789, 'device_name': '/dev/sdb2'},
|
||||
{'snapshot_id': 0x3456789A, 'device_name': '/dev/sdb3'},
|
||||
{'no_device': True, 'device_name': '/dev/sdb4'},
|
||||
|
||||
{'virtual_name': 'ephemeral0', 'device_name': '/dev/sdc1'},
|
||||
{'snapshot_id': 0x456789AB, 'device_name': '/dev/sdc2'},
|
||||
{'snapshot_id': 0x56789ABC, 'device_name': '/dev/sdc3'},
|
||||
{'no_device': True, 'device_name': '/dev/sdc4'},
|
||||
|
||||
{'snapshot_id': 0x87654321, 'device_name': '/dev/sdd1'},
|
||||
{'snapshot_id': 0x98765432, 'device_name': '/dev/sdd2'},
|
||||
{'snapshot_id': 0xA9875463, 'device_name': '/dev/sdd3'},
|
||||
{'no_device': True, 'device_name': '/dev/sdd4'}]
|
||||
bdms.sort()
|
||||
expected_result.sort()
|
||||
self.assertDictListMatch(bdms, expected_result)
|
||||
|
||||
for bdm in db.block_device_mapping_get_all_by_instance(
|
||||
self.context, instance_id):
|
||||
db.block_device_mapping_destroy(self.context, bdm['id'])
|
||||
self.compute.terminate_instance(self.context, instance_id)
|
||||
|
@@ -27,8 +27,10 @@ from nova import exception
|
||||
from nova import db
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
from nova import rpc
|
||||
from nova import test
|
||||
from nova import utils
|
||||
from nova import volume
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
LOG = logging.getLogger('nova.tests.volume')
|
||||
@@ -43,6 +45,11 @@ class VolumeTestCase(test.TestCase):
|
||||
self.flags(connection_type='fake')
|
||||
self.volume = utils.import_object(FLAGS.volume_manager)
|
||||
self.context = context.get_admin_context()
|
||||
self.instance_id = db.instance_create(self.context, {})['id']
|
||||
|
||||
def tearDown(self):
|
||||
db.instance_destroy(self.context, self.instance_id)
|
||||
super(VolumeTestCase, self).tearDown()
|
||||
|
||||
@staticmethod
|
||||
def _create_volume(size='0', snapshot_id=None):
|
||||
@@ -223,6 +230,30 @@ class VolumeTestCase(test.TestCase):
|
||||
snapshot_id)
|
||||
self.volume.delete_volume(self.context, volume_id)
|
||||
|
||||
def test_create_snapshot_force(self):
|
||||
"""Test snapshot in use can be created forcibly."""
|
||||
|
||||
def fake_cast(ctxt, topic, msg):
|
||||
pass
|
||||
self.stubs.Set(rpc, 'cast', fake_cast)
|
||||
|
||||
volume_id = self._create_volume()
|
||||
self.volume.create_volume(self.context, volume_id)
|
||||
db.volume_attached(self.context, volume_id, self.instance_id,
|
||||
'/dev/sda1')
|
||||
|
||||
volume_api = volume.api.API()
|
||||
self.assertRaises(exception.ApiError,
|
||||
volume_api.create_snapshot,
|
||||
self.context, volume_id,
|
||||
'fake_name', 'fake_description')
|
||||
snapshot_ref = volume_api.create_snapshot_force(self.context,
|
||||
volume_id,
|
||||
'fake_name',
|
||||
'fake_description')
|
||||
db.snapshot_destroy(self.context, snapshot_ref['id'])
|
||||
db.volume_destroy(self.context, volume_id)
|
||||
|
||||
|
||||
class DriverTestCase(test.TestCase):
|
||||
"""Base Test class for Drivers."""
|
||||
|
Reference in New Issue
Block a user