diff options
author | matt.dietz@rackspace.com <> | 2011-07-29 17:59:23 +0000 |
---|---|---|
committer | Tarmac <> | 2011-07-29 17:59:23 +0000 |
commit | ab0c38efa5440347c3c75171e703e010023affe2 (patch) | |
tree | 7f042f9c391ed7033a91a39cdf2ee2a9dabec168 | |
parent | 8c099960a0938f168fe8ca85c63988d697228512 (diff) | |
parent | 396cf66676a64643645e25f81bd2422ac3ba5dbf (diff) | |
download | nova-ab0c38efa5440347c3c75171e703e010023affe2.tar.gz nova-ab0c38efa5440347c3c75171e703e010023affe2.tar.xz nova-ab0c38efa5440347c3c75171e703e010023affe2.zip |
--Stolen from https://code.launchpad.net/~cerberus/nova/lp809909/+merge/68602
Fixes lp809909
Migrate of instance with no local storage fails with exception
Simply checks to see if the instance has any local storage, and if not, skips over the resize VDI step.
-rw-r--r-- | nova/compute/manager.py | 24 | ||||
-rw-r--r-- | nova/tests/api/openstack/test_extensions.py | 38 | ||||
-rw-r--r-- | nova/tests/api/openstack/test_limits.py | 14 | ||||
-rw-r--r-- | nova/tests/test_compute.py | 6 | ||||
-rw-r--r-- | nova/tests/test_db_api.py | 4 | ||||
-rw-r--r-- | nova/tests/test_libvirt.py | 2 | ||||
-rw-r--r-- | nova/tests/test_xenapi.py | 75 | ||||
-rw-r--r-- | nova/virt/driver.py | 5 | ||||
-rw-r--r-- | nova/virt/xenapi/vmops.py | 30 | ||||
-rw-r--r-- | nova/virt/xenapi_conn.py | 8 |
10 files changed, 145 insertions, 61 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 173469bc3..a2d84cd76 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -747,7 +747,7 @@ class ComputeManager(manager.SchedulerDependentManager): local_gb=instance_type['local_gb'], instance_type_id=instance_type['id'])) - self.driver.revert_resize(instance_ref) + self.driver.revert_migration(instance_ref) self.db.migration_update(context, migration_id, {'status': 'reverted'}) usage_info = utils.usage_from_instance(instance_ref) @@ -845,20 +845,26 @@ class ComputeManager(manager.SchedulerDependentManager): """ migration_ref = self.db.migration_get(context, migration_id) + + resize_instance = False instance_ref = self.db.instance_get_by_uuid(context, migration_ref.instance_uuid) - instance_type = self.db.instance_type_get_by_flavor_id(context, - migration_ref['new_flavor_id']) - self.db.instance_update(context, instance_ref.uuid, - dict(instance_type_id=instance_type['id'], - memory_mb=instance_type['memory_mb'], - vcpus=instance_type['vcpus'], - local_gb=instance_type['local_gb'])) + if migration_ref['old_flavor_id'] != migration_ref['new_flavor_id']: + instance_type = self.db.instance_type_get_by_flavor_id(context, + migration_ref['new_flavor_id']) + self.db.instance_update(context, instance_ref.uuid, + dict(instance_type_id=instance_type['id'], + memory_mb=instance_type['memory_mb'], + vcpus=instance_type['vcpus'], + local_gb=instance_type['local_gb'])) + resize_instance = True instance_ref = self.db.instance_get_by_uuid(context, instance_ref.uuid) + network_info = self._get_instance_nw_info(context, instance_ref) - self.driver.finish_resize(instance_ref, disk_info, network_info) + self.driver.finish_migration(instance_ref, disk_info, network_info, + resize_instance) self.db.migration_update(context, migration_id, {'status': 'finished', }) diff --git a/nova/tests/api/openstack/test_extensions.py b/nova/tests/api/openstack/test_extensions.py index d459c694f..bf2d0368f 100644 --- a/nova/tests/api/openstack/test_extensions.py +++ b/nova/tests/api/openstack/test_extensions.py @@ -109,8 +109,8 @@ class ExtensionControllerTest(unittest.TestCase): 'updated': '2011-01-22T13:25:27-06:00', 'description': 'The Fox In Socks Extension', 'alias': 'FOXNSOX', - 'links': [] - } + 'links': [], + }, ) def test_get_extension_json(self): @@ -127,8 +127,8 @@ class ExtensionControllerTest(unittest.TestCase): "updated": "2011-01-22T13:25:27-06:00", "description": "The Fox In Socks Extension", "alias": "FOXNSOX", - "links": [] - } + "links": [], + }, ) def test_list_extensions_xml(self): @@ -342,15 +342,15 @@ class ExtensionsXMLSerializerTest(unittest.TestCase): { 'rel': 'describedby', 'type': 'application/pdf', - 'href': 'http://docs.rack.com/servers/api/ext/cs.pdf' + 'href': 'http://docs.rack.com/servers/api/ext/cs.pdf', }, { 'rel': 'describedby', 'type': 'application/vnd.sun.wadl+xml', - 'href': 'http://docs.rack.com/servers/api/ext/cs.wadl' - } - ] - } + 'href': 'http://docs.rack.com/servers/api/ext/cs.wadl', + }, + ], + }, } xml = serializer.serialize(data, 'show') @@ -382,14 +382,14 @@ class ExtensionsXMLSerializerTest(unittest.TestCase): { "rel": "describedby", "type": "application/pdf", - "href": "http://foo.com/api/ext/cs-pie.pdf" + "href": "http://foo.com/api/ext/cs-pie.pdf", }, { "rel": "describedby", "type": "application/vnd.sun.wadl+xml", - "href": "http://foo.com/api/ext/cs-pie.wadl" - } - ] + "href": "http://foo.com/api/ext/cs-pie.wadl", + }, + ], }, { "name": "Cloud Block Storage", @@ -401,16 +401,16 @@ class ExtensionsXMLSerializerTest(unittest.TestCase): { "rel": "describedby", "type": "application/pdf", - "href": "http://foo.com/api/ext/cs-cbs.pdf" + "href": "http://foo.com/api/ext/cs-cbs.pdf", }, { "rel": "describedby", "type": "application/vnd.sun.wadl+xml", - "href": "http://foo.com/api/ext/cs-cbs.wadl" - } - ] - } - ] + "href": "http://foo.com/api/ext/cs-cbs.wadl", + }, + ], + }, + ], } xml = serializer.serialize(data, 'index') diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py index 8a3fe681a..6c3d531e3 100644 --- a/nova/tests/api/openstack/test_limits.py +++ b/nova/tests/api/openstack/test_limits.py @@ -920,7 +920,7 @@ class LimitsViewBuilderV11Test(test.TestCase): "verb": "POST", "remaining": 2, "unit": "MINUTE", - "resetTime": 1311272226 + "resetTime": 1311272226, }, { "URI": "*/servers", @@ -929,7 +929,7 @@ class LimitsViewBuilderV11Test(test.TestCase): "verb": "POST", "remaining": 10, "unit": "DAY", - "resetTime": 1311272226 + "resetTime": 1311272226, }, ] self.absolute_limits = { @@ -954,7 +954,7 @@ class LimitsViewBuilderV11Test(test.TestCase): "verb": "POST", "remaining": 2, "unit": "MINUTE", - "next-available": "2011-07-21T18:17:06Z" + "next-available": "2011-07-21T18:17:06Z", }, ] }, @@ -967,7 +967,7 @@ class LimitsViewBuilderV11Test(test.TestCase): "verb": "POST", "remaining": 10, "unit": "DAY", - "next-available": "2011-07-21T18:17:06Z" + "next-available": "2011-07-21T18:17:06Z", }, ] }, @@ -989,7 +989,7 @@ class LimitsViewBuilderV11Test(test.TestCase): expected_limits = { "limits": { "rate": [], - "absolute": {} + "absolute": {}, } } @@ -1022,7 +1022,7 @@ class LimitsXMLSerializationTest(test.TestCase): "verb": "POST", "remaining": 2, "unit": "MINUTE", - "next-available": "2011-12-15T22:42:45Z" + "next-available": "2011-12-15T22:42:45Z", }, ] }, @@ -1083,7 +1083,7 @@ class LimitsXMLSerializationTest(test.TestCase): fixture = { "limits": { "rate": [], - "absolute": {} + "absolute": {}, } } diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 0ede4f469..d82666689 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -420,7 +420,7 @@ class ComputeTestCase(test.TestCase): def fake(*args, **kwargs): pass - self.stubs.Set(self.compute.driver, 'finish_resize', fake) + self.stubs.Set(self.compute.driver, 'finish_migration', fake) self.stubs.Set(self.compute.network_api, 'get_instance_nw_info', fake) context = self.context.elevated() instance_id = self._create_instance() @@ -531,8 +531,8 @@ class ComputeTestCase(test.TestCase): 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.driver, 'finish_migration', fake) + self.stubs.Set(self.compute.driver, 'revert_migration', fake) self.stubs.Set(self.compute.network_api, 'get_instance_nw_info', fake) self.compute.run_instance(self.context, instance_id) diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py index 107fd03e3..5560b489b 100644 --- a/nova/tests/test_db_api.py +++ b/nova/tests/test_db_api.py @@ -66,7 +66,7 @@ class DbApiTestCase(test.TestCase): result = db.fixed_ip_get_all(self.context) values = {'instance_type_id': FLAGS.default_instance_type, 'image_ref': FLAGS.vpn_image_id, - 'project_id': self.project.id + 'project_id': self.project.id, } instance = db.instance_create(self.context, values) result = db.instance_get_project_vpn(self.context, self.project.id) @@ -76,7 +76,7 @@ class DbApiTestCase(test.TestCase): result = db.fixed_ip_get_all(self.context) values = {'instance_type_id': FLAGS.default_instance_type, 'image_ref': FLAGS.vpn_image_id, - 'project_id': self.project.id + 'project_id': self.project.id, } instance = db.instance_create(self.context, values) _setup_networking(instance.id) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index bab4d200b..f367688cc 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -239,7 +239,7 @@ class LibvirtConnTestCase(test.TestCase): 'mac_address': 'fake', 'ip_address': 'fake', 'dhcp_server': 'fake', - 'extra_params': 'fake' + 'extra_params': 'fake', } # Creating mocks diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 8b3b5fa28..e8631b0fb 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -785,8 +785,47 @@ class XenAPIMigrateInstance(test.TestCase): conn = xenapi_conn.get_connection(False) conn.migrate_disk_and_power_off(instance, '127.0.0.1') - def test_finish_resize(self): + def test_finish_migrate(self): instance = db.instance_create(self.context, self.values) + self.called = False + + def fake_vdi_resize(*args, **kwargs): + self.called = True + + self.stubs.Set(stubs.FakeSessionForMigrationTests, + "VDI_resize_online", fake_vdi_resize) + stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests) + stubs.stubout_loopingcall_start(self.stubs) + conn = xenapi_conn.get_connection(False) + network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False}, + {'broadcast': '192.168.0.255', + 'dns': ['192.168.0.1'], + 'gateway': '192.168.0.1', + 'gateway6': 'dead:beef::1', + 'ip6s': [{'enabled': '1', + 'ip': 'dead:beef::dcad:beff:feef:0', + 'netmask': '64'}], + 'ips': [{'enabled': '1', + 'ip': '192.168.0.100', + 'netmask': '255.255.255.0'}], + 'label': 'fake', + 'mac': 'DE:AD:BE:EF:00:00', + 'rxtx_cap': 3})] + conn.finish_migration(instance, dict(base_copy='hurr', cow='durr'), + network_info, resize_instance=True) + self.assertEqual(self.called, True) + + def test_finish_migrate_no_local_storage(self): + tiny_type_id = \ + instance_types.get_instance_type_by_name('m1.tiny')['id'] + self.values.update({'instance_type_id': tiny_type_id, 'local_gb': 0}) + instance = db.instance_create(self.context, self.values) + + def fake_vdi_resize(*args, **kwargs): + raise Exception("This shouldn't be called") + + self.stubs.Set(stubs.FakeSessionForMigrationTests, + "VDI_resize_online", fake_vdi_resize) stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests) stubs.stubout_loopingcall_start(self.stubs) conn = xenapi_conn.get_connection(False) @@ -804,8 +843,38 @@ class XenAPIMigrateInstance(test.TestCase): 'label': 'fake', 'mac': 'DE:AD:BE:EF:00:00', 'rxtx_cap': 3})] - conn.finish_resize(instance, dict(base_copy='hurr', cow='durr'), - network_info) + conn.finish_migration(instance, dict(base_copy='hurr', cow='durr'), + network_info, resize_instance=True) + + def test_finish_migrate_no_resize_vdi(self): + instance = db.instance_create(self.context, self.values) + + def fake_vdi_resize(*args, **kwargs): + raise Exception("This shouldn't be called") + + self.stubs.Set(stubs.FakeSessionForMigrationTests, + "VDI_resize_online", fake_vdi_resize) + stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests) + stubs.stubout_loopingcall_start(self.stubs) + conn = xenapi_conn.get_connection(False) + network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False}, + {'broadcast': '192.168.0.255', + 'dns': ['192.168.0.1'], + 'gateway': '192.168.0.1', + 'gateway6': 'dead:beef::1', + 'ip6s': [{'enabled': '1', + 'ip': 'dead:beef::dcad:beff:feef:0', + 'netmask': '64'}], + 'ips': [{'enabled': '1', + 'ip': '192.168.0.100', + 'netmask': '255.255.255.0'}], + 'label': 'fake', + 'mac': 'DE:AD:BE:EF:00:00', + 'rxtx_cap': 3})] + + # Resize instance would be determined by the compute call + conn.finish_migration(instance, dict(base_copy='hurr', cow='durr'), + network_info, resize_instance=False) class XenAPIDetermineDiskImageTestCase(test.TestCase): diff --git a/nova/virt/driver.py b/nova/virt/driver.py index 34dc5f544..b219fb2cb 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -122,11 +122,12 @@ class ComputeDriver(object): """Create snapshot from a running VM instance.""" raise NotImplementedError() - def finish_resize(self, instance, disk_info): + def finish_migration(self, instance, disk_info, network_info, + resize_instance): """Completes a resize, turning on the migrated instance""" raise NotImplementedError() - def revert_resize(self, instance): + def revert_migration(self, instance): """Reverts a resize, powering back on the instance""" raise NotImplementedError() diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 77efe1bf0..38ecc47c9 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -110,17 +110,19 @@ class VMOps(object): instance_infos.append(instance_info) return instance_infos - def revert_resize(self, instance): + def revert_migration(self, instance): vm_ref = VMHelper.lookup(self._session, instance.name) self._start(instance, vm_ref) - def finish_resize(self, instance, disk_info, network_info): + def finish_migration(self, instance, disk_info, network_info, + resize_instance): vdi_uuid = self.link_disks(instance, disk_info['base_copy'], disk_info['cow']) vm_ref = self._create_vm(instance, [dict(vdi_type='os', vdi_uuid=vdi_uuid)], network_info) - self.resize_instance(instance, vdi_uuid) + if resize_instance: + self.resize_instance(instance, vdi_uuid) self._spawn(instance, vm_ref) def _start(self, instance, vm_ref=None): @@ -568,18 +570,22 @@ class VMOps(object): return new_cow_uuid def resize_instance(self, instance, vdi_uuid): - """Resize a running instance by changing it's RAM and disk size.""" + """Resize a running instance by changing its RAM and disk size.""" #TODO(mdietz): this will need to be adjusted for swap later #The new disk size must be in bytes - new_disk_size = str(instance.local_gb * 1024 * 1024 * 1024) - instance_name = instance.name - instance_local_gb = instance.local_gb - LOG.debug(_("Resizing VDI %(vdi_uuid)s for instance %(instance_name)s." - " Expanding to %(instance_local_gb)d GB") % locals()) - vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid) - self._session.call_xenapi('VDI.resize_online', vdi_ref, new_disk_size) - LOG.debug(_("Resize instance %s complete") % (instance.name)) + new_disk_size = instance.local_gb * 1024 * 1024 * 1024 + if new_disk_size > 0: + instance_name = instance.name + instance_local_gb = instance.local_gb + LOG.debug(_("Resizing VDI %(vdi_uuid)s for instance" + "%(instance_name)s. Expanding to %(instance_local_gb)d" + " GB") % locals()) + vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid) + # for an instance with no local storage + self._session.call_xenapi('VDI.resize_online', vdi_ref, + str(new_disk_size)) + LOG.debug(_("Resize instance %s complete") % (instance.name)) def reboot(self, instance): """Reboot VM instance.""" diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index cddb8203b..cc18ed83c 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -191,13 +191,15 @@ class XenAPIConnection(driver.ComputeDriver): """Create VM instance""" self._vmops.spawn(instance, network_info) - def revert_resize(self, instance): + def revert_migration(self, instance): """Reverts a resize, powering back on the instance""" self._vmops.revert_resize(instance) - def finish_resize(self, instance, disk_info, network_info): + def finish_migration(self, instance, disk_info, network_info, + resize_instance=False): """Completes a resize, turning on the migrated instance""" - self._vmops.finish_resize(instance, disk_info, network_info) + self._vmops.finish_migration(instance, disk_info, network_info, + resize_instance) def snapshot(self, instance, image_id): """ Create snapshot from a running VM instance """ |