Port tests for instance volume manipulation
Change-Id: I41e61a5e6eb82515847cf0108366a7e72cb220af
This commit is contained in:
@@ -1240,10 +1240,10 @@ def _cloud_parse_block_device_mapping(context, bdm):
|
|||||||
if ec2_id:
|
if ec2_id:
|
||||||
if ec2_id.startswith('snap-'):
|
if ec2_id.startswith('snap-'):
|
||||||
snapshot = ec2utils.get_db_item(context, 'snap', ec2_id)
|
snapshot = ec2utils.get_db_item(context, 'snap', ec2_id)
|
||||||
bdm['snapshot_id'] = snapshot['id']
|
bdm['snapshot_id'] = snapshot['os_id']
|
||||||
elif ec2_id.startswith('vol-'):
|
elif ec2_id.startswith('vol-'):
|
||||||
volume = ec2utils.get_db_item(context, 'vol', ec2_id)
|
volume = ec2utils.get_db_item(context, 'vol', ec2_id)
|
||||||
bdm['volume_id'] = volume['id']
|
bdm['volume_id'] = volume['os_id']
|
||||||
else:
|
else:
|
||||||
# NOTE(ft): AWS returns undocumented InvalidSnapshotID.NotFound
|
# NOTE(ft): AWS returns undocumented InvalidSnapshotID.NotFound
|
||||||
raise exception.InvalidSnapshotIDMalformed(snapshot_id=ec2_id)
|
raise exception.InvalidSnapshotIDMalformed(snapshot_id=ec2_id)
|
||||||
|
@@ -50,6 +50,7 @@ class ApiTestCase(test_base.BaseTestCase):
|
|||||||
self.nova_security_groups = nova_mock.return_value.security_groups
|
self.nova_security_groups = nova_mock.return_value.security_groups
|
||||||
self.nova_security_group_rules = (
|
self.nova_security_group_rules = (
|
||||||
nova_mock.return_value.security_group_rules)
|
nova_mock.return_value.security_group_rules)
|
||||||
|
self.nova_volumes = nova_mock.return_value.volumes
|
||||||
self.addCleanup(nova_patcher.stop)
|
self.addCleanup(nova_patcher.stop)
|
||||||
|
|
||||||
glance_patcher = mock.patch('glanceclient.client.Client')
|
glance_patcher = mock.patch('glanceclient.client.Client')
|
||||||
|
@@ -1119,7 +1119,8 @@ EC2_IMAGE_1 = {
|
|||||||
{'deviceName': '/dev/sdb0',
|
{'deviceName': '/dev/sdb0',
|
||||||
'virtualName': 'ephemeral0'},
|
'virtualName': 'ephemeral0'},
|
||||||
{'deviceName': '/dev/sdb1',
|
{'deviceName': '/dev/sdb1',
|
||||||
'ebs': {'snapshotId': ID_EC2_SNAPSHOT_1}},
|
'ebs': {'snapshotId': ID_EC2_SNAPSHOT_1,
|
||||||
|
'volumeSize': 22}},
|
||||||
{'deviceName': '/dev/sdb2',
|
{'deviceName': '/dev/sdb2',
|
||||||
'ebs': {'snapshotId': ID_EC2_VOLUME_1}},
|
'ebs': {'snapshotId': ID_EC2_VOLUME_1}},
|
||||||
{'deviceName': '/dev/sdb3',
|
{'deviceName': '/dev/sdb3',
|
||||||
@@ -1199,7 +1200,8 @@ OS_IMAGE_1 = {
|
|||||||
{'device': 'sdc4', 'virtual': 'swap'}],
|
{'device': 'sdc4', 'virtual': 'swap'}],
|
||||||
'block_device_mapping': [
|
'block_device_mapping': [
|
||||||
{'device_name': '/dev/sdb1',
|
{'device_name': '/dev/sdb1',
|
||||||
'snapshot_id': ID_OS_SNAPSHOT_1},
|
'snapshot_id': ID_OS_SNAPSHOT_1,
|
||||||
|
'volume_size': 22},
|
||||||
{'device_name': '/dev/sdb2',
|
{'device_name': '/dev/sdb2',
|
||||||
'volume_id': ID_OS_VOLUME_1},
|
'volume_id': ID_OS_VOLUME_1},
|
||||||
{'device_name': '/dev/sdb3', 'virtual_name': 'ephemeral5'},
|
{'device_name': '/dev/sdb3', 'virtual_name': 'ephemeral5'},
|
||||||
|
@@ -294,31 +294,39 @@ class InstanceTestCase(base.ApiTestCase):
|
|||||||
mock.call(mock.ANY, 'i', tools.purge_dict(db_instance, ['id']))
|
mock.call(mock.ANY, 'i', tools.purge_dict(db_instance, ['id']))
|
||||||
for db_instance in self.DB_INSTANCES])
|
for db_instance in self.DB_INSTANCES])
|
||||||
|
|
||||||
|
@mock.patch('ec2api.api.instance._parse_block_device_mapping')
|
||||||
@mock.patch('ec2api.api.instance._format_reservation')
|
@mock.patch('ec2api.api.instance._format_reservation')
|
||||||
@mock.patch('ec2api.api.instance.InstanceEngineNeutron.'
|
@mock.patch('ec2api.api.instance.InstanceEngineNeutron.'
|
||||||
'get_ec2_classic_os_network')
|
'get_ec2_classic_os_network')
|
||||||
def test_run_instances_other_parameters(self, get_ec2_classic_os_network,
|
def test_run_instances_other_parameters(self, get_ec2_classic_os_network,
|
||||||
format_reservation):
|
format_reservation,
|
||||||
|
parse_block_device_mapping):
|
||||||
self.glance.images.get.return_value = fakes.OSImage(fakes.OS_IMAGE_1)
|
self.glance.images.get.return_value = fakes.OSImage(fakes.OS_IMAGE_1)
|
||||||
get_ec2_classic_os_network.return_value = {'id': fakes.random_os_id()}
|
get_ec2_classic_os_network.return_value = {'id': fakes.random_os_id()}
|
||||||
format_reservation.return_value = {}
|
format_reservation.return_value = {}
|
||||||
|
parse_block_device_mapping.return_value = 'fake_bdm'
|
||||||
|
|
||||||
def do_check(engine, extra_kwargs={}, extra_db_instance={}):
|
def do_check(engine, extra_kwargs={}, extra_db_instance={}):
|
||||||
instance_api.instance_engine = engine
|
instance_api.instance_engine = engine
|
||||||
|
|
||||||
resp = self.execute('RunInstances',
|
resp = self.execute(
|
||||||
{'ImageId': fakes.ID_EC2_IMAGE_1,
|
'RunInstances',
|
||||||
'InstanceType': 'fake_flavor',
|
{'ImageId': fakes.ID_EC2_IMAGE_1,
|
||||||
'MinCount': '1', 'MaxCount': '1',
|
'InstanceType': 'fake_flavor',
|
||||||
'SecurityGroup.1': 'Default',
|
'MinCount': '1', 'MaxCount': '1',
|
||||||
'Placement.AvailabilityZone': 'fake_zone',
|
'SecurityGroup.1': 'Default',
|
||||||
'ClientToken': 'fake_client_token'})
|
'Placement.AvailabilityZone': 'fake_zone',
|
||||||
|
'ClientToken': 'fake_client_token',
|
||||||
|
'BlockDeviceMapping.1.DeviceName': '/dev/vdd',
|
||||||
|
'BlockDeviceMapping.1.Ebs.SnapshotId': (
|
||||||
|
fakes.ID_EC2_SNAPSHOT_1),
|
||||||
|
'BlockDeviceMapping.1.Ebs.DeleteOnTermination': 'False'})
|
||||||
self.assertEqual(200, resp['http_status_code'])
|
self.assertEqual(200, resp['http_status_code'])
|
||||||
|
|
||||||
self.nova_servers.create.assert_called_once_with(
|
self.nova_servers.create.assert_called_once_with(
|
||||||
mock.ANY, mock.ANY, mock.ANY, min_count=1, max_count=1,
|
mock.ANY, mock.ANY, mock.ANY, min_count=1, max_count=1,
|
||||||
userdata=None, block_device_mapping=None,
|
userdata=None, kernel_id=None, ramdisk_id=None, key_name=None,
|
||||||
kernel_id=None, ramdisk_id=None, key_name=None,
|
block_device_mapping='fake_bdm',
|
||||||
availability_zone='fake_zone', security_groups=['Default'],
|
availability_zone='fake_zone', security_groups=['Default'],
|
||||||
**extra_kwargs)
|
**extra_kwargs)
|
||||||
self.nova_servers.reset_mock()
|
self.nova_servers.reset_mock()
|
||||||
@@ -330,6 +338,13 @@ class InstanceTestCase(base.ApiTestCase):
|
|||||||
self.db_api.add_item.assert_called_once_with(
|
self.db_api.add_item.assert_called_once_with(
|
||||||
mock.ANY, 'i', db_instance)
|
mock.ANY, 'i', db_instance)
|
||||||
self.db_api.reset_mock()
|
self.db_api.reset_mock()
|
||||||
|
parse_block_device_mapping.assert_called_once_with(
|
||||||
|
mock.ANY,
|
||||||
|
[{'device_name': '/dev/vdd',
|
||||||
|
'ebs': {'snapshot_id': fakes.ID_EC2_SNAPSHOT_1,
|
||||||
|
'delete_on_termination': False}}],
|
||||||
|
self.glance.images.get.return_value)
|
||||||
|
parse_block_device_mapping.reset_mock()
|
||||||
|
|
||||||
do_check(
|
do_check(
|
||||||
instance_api.InstanceEngineNeutron(),
|
instance_api.InstanceEngineNeutron(),
|
||||||
@@ -1147,6 +1162,61 @@ class InstancePrivateTestCase(test_base.BaseTestCase):
|
|||||||
instance_api._parse_image_parameters,
|
instance_api._parse_image_parameters,
|
||||||
fake_context, image_id, None, None)
|
fake_context, image_id, None, None)
|
||||||
|
|
||||||
|
@mock.patch('ec2api.db.api.IMPL')
|
||||||
|
def test_parse_block_device_mapping(self, db_api):
|
||||||
|
fake_context = mock.Mock(service_catalog=[{'type': 'fake'}])
|
||||||
|
os_image = fakes.OSImage(fakes.OS_IMAGE_1)
|
||||||
|
|
||||||
|
db_api.get_item_by_id.side_effect = fakes.get_db_api_get_item_by_id({
|
||||||
|
fakes.ID_EC2_VOLUME_1: fakes.DB_VOLUME_1,
|
||||||
|
fakes.ID_EC2_VOLUME_2: fakes.DB_VOLUME_2,
|
||||||
|
fakes.ID_EC2_VOLUME_3: fakes.DB_VOLUME_3,
|
||||||
|
fakes.ID_EC2_SNAPSHOT_1: fakes.DB_SNAPSHOT_1,
|
||||||
|
fakes.ID_EC2_SNAPSHOT_2: fakes.DB_SNAPSHOT_2})
|
||||||
|
|
||||||
|
res = instance_api._parse_block_device_mapping(
|
||||||
|
fake_context, [], os_image)
|
||||||
|
self.assertEqual([], res)
|
||||||
|
|
||||||
|
res = instance_api._parse_block_device_mapping(
|
||||||
|
fake_context, [{'device_name': '/dev/vdf',
|
||||||
|
'ebs': {'snapshot_id': fakes.ID_EC2_SNAPSHOT_1}},
|
||||||
|
{'device_name': '/dev/vdg',
|
||||||
|
'ebs': {'snapshot_id': fakes.ID_EC2_SNAPSHOT_2,
|
||||||
|
'volume_size': 111,
|
||||||
|
'delete_on_termination': False}},
|
||||||
|
{'device_name': '/dev/vdh',
|
||||||
|
'ebs': {'snapshot_id': fakes.ID_EC2_VOLUME_1}},
|
||||||
|
{'device_name': '/dev/vdi',
|
||||||
|
'ebs': {'snapshot_id': fakes.ID_EC2_VOLUME_2,
|
||||||
|
'delete_on_termination': True}},
|
||||||
|
{'device_name': '/dev/sdb1',
|
||||||
|
'ebs': {'volume_size': 55}}],
|
||||||
|
os_image)
|
||||||
|
self.assertThat(
|
||||||
|
res,
|
||||||
|
matchers.ListMatches([{'device_name': '/dev/vdf',
|
||||||
|
'snapshot_id': fakes.ID_OS_SNAPSHOT_1,
|
||||||
|
'delete_on_termination': True},
|
||||||
|
{'device_name': '/dev/vdg',
|
||||||
|
'snapshot_id': fakes.ID_OS_SNAPSHOT_2,
|
||||||
|
'volume_size': 111,
|
||||||
|
'delete_on_termination': False},
|
||||||
|
{'device_name': '/dev/vdh',
|
||||||
|
'volume_id': fakes.ID_OS_VOLUME_1,
|
||||||
|
'delete_on_termination': True},
|
||||||
|
{'device_name': '/dev/vdi',
|
||||||
|
'volume_id': fakes.ID_OS_VOLUME_2,
|
||||||
|
'delete_on_termination': True},
|
||||||
|
{'device_name': '/dev/sdb1',
|
||||||
|
'snapshot_id': fakes.ID_OS_SNAPSHOT_1,
|
||||||
|
'volume_size': 55,
|
||||||
|
'volume_id': None,
|
||||||
|
'delete_on_termination': None,
|
||||||
|
'virtual_name': None,
|
||||||
|
'no_device': None}],
|
||||||
|
orderless_lists=True))
|
||||||
|
|
||||||
@mock.patch('ec2api.api.instance.novadb')
|
@mock.patch('ec2api.api.instance.novadb')
|
||||||
@mock.patch('novaclient.v1_1.client.Client')
|
@mock.patch('novaclient.v1_1.client.Client')
|
||||||
@mock.patch('ec2api.db.api.IMPL')
|
@mock.patch('ec2api.db.api.IMPL')
|
||||||
|
@@ -149,3 +149,64 @@ class VolumeTestCase(base.ApiTestCase):
|
|||||||
resp = self.execute('DescribeVolumes', {})
|
resp = self.execute('DescribeVolumes', {})
|
||||||
self.assertEqual(200, resp['http_status_code'])
|
self.assertEqual(200, resp['http_status_code'])
|
||||||
self.assertEqual('banana', resp['volumeSet'][0]['status'])
|
self.assertEqual('banana', resp['volumeSet'][0]['status'])
|
||||||
|
|
||||||
|
def test_attach_volume(self):
|
||||||
|
self.db_api.get_item_by_id.side_effect = (
|
||||||
|
fakes.get_db_api_get_item_by_id({
|
||||||
|
fakes.ID_EC2_INSTANCE_2: fakes.DB_INSTANCE_2,
|
||||||
|
fakes.ID_EC2_VOLUME_3: fakes.DB_VOLUME_3}))
|
||||||
|
os_volume = fakes.CinderVolume(fakes.OS_VOLUME_3)
|
||||||
|
os_volume.attachments.append({'device': '/dev/vdf',
|
||||||
|
'server_id': fakes.ID_OS_INSTANCE_2})
|
||||||
|
os_volume.status = 'attaching'
|
||||||
|
self.cinder.volumes.get.return_value = os_volume
|
||||||
|
|
||||||
|
resp = self.execute('AttachVolume',
|
||||||
|
{'VolumeId': fakes.ID_EC2_VOLUME_3,
|
||||||
|
'InstanceId': fakes.ID_EC2_INSTANCE_2,
|
||||||
|
'Device': '/dev/vdf'})
|
||||||
|
self.assertEqual({'http_status_code': 200,
|
||||||
|
'attachTime': None,
|
||||||
|
'device': '/dev/vdf',
|
||||||
|
'instanceId': fakes.ID_EC2_INSTANCE_2,
|
||||||
|
'status': 'attaching',
|
||||||
|
'volumeId': fakes.ID_EC2_VOLUME_3},
|
||||||
|
resp)
|
||||||
|
self.nova_volumes.create_server_volume.assert_called_once_with(
|
||||||
|
fakes.ID_OS_INSTANCE_2, fakes.ID_OS_VOLUME_3, '/dev/vdf')
|
||||||
|
|
||||||
|
@mock.patch.object(fakes.CinderVolume, 'get', autospec=True)
|
||||||
|
def test_detach_volume(self, os_volume_get):
|
||||||
|
self.db_api.get_item_by_id.side_effect = (
|
||||||
|
fakes.get_db_api_get_item_by_id({
|
||||||
|
fakes.ID_EC2_INSTANCE_2: fakes.DB_INSTANCE_2,
|
||||||
|
fakes.ID_EC2_VOLUME_2: fakes.DB_VOLUME_2}))
|
||||||
|
self.db_api.get_items.return_value = [fakes.DB_INSTANCE_1,
|
||||||
|
fakes.DB_INSTANCE_2]
|
||||||
|
os_volume = fakes.CinderVolume(fakes.OS_VOLUME_2)
|
||||||
|
self.cinder.volumes.get.return_value = os_volume
|
||||||
|
os_volume_get.side_effect = (
|
||||||
|
lambda vol: setattr(vol, 'status', 'detaching'))
|
||||||
|
|
||||||
|
resp = self.execute('DetachVolume',
|
||||||
|
{'VolumeId': fakes.ID_EC2_VOLUME_2})
|
||||||
|
self.assertEqual({'http_status_code': 200,
|
||||||
|
'attachTime': None,
|
||||||
|
'device': os_volume.attachments[0]['device'],
|
||||||
|
'instanceId': fakes.ID_EC2_INSTANCE_2,
|
||||||
|
'status': 'detaching',
|
||||||
|
'volumeId': fakes.ID_EC2_VOLUME_2},
|
||||||
|
resp)
|
||||||
|
self.nova_volumes.delete_server_volume.assert_called_once_with(
|
||||||
|
fakes.ID_OS_INSTANCE_2, fakes.ID_OS_VOLUME_2)
|
||||||
|
self.cinder.volumes.get.assert_called_once_with(fakes.ID_OS_VOLUME_2)
|
||||||
|
|
||||||
|
def test_detach_volume_invalid_parameters(self):
|
||||||
|
self.db_api.get_item_by_id.return_value = fakes.DB_VOLUME_1
|
||||||
|
self.cinder.volumes.get.return_value = (
|
||||||
|
fakes.CinderVolume(fakes.OS_VOLUME_1))
|
||||||
|
|
||||||
|
resp = self.execute('DetachVolume',
|
||||||
|
{'VolumeId': fakes.ID_EC2_VOLUME_1})
|
||||||
|
self.assertEqual(400, resp['http_status_code'])
|
||||||
|
self.assertEqual('IncorrectState', resp['Error']['Code'])
|
||||||
|
Reference in New Issue
Block a user