diff --git a/heat/engine/service_software_config.py b/heat/engine/service_software_config.py index 05e5a9d73..ce062adc9 100644 --- a/heat/engine/service_software_config.py +++ b/heat/engine/service_software_config.py @@ -88,7 +88,8 @@ class SoftwareConfigService(service.Service): return result @oslo_db_api.wrap_db_retry(max_retries=10, retry_on_request=True) - def _push_metadata_software_deployments(self, cnxt, server_id, sd): + def _push_metadata_software_deployments( + self, cnxt, server_id, stack_user_project_id): rs = db_api.resource_get_by_physical_resource_id(cnxt, server_id) if not rs: return @@ -112,7 +113,7 @@ class SoftwareConfigService(service.Service): json_md = jsonutils.dumps(md) requests.put(metadata_put_url, json_md) if metadata_queue_id: - project = sd.stack_user_project_id + project = stack_user_project_id token = self._get_user_token(cnxt, rs, project) zaqar_plugin = cnxt.clients.client_plugin('zaqar') zaqar = zaqar_plugin.create_for_tenant(project, token) @@ -224,7 +225,8 @@ class SoftwareConfigService(service.Service): 'action': action, 'status': status, 'status_reason': status_reason}) - self._push_metadata_software_deployments(cnxt, server_id, sd) + self._push_metadata_software_deployments( + cnxt, server_id, stack_user_project_id) return api.format_software_deployment(sd) def signal_software_deployment(self, cnxt, deployment_id, details, @@ -315,10 +317,15 @@ class SoftwareConfigService(service.Service): # only push metadata if this update resulted in the config_id # changing, since metadata is just a list of configs if config_id: - self._push_metadata_software_deployments(cnxt, sd.server_id, sd) + self._push_metadata_software_deployments( + cnxt, sd.server_id, sd.stack_user_project_id) return api.format_software_deployment(sd) def delete_software_deployment(self, cnxt, deployment_id): + sd = software_deployment_object.SoftwareDeployment.get_by_id( + cnxt, deployment_id) software_deployment_object.SoftwareDeployment.delete( cnxt, deployment_id) + self._push_metadata_software_deployments( + cnxt, sd.server_id, sd.stack_user_project_id) diff --git a/heat/objects/software_config.py b/heat/objects/software_config.py index f46030f2a..eab2da302 100644 --- a/heat/objects/software_config.py +++ b/heat/objects/software_config.py @@ -37,6 +37,11 @@ class SoftwareConfig(base.VersionedObject, @staticmethod def _from_db_object(context, config, db_config): + + # SoftwareDeployment._from_db_object may attempt to load a None config + if db_config is None: + return None + for field in config.fields: config[field] = db_config[field] config._context = context diff --git a/heat/tests/engine/service/test_software_config.py b/heat/tests/engine/service/test_software_config.py index 648dc22c6..6a201e39c 100644 --- a/heat/tests/engine/service/test_software_config.py +++ b/heat/tests/engine/service/test_software_config.py @@ -512,9 +512,7 @@ class SoftwareConfigServiceTest(common.HeatTestCase): self.assertEqual('DEPLOY', updated['action']) self.assertEqual('WAITING', updated['status']) - sd = software_deployment_object.SoftwareDeployment.get_by_id( - self.ctx, deployment_id) - mock_push.assert_called_once_with(self.ctx, server_id, sd) + mock_push.assert_called_once_with(self.ctx, server_id, None) def test_update_software_deployment_fields(self): @@ -544,7 +542,9 @@ class SoftwareConfigServiceTest(common.HeatTestCase): check_software_deployment_updated(status='COMPLETE') check_software_deployment_updated(status_reason='Done!') - def test_delete_software_deployment(self): + @mock.patch.object(service_software_config.SoftwareConfigService, + '_push_metadata_software_deployments') + def test_delete_software_deployment(self, pmsd): deployment_id = str(uuid.uuid4()) ex = self.assertRaises(dispatcher.ExpectedException, self.engine.delete_software_deployment, @@ -554,11 +554,19 @@ class SoftwareConfigServiceTest(common.HeatTestCase): deployment = self._create_software_deployment() self.assertIsNotNone(deployment) deployment_id = deployment['id'] + deployments = self.engine.list_software_deployments( self.ctx, server_id=None) deployment_ids = [x['id'] for x in deployments] self.assertIn(deployment_id, deployment_ids) self.engine.delete_software_deployment(self.ctx, deployment_id) + + # assert one call for the create, and one for the delete + pmsd.assert_has_calls([ + mock.call(self.ctx, deployment['server_id'], None), + mock.call(self.ctx, deployment['server_id'], None) + ]) + deployments = self.engine.list_software_deployments( self.ctx, server_id=None) deployment_ids = [x['id'] for x in deployments] @@ -673,8 +681,6 @@ class SoftwareConfigServiceTest(common.HeatTestCase): rs.data = [rd] res_get.return_value = rs res_upd.return_value = 1 - sd = mock.Mock() - sd.stack_user_project_id = 'project1' queue = mock.Mock() zaqar_client = mock.Mock() plugin.return_value = zaqar_client @@ -689,7 +695,7 @@ class SoftwareConfigServiceTest(common.HeatTestCase): } self.engine.software_config._push_metadata_software_deployments( - self.ctx, '1234', sd) + self.ctx, '1234', 'project1') res_upd.assert_called_once_with( self.ctx, '1234', {'rsrc_metadata': result_metadata}, 1)