From 77dd6a0b37652bc163d4ad3083e29af55f2b9a5d Mon Sep 17 00:00:00 2001 From: Joe Gordon Date: Fri, 31 Aug 2012 00:04:33 +0000 Subject: Allow for deleting VMs from down compute nodes. Fix bug 872899 If compute node service_is_up returns false, just delete the VM from the database. If compute node recovers, setting running_deleted_instance_action=reap will clean up the node. Change-Id: Ibb5f1e22c2e482d304c59a485a04b882ead0c67d --- nova/compute/api.py | 17 +++++++++++++++-- nova/tests/compute/test_compute.py | 25 ++++++++++++++++--------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index dcc6a7f06..3292d9080 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -855,7 +855,7 @@ class API(base.Base): cores=-instance['vcpus'], ram=-instance['memory_mb']) - if not instance['host']: + if not host: # Just update database, nothing else we can do constraint = self.db.constraint(host=self.db.equal_any(host)) try: @@ -894,7 +894,20 @@ class API(base.Base): host=src_host, cast=False, reservations=downsize_reservations) - self.compute_rpcapi.terminate_instance(context, instance) + services = self.db.service_get_all_compute_by_host( + context.elevated(), instance['host']) + is_up = False + #Note(jogo): db allows for multiple compute services per host + for service in services: + if utils.service_is_up(service): + is_up = True + self.compute_rpcapi.terminate_instance(context, instance) + break + if is_up == False: + # If compute node isn't up, just delete from DB + LOG.warning(_('host for instance is down, deleting from ' + 'database'), instance=instance) + self.db.instance_destroy(context, instance['uuid']) if reservations: QUOTAS.commit(context, reservations) diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index 822c23e03..ffedff1b5 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -148,6 +148,8 @@ class BaseTestCase(test.TestCase): inst['architecture'] = 'x86_64' inst['os_type'] = 'Linux' inst.update(params) + _create_service_entries(self.context.elevated(), + {'fake_zone': [inst['host']]}) return db.instance_create(self.context, inst) def _create_instance(self, params=None, type_name='m1.tiny'): @@ -2403,8 +2405,8 @@ class ComputeAPITestCase(BaseTestCase): 'ramdisk_id': 'fake_ramdisk_id'}, } - def _run_instance(self): - instance = jsonutils.to_primitive(self._create_fake_instance()) + def _run_instance(self, params=None): + instance = jsonutils.to_primitive(self._create_fake_instance(params)) instance_uuid = instance['uuid'] self.compute.run_instance(self.context, instance=instance) @@ -2719,7 +2721,8 @@ class ComputeAPITestCase(BaseTestCase): db.instance_destroy(self.context, instance['uuid']) def test_delete(self): - instance, instance_uuid = self._run_instance() + instance, instance_uuid = self._run_instance(params={ + 'host': FLAGS.host}) self.compute_api.delete(self.context, instance) @@ -2742,7 +2745,8 @@ class ComputeAPITestCase(BaseTestCase): self.stubs.Set(QUOTAS, 'commit', fake_commit) - instance, instance_uuid = self._run_instance() + instance, instance_uuid = self._run_instance(params={ + 'host': FLAGS.host}) self.compute_api.delete(self.context, instance) self.compute_api.delete(self.context, instance) @@ -2761,7 +2765,8 @@ class ComputeAPITestCase(BaseTestCase): self.context, instance['uuid']) def test_delete_handles_host_setting_race_condition(self): - instance, instance_uuid = self._run_instance() + instance, instance_uuid = self._run_instance(params={ + 'host': FLAGS.host}) instance['host'] = None # make it think host was never set self.compute_api.delete(self.context, instance) @@ -2771,7 +2776,8 @@ class ComputeAPITestCase(BaseTestCase): db.instance_destroy(self.context, instance['uuid']) def test_delete_fail(self): - instance, instance_uuid = self._run_instance() + instance, instance_uuid = self._run_instance(params={ + 'host': FLAGS.host}) instance = db.instance_update(self.context, instance_uuid, {'disable_terminate': True}) @@ -2806,7 +2812,8 @@ class ComputeAPITestCase(BaseTestCase): def test_force_delete(self): """Ensure instance can be deleted after a soft delete""" - instance = jsonutils.to_primitive(self._create_fake_instance()) + instance = jsonutils.to_primitive(self._create_fake_instance(params={ + 'host': FLAGS.host})) instance_uuid = instance['uuid'] self.compute.run_instance(self.context, instance=instance) @@ -3999,7 +4006,7 @@ class ComputeAPITestCase(BaseTestCase): db.instance_destroy(self.context, i_ref['uuid']) def test_add_remove_fixed_ip(self): - instance = self._create_fake_instance() + instance = self._create_fake_instance(params={'host': FLAGS.host}) self.compute_api.add_fixed_ip(self.context, instance, '1') self.compute_api.remove_fixed_ip(self.context, instance, '192.168.1.1') self.compute_api.delete(self.context, instance) @@ -4097,7 +4104,7 @@ class ComputeAPITestCase(BaseTestCase): self.compute_api.attach_volume(self.context, instance, 1, '/dev/vdb') def test_inject_network_info(self): - instance = self._create_fake_instance() + instance = self._create_fake_instance(params={'host': FLAGS.host}) self.compute.run_instance(self.context, instance=jsonutils.to_primitive(instance)) instance = self.compute_api.get(self.context, instance['uuid']) -- cgit