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> | ||||
| Alexander Sakhnov <asakhnov@mirantis.com> | ||||
| Andrey Brindeyev <abrindeyev@griddynamics.com> | ||||
|   | ||||
| @@ -91,7 +91,7 @@ def init_leases(interface): | ||||
|     """Get the list of hosts for an interface.""" | ||||
|     ctxt = context.get_admin_context() | ||||
|     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(): | ||||
|   | ||||
| @@ -484,7 +484,7 @@ class ProjectCommands(object): | ||||
|         except db.api.NoMoreNetworks: | ||||
|             print _('No more networks available. If this is a new ' | ||||
|                     '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: | ||||
|             print e | ||||
|             print _("The above error may show that the certificate db has not " | ||||
| @@ -505,7 +505,7 @@ class FixedIpCommands(object): | ||||
|             if host is None: | ||||
|                 fixed_ips = db.fixed_ip_get_all(ctxt) | ||||
|             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: | ||||
|             print "error: %s" % ex | ||||
|             sys.exit(2) | ||||
| @@ -523,7 +523,7 @@ class FixedIpCommands(object): | ||||
|                 instance = fixed_ip['instance'] | ||||
|                 hostname = instance['hostname'] | ||||
|                 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" % ( | ||||
|                     fixed_ip['network']['cidr'], | ||||
|                     fixed_ip['address'], | ||||
| @@ -569,17 +569,17 @@ class NetworkCommands(object): | ||||
|     """Class for managing networks.""" | ||||
|  | ||||
|     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, | ||||
|                flat_network_bridge=None, bridge_interface=None): | ||||
|         """Creates fixed ips for host by range | ||||
|         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], | ||||
|                    [flat_network_bridge=FLAG], [bridge_interface=FLAG] | ||||
|         If you wish to use a later argument fill in the gaps with 0s | ||||
|         Ex: network create private 10.0.0.0/8 1 15 0 0 0 0 xenbr1 eth1 | ||||
|             network create private 10.0.0.0/8 1 15 | ||||
|         If you wish to use a later argument fill in the gaps with ""s | ||||
|         Ex: network create private 10.0.0.0/8 1 16 T "" "" "" "" xenbr1 eth1 | ||||
|             network create private 10.0.0.0/8 1 16 | ||||
|         """ | ||||
|         if not label: | ||||
|             msg = _('a label (ex: public) is required to create networks.') | ||||
| @@ -594,6 +594,10 @@ class NetworkCommands(object): | ||||
|             num_networks = FLAGS.num_networks | ||||
|         if not 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: | ||||
|             vlan_start = FLAGS.vlan_start | ||||
|         if not vpn_start: | ||||
| @@ -612,6 +616,7 @@ class NetworkCommands(object): | ||||
|             net_manager.create_networks(context.get_admin_context(), | ||||
|                                         label=label, | ||||
|                                         cidr=fixed_range, | ||||
|                                         multi_host=multi_host, | ||||
|                                         num_networks=int(num_networks), | ||||
|                                         network_size=int(network_size), | ||||
|                                         vlan_start=int(vlan_start), | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
| #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| #    License for the specific language governing permissions and limitations | ||||
| #    under the License. | ||||
| import mox | ||||
|  | ||||
| from base64 import b64decode | ||||
| from M2Crypto import BIO | ||||
| @@ -29,6 +30,7 @@ from nova import db | ||||
| from nova import exception | ||||
| from nova import flags | ||||
| from nova import log as logging | ||||
| from nova import network | ||||
| from nova import rpc | ||||
| from nova import test | ||||
| from nova import utils | ||||
| @@ -45,7 +47,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() | ||||
|  | ||||
| @@ -131,6 +134,33 @@ class CloudTestCase(test.TestCase): | ||||
|                           allocate, | ||||
|                           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") | ||||
|     def test_associate_disassociate_address(self): | ||||
|         """Verifies associate runs cleanly without raising an exception""" | ||||
| @@ -290,7 +320,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 +336,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 +375,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 +389,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 +406,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 +445,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 +654,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 +823,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 +1089,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 +1098,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 +1176,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 +1211,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 +1346,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 +1405,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() | ||||
|   | ||||
| @@ -424,11 +424,12 @@ class ComputeTestCase(test.TestCase): | ||||
|         self.stubs.Set(self.compute.network_api, 'get_instance_nw_info', fake) | ||||
|         context = self.context.elevated() | ||||
|         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, | ||||
|                 instance_id, 'pre-migrating') | ||||
|                 instance_ref['uuid'], 'pre-migrating') | ||||
|         try: | ||||
|             self.compute.finish_resize(context, instance_id, | ||||
|             self.compute.finish_resize(context, instance_ref['uuid'], | ||||
|                     int(migration_ref['id']), {}) | ||||
|         except KeyError, e: | ||||
|             # 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""" | ||||
|         instance_id = self._create_instance() | ||||
|         context = self.context.elevated() | ||||
|         inst_ref = db.instance_get(context, instance_id) | ||||
|  | ||||
|         self.compute.run_instance(self.context, instance_id) | ||||
|         test_notifier.NOTIFICATIONS = [] | ||||
|  | ||||
|         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, | ||||
|                 instance_id, 'pre-migrating') | ||||
|                 inst_ref['uuid'], 'pre-migrating') | ||||
|  | ||||
|         self.assertEquals(len(test_notifier.NOTIFICATIONS), 1) | ||||
|         msg = test_notifier.NOTIFICATIONS[0] | ||||
| @@ -471,13 +473,15 @@ class ComputeTestCase(test.TestCase): | ||||
|         """Ensure instance can be migrated/resized""" | ||||
|         instance_id = self._create_instance() | ||||
|         context = self.context.elevated() | ||||
|         inst_ref = db.instance_get(context, instance_id) | ||||
|  | ||||
|         self.compute.run_instance(self.context, instance_id) | ||||
|         db.instance_update(self.context, instance_id, {'host': 'foo'}) | ||||
|         self.compute.prep_resize(context, instance_id, 1) | ||||
|         db.instance_update(self.context, inst_ref['uuid'], | ||||
|                            {'host': 'foo'}) | ||||
|         self.compute.prep_resize(context, inst_ref['uuid'], 1) | ||||
|         migration_ref = db.migration_get_by_instance_and_status(context, | ||||
|                 instance_id, 'pre-migrating') | ||||
|         self.compute.resize_instance(context, instance_id, | ||||
|                 inst_ref['uuid'], 'pre-migrating') | ||||
|         self.compute.resize_instance(context, inst_ref['uuid'], | ||||
|                 migration_ref['id']) | ||||
|         self.compute.terminate_instance(context, instance_id) | ||||
|  | ||||
| @@ -519,6 +523,57 @@ class ComputeTestCase(test.TestCase): | ||||
|  | ||||
|         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): | ||||
|         type = instance_types.get_instance_type_by_flavor_id(1) | ||||
|         self.assertEqual(type['name'], 'm1.tiny') | ||||
| @@ -818,3 +873,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) | ||||
|   | ||||
| @@ -58,6 +58,7 @@ def _create_network_info(count=1, ipv6=None): | ||||
|                'cidr': fake_ip, | ||||
|                'cidr_v6': fake_ip} | ||||
|     mapping = {'mac': fake, | ||||
|                'dhcp_server': fake, | ||||
|                'gateway': fake, | ||||
|                'gateway6': fake, | ||||
|                'ips': [{'ip': fake_ip}, {'ip': fake_ip}]} | ||||
| @@ -242,7 +243,7 @@ class LibvirtConnTestCase(test.TestCase): | ||||
|                 return """ | ||||
|                     <domain type='kvm'> | ||||
|                         <devices> | ||||
|                             <drive type='file'> | ||||
|                             <disk type='file'> | ||||
|                                 <source file='filename'/> | ||||
|                             </disk> | ||||
|                         </devices> | ||||
|   | ||||
| @@ -45,6 +45,7 @@ class FakeModel(dict): | ||||
| networks = [{'id': 0, | ||||
|              'label': 'test0', | ||||
|              'injected': False, | ||||
|              'multi_host': False, | ||||
|              'cidr': '192.168.0.0/24', | ||||
|              'cidr_v6': '2001:db8::/64', | ||||
|              'gateway_v6': '2001:db8::1', | ||||
| @@ -62,6 +63,7 @@ networks = [{'id': 0, | ||||
|             {'id': 1, | ||||
|              'label': 'test1', | ||||
|              'injected': False, | ||||
|              'multi_host': False, | ||||
|              'cidr': '192.168.1.0/24', | ||||
|              'cidr_v6': '2001:db9::/64', | ||||
|              'gateway_v6': '2001:db9::1', | ||||
| @@ -122,34 +124,20 @@ class FlatNetworkTestCase(test.TestCase): | ||||
|         self.network = network_manager.FlatManager(host=HOST) | ||||
|         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): | ||||
|         self.mox.StubOutWithMock(db, 'fixed_ip_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(), | ||||
|                                     mox.IgnoreArg()).AndReturn(fixed_ips) | ||||
|         db.virtual_interface_get_by_instance(mox.IgnoreArg(), | ||||
|                                              mox.IgnoreArg()).AndReturn(vifs) | ||||
|         db.instance_type_get_by_id(mox.IgnoreArg(), | ||||
|         db.instance_type_get(mox.IgnoreArg(), | ||||
|                                    mox.IgnoreArg()).AndReturn(flavor) | ||||
|         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) | ||||
|  | ||||
| @@ -164,6 +152,7 @@ class FlatNetworkTestCase(test.TestCase): | ||||
|             self.assertDictMatch(nw[0], check) | ||||
|  | ||||
|             check = {'broadcast': '192.168.%s.255' % i, | ||||
|                      'dhcp_server': '192.168.%s.1' % i, | ||||
|                      'dns': 'DONTCARE', | ||||
|                      'gateway': '192.168.%s.1' % i, | ||||
|                      'gateway6': '2001:db%s::1' % i8, | ||||
|   | ||||
| @@ -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
	 vladimir.p
					vladimir.p