merge with 1305
This commit is contained in:
		
							
								
								
									
										1
									
								
								Authors
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Authors
									
									
									
									
									
								
							| @@ -1,3 +1,4 @@ | |||||||
|  | Adam Gandelman <adamg@canonical.com> | ||||||
| Alex Meade <alex.meade@rackspace.com> | Alex Meade <alex.meade@rackspace.com> | ||||||
| Alexander Sakhnov <asakhnov@mirantis.com> | Alexander Sakhnov <asakhnov@mirantis.com> | ||||||
| Andrey Brindeyev <abrindeyev@griddynamics.com> | Andrey Brindeyev <abrindeyev@griddynamics.com> | ||||||
|   | |||||||
| @@ -91,7 +91,7 @@ def init_leases(interface): | |||||||
|     """Get the list of hosts for an interface.""" |     """Get the list of hosts for an interface.""" | ||||||
|     ctxt = context.get_admin_context() |     ctxt = context.get_admin_context() | ||||||
|     network_ref = db.network_get_by_bridge(ctxt, interface) |     network_ref = db.network_get_by_bridge(ctxt, interface) | ||||||
|     return linux_net.get_dhcp_leases(ctxt, network_ref['id']) |     return linux_net.get_dhcp_leases(ctxt, network_ref) | ||||||
|  |  | ||||||
|  |  | ||||||
| def main(): | def main(): | ||||||
|   | |||||||
| @@ -484,7 +484,7 @@ class ProjectCommands(object): | |||||||
|         except db.api.NoMoreNetworks: |         except db.api.NoMoreNetworks: | ||||||
|             print _('No more networks available. If this is a new ' |             print _('No more networks available. If this is a new ' | ||||||
|                     'installation, you need\nto call something like this:\n\n' |                     'installation, you need\nto call something like this:\n\n' | ||||||
|                     '    nova-manage network create 10.0.0.0/8 10 64\n\n') |                     '  nova-manage network create pvt 10.0.0.0/8 10 64\n\n') | ||||||
|         except exception.ProcessExecutionError, e: |         except exception.ProcessExecutionError, e: | ||||||
|             print e |             print e | ||||||
|             print _("The above error may show that the certificate db has not " |             print _("The above error may show that the certificate db has not " | ||||||
| @@ -505,7 +505,7 @@ class FixedIpCommands(object): | |||||||
|             if host is None: |             if host is None: | ||||||
|                 fixed_ips = db.fixed_ip_get_all(ctxt) |                 fixed_ips = db.fixed_ip_get_all(ctxt) | ||||||
|             else: |             else: | ||||||
|                 fixed_ips = db.fixed_ip_get_all_by_host(ctxt, host) |                 fixed_ips = db.fixed_ip_get_all_by_instance_host(ctxt, host) | ||||||
|         except exception.NotFound as ex: |         except exception.NotFound as ex: | ||||||
|             print "error: %s" % ex |             print "error: %s" % ex | ||||||
|             sys.exit(2) |             sys.exit(2) | ||||||
| @@ -523,7 +523,7 @@ class FixedIpCommands(object): | |||||||
|                 instance = fixed_ip['instance'] |                 instance = fixed_ip['instance'] | ||||||
|                 hostname = instance['hostname'] |                 hostname = instance['hostname'] | ||||||
|                 host = instance['host'] |                 host = instance['host'] | ||||||
|                 mac_address = fixed_ip['mac_address']['address'] |                 mac_address = fixed_ip['virtual_interface']['address'] | ||||||
|             print "%-18s\t%-15s\t%-17s\t%-15s\t%s" % ( |             print "%-18s\t%-15s\t%-17s\t%-15s\t%s" % ( | ||||||
|                     fixed_ip['network']['cidr'], |                     fixed_ip['network']['cidr'], | ||||||
|                     fixed_ip['address'], |                     fixed_ip['address'], | ||||||
| @@ -569,17 +569,17 @@ class NetworkCommands(object): | |||||||
|     """Class for managing networks.""" |     """Class for managing networks.""" | ||||||
|  |  | ||||||
|     def create(self, label=None, fixed_range=None, num_networks=None, |     def create(self, label=None, fixed_range=None, num_networks=None, | ||||||
|                network_size=None, vlan_start=None, |                network_size=None, multi_host=None, vlan_start=None, | ||||||
|                vpn_start=None, fixed_range_v6=None, gateway_v6=None, |                vpn_start=None, fixed_range_v6=None, gateway_v6=None, | ||||||
|                flat_network_bridge=None, bridge_interface=None): |                flat_network_bridge=None, bridge_interface=None): | ||||||
|         """Creates fixed ips for host by range |         """Creates fixed ips for host by range | ||||||
|         arguments: label, fixed_range, [num_networks=FLAG], |         arguments: label, fixed_range, [num_networks=FLAG], | ||||||
|                    [network_size=FLAG], [vlan_start=FLAG], |                    [network_size=FLAG], [multi_host=FLAG], [vlan_start=FLAG], | ||||||
|                    [vpn_start=FLAG], [fixed_range_v6=FLAG], [gateway_v6=FLAG], |                    [vpn_start=FLAG], [fixed_range_v6=FLAG], [gateway_v6=FLAG], | ||||||
|                    [flat_network_bridge=FLAG], [bridge_interface=FLAG] |                    [flat_network_bridge=FLAG], [bridge_interface=FLAG] | ||||||
|         If you wish to use a later argument fill in the gaps with 0s |         If you wish to use a later argument fill in the gaps with ""s | ||||||
|         Ex: network create private 10.0.0.0/8 1 15 0 0 0 0 xenbr1 eth1 |         Ex: network create private 10.0.0.0/8 1 16 T "" "" "" "" xenbr1 eth1 | ||||||
|             network create private 10.0.0.0/8 1 15 |             network create private 10.0.0.0/8 1 16 | ||||||
|         """ |         """ | ||||||
|         if not label: |         if not label: | ||||||
|             msg = _('a label (ex: public) is required to create networks.') |             msg = _('a label (ex: public) is required to create networks.') | ||||||
| @@ -594,6 +594,10 @@ class NetworkCommands(object): | |||||||
|             num_networks = FLAGS.num_networks |             num_networks = FLAGS.num_networks | ||||||
|         if not network_size: |         if not network_size: | ||||||
|             network_size = FLAGS.network_size |             network_size = FLAGS.network_size | ||||||
|  |         if not multi_host: | ||||||
|  |             multi_host = FLAGS.multi_host | ||||||
|  |         else: | ||||||
|  |             multi_host = multi_host == 'T' | ||||||
|         if not vlan_start: |         if not vlan_start: | ||||||
|             vlan_start = FLAGS.vlan_start |             vlan_start = FLAGS.vlan_start | ||||||
|         if not vpn_start: |         if not vpn_start: | ||||||
| @@ -612,6 +616,7 @@ class NetworkCommands(object): | |||||||
|             net_manager.create_networks(context.get_admin_context(), |             net_manager.create_networks(context.get_admin_context(), | ||||||
|                                         label=label, |                                         label=label, | ||||||
|                                         cidr=fixed_range, |                                         cidr=fixed_range, | ||||||
|  |                                         multi_host=multi_host, | ||||||
|                                         num_networks=int(num_networks), |                                         num_networks=int(num_networks), | ||||||
|                                         network_size=int(network_size), |                                         network_size=int(network_size), | ||||||
|                                         vlan_start=int(vlan_start), |                                         vlan_start=int(vlan_start), | ||||||
|   | |||||||
| @@ -92,7 +92,9 @@ class XmlConversionTestCase(test.TestCase): | |||||||
|         conv = ec2utils._try_convert |         conv = ec2utils._try_convert | ||||||
|         self.assertEqual(conv('None'), None) |         self.assertEqual(conv('None'), None) | ||||||
|         self.assertEqual(conv('True'), True) |         self.assertEqual(conv('True'), True) | ||||||
|  |         self.assertEqual(conv('true'), True) | ||||||
|         self.assertEqual(conv('False'), False) |         self.assertEqual(conv('False'), False) | ||||||
|  |         self.assertEqual(conv('false'), False) | ||||||
|         self.assertEqual(conv('0'), 0) |         self.assertEqual(conv('0'), 0) | ||||||
|         self.assertEqual(conv('42'), 42) |         self.assertEqual(conv('42'), 42) | ||||||
|         self.assertEqual(conv('3.14'), 3.14) |         self.assertEqual(conv('3.14'), 3.14) | ||||||
| @@ -107,6 +109,8 @@ class Ec2utilsTestCase(test.TestCase): | |||||||
|     def test_ec2_id_to_id(self): |     def test_ec2_id_to_id(self): | ||||||
|         self.assertEqual(ec2utils.ec2_id_to_id('i-0000001e'), 30) |         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('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): |     def test_bad_ec2_id(self): | ||||||
|         self.assertRaises(exception.InvalidEc2Id, |         self.assertRaises(exception.InvalidEc2Id, | ||||||
| @@ -116,6 +120,72 @@ class Ec2utilsTestCase(test.TestCase): | |||||||
|     def test_id_to_ec2_id(self): |     def test_id_to_ec2_id(self): | ||||||
|         self.assertEqual(ec2utils.id_to_ec2_id(30), 'i-0000001e') |         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_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): | class ApiEc2TestCase(test.TestCase): | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ | |||||||
| #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||||
| #    License for the specific language governing permissions and limitations | #    License for the specific language governing permissions and limitations | ||||||
| #    under the License. | #    under the License. | ||||||
|  | import mox | ||||||
|  |  | ||||||
| from base64 import b64decode | from base64 import b64decode | ||||||
| from M2Crypto import BIO | from M2Crypto import BIO | ||||||
| @@ -29,6 +30,7 @@ from nova import db | |||||||
| from nova import exception | from nova import exception | ||||||
| from nova import flags | from nova import flags | ||||||
| from nova import log as logging | from nova import log as logging | ||||||
|  | from nova import network | ||||||
| from nova import rpc | from nova import rpc | ||||||
| from nova import test | from nova import test | ||||||
| from nova import utils | from nova import utils | ||||||
| @@ -45,7 +47,8 @@ LOG = logging.getLogger('nova.tests.cloud') | |||||||
| class CloudTestCase(test.TestCase): | class CloudTestCase(test.TestCase): | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         super(CloudTestCase, self).setUp() |         super(CloudTestCase, self).setUp() | ||||||
|         self.flags(connection_type='fake') |         self.flags(connection_type='fake', | ||||||
|  |                    stub_network=True) | ||||||
|  |  | ||||||
|         self.conn = rpc.Connection.instance() |         self.conn = rpc.Connection.instance() | ||||||
|  |  | ||||||
| @@ -131,6 +134,33 @@ class CloudTestCase(test.TestCase): | |||||||
|                           allocate, |                           allocate, | ||||||
|                           self.context) |                           self.context) | ||||||
|  |  | ||||||
|  |     def test_release_address(self): | ||||||
|  |         address = "10.10.10.10" | ||||||
|  |         allocate = self.cloud.allocate_address | ||||||
|  |         db.floating_ip_create(self.context, | ||||||
|  |                               {'address': address, | ||||||
|  |                                'host': self.network.host}) | ||||||
|  |         result = self.cloud.release_address(self.context, address) | ||||||
|  |         self.assertEqual(result['releaseResponse'], ['Address released.']) | ||||||
|  |  | ||||||
|  |     def test_release_address_still_associated(self): | ||||||
|  |         address = "10.10.10.10" | ||||||
|  |         fixed_ip = {'instance': {'id': 1}} | ||||||
|  |         floating_ip = {'id': 0, | ||||||
|  |                        'address': address, | ||||||
|  |                        'fixed_ip_id': 0, | ||||||
|  |                        'fixed_ip': fixed_ip, | ||||||
|  |                        'project_id': None, | ||||||
|  |                        'auto_assigned': False} | ||||||
|  |         network_api = network.api.API() | ||||||
|  |         self.mox.StubOutWithMock(network_api.db, 'floating_ip_get_by_address') | ||||||
|  |         network_api.db.floating_ip_get_by_address(mox.IgnoreArg(), | ||||||
|  |                                 mox.IgnoreArg()).AndReturn(floating_ip) | ||||||
|  |         self.mox.ReplayAll() | ||||||
|  |         release = self.cloud.release_address | ||||||
|  |         # ApiError: Floating ip is in use.  Disassociate it before releasing. | ||||||
|  |         self.assertRaises(exception.ApiError, release, self.context, address) | ||||||
|  |  | ||||||
|     @test.skip_test("Skipping this pending future merge") |     @test.skip_test("Skipping this pending future merge") | ||||||
|     def test_associate_disassociate_address(self): |     def test_associate_disassociate_address(self): | ||||||
|         """Verifies associate runs cleanly without raising an exception""" |         """Verifies associate runs cleanly without raising an exception""" | ||||||
| @@ -290,7 +320,7 @@ class CloudTestCase(test.TestCase): | |||||||
|         vol2 = db.volume_create(self.context, {}) |         vol2 = db.volume_create(self.context, {}) | ||||||
|         result = self.cloud.describe_volumes(self.context) |         result = self.cloud.describe_volumes(self.context) | ||||||
|         self.assertEqual(len(result['volumeSet']), 2) |         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, |         result = self.cloud.describe_volumes(self.context, | ||||||
|                                              volume_id=[volume_id]) |                                              volume_id=[volume_id]) | ||||||
|         self.assertEqual(len(result['volumeSet']), 1) |         self.assertEqual(len(result['volumeSet']), 1) | ||||||
| @@ -306,7 +336,7 @@ class CloudTestCase(test.TestCase): | |||||||
|         snap = db.snapshot_create(self.context, {'volume_id': vol['id'], |         snap = db.snapshot_create(self.context, {'volume_id': vol['id'], | ||||||
|                                                  'volume_size': vol['size'], |                                                  'volume_size': vol['size'], | ||||||
|                                                  'status': "available"}) |                                                  '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, |         result = self.cloud.create_volume(self.context, | ||||||
|                                           snapshot_id=snapshot_id) |                                           snapshot_id=snapshot_id) | ||||||
| @@ -345,7 +375,7 @@ class CloudTestCase(test.TestCase): | |||||||
|         snap2 = db.snapshot_create(self.context, {'volume_id': vol['id']}) |         snap2 = db.snapshot_create(self.context, {'volume_id': vol['id']}) | ||||||
|         result = self.cloud.describe_snapshots(self.context) |         result = self.cloud.describe_snapshots(self.context) | ||||||
|         self.assertEqual(len(result['snapshotSet']), 2) |         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, |         result = self.cloud.describe_snapshots(self.context, | ||||||
|                                                snapshot_id=[snapshot_id]) |                                                snapshot_id=[snapshot_id]) | ||||||
|         self.assertEqual(len(result['snapshotSet']), 1) |         self.assertEqual(len(result['snapshotSet']), 1) | ||||||
| @@ -359,7 +389,7 @@ class CloudTestCase(test.TestCase): | |||||||
|     def test_create_snapshot(self): |     def test_create_snapshot(self): | ||||||
|         """Makes sure create_snapshot works.""" |         """Makes sure create_snapshot works.""" | ||||||
|         vol = db.volume_create(self.context, {'status': "available"}) |         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, |         result = self.cloud.create_snapshot(self.context, | ||||||
|                                             volume_id=volume_id) |                                             volume_id=volume_id) | ||||||
| @@ -376,7 +406,7 @@ class CloudTestCase(test.TestCase): | |||||||
|         vol = db.volume_create(self.context, {'status': "available"}) |         vol = db.volume_create(self.context, {'status': "available"}) | ||||||
|         snap = db.snapshot_create(self.context, {'volume_id': vol['id'], |         snap = db.snapshot_create(self.context, {'volume_id': vol['id'], | ||||||
|                                                   'status': "available"}) |                                                   '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, |         result = self.cloud.delete_snapshot(self.context, | ||||||
|                                             snapshot_id=snapshot_id) |                                             snapshot_id=snapshot_id) | ||||||
| @@ -415,6 +445,185 @@ class CloudTestCase(test.TestCase): | |||||||
|         db.service_destroy(self.context, comp1['id']) |         db.service_destroy(self.context, comp1['id']) | ||||||
|         db.service_destroy(self.context, comp2['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): |     def test_describe_images(self): | ||||||
|         describe_images = self.cloud.describe_images |         describe_images = self.cloud.describe_images | ||||||
|  |  | ||||||
| @@ -445,6 +654,161 @@ class CloudTestCase(test.TestCase): | |||||||
|         self.assertRaises(exception.ImageNotFound, describe_images, |         self.assertRaises(exception.ImageNotFound, describe_images, | ||||||
|                           self.context, ['ami-fake']) |                           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): |     def test_describe_image_attribute(self): | ||||||
|         describe_image_attribute = self.cloud.describe_image_attribute |         describe_image_attribute = self.cloud.describe_image_attribute | ||||||
|  |  | ||||||
| @@ -459,6 +823,32 @@ class CloudTestCase(test.TestCase): | |||||||
|                                           'launchPermission') |                                           'launchPermission') | ||||||
|         self.assertEqual([{'group': 'all'}], result['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): |     def test_modify_image_attribute(self): | ||||||
|         modify_image_attribute = self.cloud.modify_image_attribute |         modify_image_attribute = self.cloud.modify_image_attribute | ||||||
|  |  | ||||||
| @@ -699,7 +1089,7 @@ class CloudTestCase(test.TestCase): | |||||||
|     def test_update_of_volume_display_fields(self): |     def test_update_of_volume_display_fields(self): | ||||||
|         vol = db.volume_create(self.context, {}) |         vol = db.volume_create(self.context, {}) | ||||||
|         self.cloud.update_volume(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') |                                  display_name='c00l v0lum3') | ||||||
|         vol = db.volume_get(self.context, vol['id']) |         vol = db.volume_get(self.context, vol['id']) | ||||||
|         self.assertEqual('c00l v0lum3', vol['display_name']) |         self.assertEqual('c00l v0lum3', vol['display_name']) | ||||||
| @@ -708,7 +1098,7 @@ class CloudTestCase(test.TestCase): | |||||||
|     def test_update_of_volume_wont_update_private_fields(self): |     def test_update_of_volume_wont_update_private_fields(self): | ||||||
|         vol = db.volume_create(self.context, {}) |         vol = db.volume_create(self.context, {}) | ||||||
|         self.cloud.update_volume(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') |                                  mountpoint='/not/here') | ||||||
|         vol = db.volume_get(self.context, vol['id']) |         vol = db.volume_get(self.context, vol['id']) | ||||||
|         self.assertEqual(None, vol['mountpoint']) |         self.assertEqual(None, vol['mountpoint']) | ||||||
| @@ -786,11 +1176,13 @@ class CloudTestCase(test.TestCase): | |||||||
|  |  | ||||||
|         self._restart_compute_service() |         self._restart_compute_service() | ||||||
|  |  | ||||||
|     def _volume_create(self): |     def _volume_create(self, volume_id=None): | ||||||
|         kwargs = {'status': 'available', |         kwargs = {'status': 'available', | ||||||
|                   'host': self.volume.host, |                   'host': self.volume.host, | ||||||
|                   'size': 1, |                   'size': 1, | ||||||
|                   'attach_status': 'detached', } |                   'attach_status': 'detached', } | ||||||
|  |         if volume_id: | ||||||
|  |             kwargs['id'] = volume_id | ||||||
|         return db.volume_create(self.context, kwargs) |         return db.volume_create(self.context, kwargs) | ||||||
|  |  | ||||||
|     def _assert_volume_attached(self, vol, instance_id, mountpoint): |     def _assert_volume_attached(self, vol, instance_id, mountpoint): | ||||||
| @@ -819,10 +1211,10 @@ class CloudTestCase(test.TestCase): | |||||||
|                   'max_count': 1, |                   'max_count': 1, | ||||||
|                   'block_device_mapping': [{'device_name': '/dev/vdb', |                   'block_device_mapping': [{'device_name': '/dev/vdb', | ||||||
|                                             'volume_id': vol1['id'], |                                             'volume_id': vol1['id'], | ||||||
|                                             'delete_on_termination': False, }, |                                             'delete_on_termination': False}, | ||||||
|                                            {'device_name': '/dev/vdc', |                                            {'device_name': '/dev/vdc', | ||||||
|                                             'volume_id': vol2['id'], |                                             'volume_id': vol2['id'], | ||||||
|                                             'delete_on_termination': True, }, |                                             'delete_on_termination': True}, | ||||||
|                                            ]} |                                            ]} | ||||||
|         ec2_instance_id = self._run_instance_wait(**kwargs) |         ec2_instance_id = self._run_instance_wait(**kwargs) | ||||||
|         instance_id = ec2utils.ec2_id_to_id(ec2_instance_id) |         instance_id = ec2utils.ec2_id_to_id(ec2_instance_id) | ||||||
| @@ -954,7 +1346,7 @@ class CloudTestCase(test.TestCase): | |||||||
|     def test_run_with_snapshot(self): |     def test_run_with_snapshot(self): | ||||||
|         """Makes sure run/stop/start instance with snapshot works.""" |         """Makes sure run/stop/start instance with snapshot works.""" | ||||||
|         vol = self._volume_create() |         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) |         ec2_snapshot1_id = self._create_snapshot(ec2_volume_id) | ||||||
|         snapshot1_id = ec2utils.ec2_id_to_id(ec2_snapshot1_id) |         snapshot1_id = ec2utils.ec2_id_to_id(ec2_snapshot1_id) | ||||||
| @@ -1013,3 +1405,33 @@ class CloudTestCase(test.TestCase): | |||||||
|             self.cloud.delete_snapshot(self.context, snapshot_id) |             self.cloud.delete_snapshot(self.context, snapshot_id) | ||||||
|             greenthread.sleep(0.3) |             greenthread.sleep(0.3) | ||||||
|         db.volume_destroy(self.context, vol['id']) |         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() | ||||||
|   | |||||||
| @@ -424,11 +424,12 @@ class ComputeTestCase(test.TestCase): | |||||||
|         self.stubs.Set(self.compute.network_api, 'get_instance_nw_info', fake) |         self.stubs.Set(self.compute.network_api, 'get_instance_nw_info', fake) | ||||||
|         context = self.context.elevated() |         context = self.context.elevated() | ||||||
|         instance_id = self._create_instance() |         instance_id = self._create_instance() | ||||||
|         self.compute.prep_resize(context, instance_id, 1) |         instance_ref = db.instance_get(context, instance_id) | ||||||
|  |         self.compute.prep_resize(context, instance_ref['uuid'], 1) | ||||||
|         migration_ref = db.migration_get_by_instance_and_status(context, |         migration_ref = db.migration_get_by_instance_and_status(context, | ||||||
|                 instance_id, 'pre-migrating') |                 instance_ref['uuid'], 'pre-migrating') | ||||||
|         try: |         try: | ||||||
|             self.compute.finish_resize(context, instance_id, |             self.compute.finish_resize(context, instance_ref['uuid'], | ||||||
|                     int(migration_ref['id']), {}) |                     int(migration_ref['id']), {}) | ||||||
|         except KeyError, e: |         except KeyError, e: | ||||||
|             # Only catch key errors. We want other reasons for the test to |             # Only catch key errors. We want other reasons for the test to | ||||||
| @@ -441,14 +442,15 @@ class ComputeTestCase(test.TestCase): | |||||||
|         """Ensure notifications on instance migrate/resize""" |         """Ensure notifications on instance migrate/resize""" | ||||||
|         instance_id = self._create_instance() |         instance_id = self._create_instance() | ||||||
|         context = self.context.elevated() |         context = self.context.elevated() | ||||||
|  |         inst_ref = db.instance_get(context, instance_id) | ||||||
|  |  | ||||||
|         self.compute.run_instance(self.context, instance_id) |         self.compute.run_instance(self.context, instance_id) | ||||||
|         test_notifier.NOTIFICATIONS = [] |         test_notifier.NOTIFICATIONS = [] | ||||||
|  |  | ||||||
|         db.instance_update(self.context, instance_id, {'host': 'foo'}) |         db.instance_update(self.context, instance_id, {'host': 'foo'}) | ||||||
|         self.compute.prep_resize(context, instance_id, 1) |         self.compute.prep_resize(context, inst_ref['uuid'], 1) | ||||||
|         migration_ref = db.migration_get_by_instance_and_status(context, |         migration_ref = db.migration_get_by_instance_and_status(context, | ||||||
|                 instance_id, 'pre-migrating') |                 inst_ref['uuid'], 'pre-migrating') | ||||||
|  |  | ||||||
|         self.assertEquals(len(test_notifier.NOTIFICATIONS), 1) |         self.assertEquals(len(test_notifier.NOTIFICATIONS), 1) | ||||||
|         msg = test_notifier.NOTIFICATIONS[0] |         msg = test_notifier.NOTIFICATIONS[0] | ||||||
| @@ -471,13 +473,15 @@ class ComputeTestCase(test.TestCase): | |||||||
|         """Ensure instance can be migrated/resized""" |         """Ensure instance can be migrated/resized""" | ||||||
|         instance_id = self._create_instance() |         instance_id = self._create_instance() | ||||||
|         context = self.context.elevated() |         context = self.context.elevated() | ||||||
|  |         inst_ref = db.instance_get(context, instance_id) | ||||||
|  |  | ||||||
|         self.compute.run_instance(self.context, instance_id) |         self.compute.run_instance(self.context, instance_id) | ||||||
|         db.instance_update(self.context, instance_id, {'host': 'foo'}) |         db.instance_update(self.context, inst_ref['uuid'], | ||||||
|         self.compute.prep_resize(context, instance_id, 1) |                            {'host': 'foo'}) | ||||||
|  |         self.compute.prep_resize(context, inst_ref['uuid'], 1) | ||||||
|         migration_ref = db.migration_get_by_instance_and_status(context, |         migration_ref = db.migration_get_by_instance_and_status(context, | ||||||
|                 instance_id, 'pre-migrating') |                 inst_ref['uuid'], 'pre-migrating') | ||||||
|         self.compute.resize_instance(context, instance_id, |         self.compute.resize_instance(context, inst_ref['uuid'], | ||||||
|                 migration_ref['id']) |                 migration_ref['id']) | ||||||
|         self.compute.terminate_instance(context, instance_id) |         self.compute.terminate_instance(context, instance_id) | ||||||
|  |  | ||||||
| @@ -519,6 +523,57 @@ class ComputeTestCase(test.TestCase): | |||||||
|  |  | ||||||
|         self.compute.terminate_instance(context, instance_id) |         self.compute.terminate_instance(context, instance_id) | ||||||
|  |  | ||||||
|  |     def test_finish_revert_resize(self): | ||||||
|  |         """Ensure that the flavor is reverted to the original on revert""" | ||||||
|  |         context = self.context.elevated() | ||||||
|  |         instance_id = self._create_instance() | ||||||
|  |  | ||||||
|  |         def fake(*args, **kwargs): | ||||||
|  |             pass | ||||||
|  |  | ||||||
|  |         self.stubs.Set(self.compute.driver, 'finish_resize', fake) | ||||||
|  |         self.stubs.Set(self.compute.driver, 'revert_resize', fake) | ||||||
|  |         self.stubs.Set(self.compute.network_api, 'get_instance_nw_info', fake) | ||||||
|  |  | ||||||
|  |         self.compute.run_instance(self.context, instance_id) | ||||||
|  |  | ||||||
|  |         # Confirm the instance size before the resize starts | ||||||
|  |         inst_ref = db.instance_get(context, instance_id) | ||||||
|  |         instance_type_ref = db.instance_type_get(context, | ||||||
|  |                 inst_ref['instance_type_id']) | ||||||
|  |         self.assertEqual(instance_type_ref['flavorid'], 1) | ||||||
|  |  | ||||||
|  |         db.instance_update(self.context, instance_id, {'host': 'foo'}) | ||||||
|  |  | ||||||
|  |         self.compute.prep_resize(context, inst_ref['uuid'], 3) | ||||||
|  |  | ||||||
|  |         migration_ref = db.migration_get_by_instance_and_status(context, | ||||||
|  |                 inst_ref['uuid'], 'pre-migrating') | ||||||
|  |  | ||||||
|  |         self.compute.resize_instance(context, inst_ref['uuid'], | ||||||
|  |                 migration_ref['id']) | ||||||
|  |         self.compute.finish_resize(context, inst_ref['uuid'], | ||||||
|  |                     int(migration_ref['id']), {}) | ||||||
|  |  | ||||||
|  |         # Prove that the instance size is now the new size | ||||||
|  |         inst_ref = db.instance_get(context, instance_id) | ||||||
|  |         instance_type_ref = db.instance_type_get(context, | ||||||
|  |                 inst_ref['instance_type_id']) | ||||||
|  |         self.assertEqual(instance_type_ref['flavorid'], 3) | ||||||
|  |  | ||||||
|  |         # Finally, revert and confirm the old flavor has been applied | ||||||
|  |         self.compute.revert_resize(context, inst_ref['uuid'], | ||||||
|  |                 migration_ref['id']) | ||||||
|  |         self.compute.finish_revert_resize(context, inst_ref['uuid'], | ||||||
|  |                 migration_ref['id']) | ||||||
|  |  | ||||||
|  |         inst_ref = db.instance_get(context, instance_id) | ||||||
|  |         instance_type_ref = db.instance_type_get(context, | ||||||
|  |                 inst_ref['instance_type_id']) | ||||||
|  |         self.assertEqual(instance_type_ref['flavorid'], 1) | ||||||
|  |  | ||||||
|  |         self.compute.terminate_instance(context, instance_id) | ||||||
|  |  | ||||||
|     def test_get_by_flavor_id(self): |     def test_get_by_flavor_id(self): | ||||||
|         type = instance_types.get_instance_type_by_flavor_id(1) |         type = instance_types.get_instance_type_by_flavor_id(1) | ||||||
|         self.assertEqual(type['name'], 'm1.tiny') |         self.assertEqual(type['name'], 'm1.tiny') | ||||||
| @@ -818,3 +873,114 @@ class ComputeTestCase(test.TestCase): | |||||||
|         LOG.info(_("After force-killing instances: %s"), instances) |         LOG.info(_("After force-killing instances: %s"), instances) | ||||||
|         self.assertEqual(len(instances), 1) |         self.assertEqual(len(instances), 1) | ||||||
|         self.assertEqual(power_state.SHUTOFF, instances[0]['state']) |         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) | ||||||
|   | |||||||
| @@ -58,6 +58,7 @@ def _create_network_info(count=1, ipv6=None): | |||||||
|                'cidr': fake_ip, |                'cidr': fake_ip, | ||||||
|                'cidr_v6': fake_ip} |                'cidr_v6': fake_ip} | ||||||
|     mapping = {'mac': fake, |     mapping = {'mac': fake, | ||||||
|  |                'dhcp_server': fake, | ||||||
|                'gateway': fake, |                'gateway': fake, | ||||||
|                'gateway6': fake, |                'gateway6': fake, | ||||||
|                'ips': [{'ip': fake_ip}, {'ip': fake_ip}]} |                'ips': [{'ip': fake_ip}, {'ip': fake_ip}]} | ||||||
| @@ -242,7 +243,7 @@ class LibvirtConnTestCase(test.TestCase): | |||||||
|                 return """ |                 return """ | ||||||
|                     <domain type='kvm'> |                     <domain type='kvm'> | ||||||
|                         <devices> |                         <devices> | ||||||
|                             <drive type='file'> |                             <disk type='file'> | ||||||
|                                 <source file='filename'/> |                                 <source file='filename'/> | ||||||
|                             </disk> |                             </disk> | ||||||
|                         </devices> |                         </devices> | ||||||
|   | |||||||
| @@ -45,6 +45,7 @@ class FakeModel(dict): | |||||||
| networks = [{'id': 0, | networks = [{'id': 0, | ||||||
|              'label': 'test0', |              'label': 'test0', | ||||||
|              'injected': False, |              'injected': False, | ||||||
|  |              'multi_host': False, | ||||||
|              'cidr': '192.168.0.0/24', |              'cidr': '192.168.0.0/24', | ||||||
|              'cidr_v6': '2001:db8::/64', |              'cidr_v6': '2001:db8::/64', | ||||||
|              'gateway_v6': '2001:db8::1', |              'gateway_v6': '2001:db8::1', | ||||||
| @@ -62,6 +63,7 @@ networks = [{'id': 0, | |||||||
|             {'id': 1, |             {'id': 1, | ||||||
|              'label': 'test1', |              'label': 'test1', | ||||||
|              'injected': False, |              'injected': False, | ||||||
|  |              'multi_host': False, | ||||||
|              'cidr': '192.168.1.0/24', |              'cidr': '192.168.1.0/24', | ||||||
|              'cidr_v6': '2001:db9::/64', |              'cidr_v6': '2001:db9::/64', | ||||||
|              'gateway_v6': '2001:db9::1', |              'gateway_v6': '2001:db9::1', | ||||||
| @@ -122,34 +124,20 @@ class FlatNetworkTestCase(test.TestCase): | |||||||
|         self.network = network_manager.FlatManager(host=HOST) |         self.network = network_manager.FlatManager(host=HOST) | ||||||
|         self.network.db = db |         self.network.db = db | ||||||
|  |  | ||||||
|     def test_set_network_hosts(self): |  | ||||||
|         self.mox.StubOutWithMock(db, 'network_get_all') |  | ||||||
|         self.mox.StubOutWithMock(db, 'network_set_host') |  | ||||||
|         self.mox.StubOutWithMock(db, 'network_update') |  | ||||||
|  |  | ||||||
|         db.network_get_all(mox.IgnoreArg()).AndReturn([networks[0]]) |  | ||||||
|         db.network_set_host(mox.IgnoreArg(), |  | ||||||
|                             networks[0]['id'], |  | ||||||
|                             mox.IgnoreArg()).AndReturn(HOST) |  | ||||||
|         db.network_update(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) |  | ||||||
|         self.mox.ReplayAll() |  | ||||||
|  |  | ||||||
|         self.network.set_network_hosts(None) |  | ||||||
|  |  | ||||||
|     def test_get_instance_nw_info(self): |     def test_get_instance_nw_info(self): | ||||||
|         self.mox.StubOutWithMock(db, 'fixed_ip_get_by_instance') |         self.mox.StubOutWithMock(db, 'fixed_ip_get_by_instance') | ||||||
|         self.mox.StubOutWithMock(db, 'virtual_interface_get_by_instance') |         self.mox.StubOutWithMock(db, 'virtual_interface_get_by_instance') | ||||||
|         self.mox.StubOutWithMock(db, 'instance_type_get_by_id') |         self.mox.StubOutWithMock(db, 'instance_type_get') | ||||||
|  |  | ||||||
|         db.fixed_ip_get_by_instance(mox.IgnoreArg(), |         db.fixed_ip_get_by_instance(mox.IgnoreArg(), | ||||||
|                                     mox.IgnoreArg()).AndReturn(fixed_ips) |                                     mox.IgnoreArg()).AndReturn(fixed_ips) | ||||||
|         db.virtual_interface_get_by_instance(mox.IgnoreArg(), |         db.virtual_interface_get_by_instance(mox.IgnoreArg(), | ||||||
|                                              mox.IgnoreArg()).AndReturn(vifs) |                                              mox.IgnoreArg()).AndReturn(vifs) | ||||||
|         db.instance_type_get_by_id(mox.IgnoreArg(), |         db.instance_type_get(mox.IgnoreArg(), | ||||||
|                                    mox.IgnoreArg()).AndReturn(flavor) |                                    mox.IgnoreArg()).AndReturn(flavor) | ||||||
|         self.mox.ReplayAll() |         self.mox.ReplayAll() | ||||||
|  |  | ||||||
|         nw_info = self.network.get_instance_nw_info(None, 0, 0) |         nw_info = self.network.get_instance_nw_info(None, 0, 0, None) | ||||||
|  |  | ||||||
|         self.assertTrue(nw_info) |         self.assertTrue(nw_info) | ||||||
|  |  | ||||||
| @@ -164,6 +152,7 @@ class FlatNetworkTestCase(test.TestCase): | |||||||
|             self.assertDictMatch(nw[0], check) |             self.assertDictMatch(nw[0], check) | ||||||
|  |  | ||||||
|             check = {'broadcast': '192.168.%s.255' % i, |             check = {'broadcast': '192.168.%s.255' % i, | ||||||
|  |                      'dhcp_server': '192.168.%s.1' % i, | ||||||
|                      'dns': 'DONTCARE', |                      'dns': 'DONTCARE', | ||||||
|                      'gateway': '192.168.%s.1' % i, |                      'gateway': '192.168.%s.1' % i, | ||||||
|                      'gateway6': '2001:db%s::1' % i8, |                      'gateway6': '2001:db%s::1' % i8, | ||||||
|   | |||||||
| @@ -27,8 +27,10 @@ from nova import exception | |||||||
| from nova import db | from nova import db | ||||||
| from nova import flags | from nova import flags | ||||||
| from nova import log as logging | from nova import log as logging | ||||||
|  | from nova import rpc | ||||||
| from nova import test | from nova import test | ||||||
| from nova import utils | from nova import utils | ||||||
|  | from nova import volume | ||||||
|  |  | ||||||
| FLAGS = flags.FLAGS | FLAGS = flags.FLAGS | ||||||
| LOG = logging.getLogger('nova.tests.volume') | LOG = logging.getLogger('nova.tests.volume') | ||||||
| @@ -43,6 +45,11 @@ class VolumeTestCase(test.TestCase): | |||||||
|         self.flags(connection_type='fake') |         self.flags(connection_type='fake') | ||||||
|         self.volume = utils.import_object(FLAGS.volume_manager) |         self.volume = utils.import_object(FLAGS.volume_manager) | ||||||
|         self.context = context.get_admin_context() |         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 |     @staticmethod | ||||||
|     def _create_volume(size='0', snapshot_id=None): |     def _create_volume(size='0', snapshot_id=None): | ||||||
| @@ -223,6 +230,30 @@ class VolumeTestCase(test.TestCase): | |||||||
|                           snapshot_id) |                           snapshot_id) | ||||||
|         self.volume.delete_volume(self.context, volume_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): | class DriverTestCase(test.TestCase): | ||||||
|     """Base Test class for Drivers.""" |     """Base Test class for Drivers.""" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 vladimir.p
					vladimir.p