diff options
author | Steven Hardy <shardy@redhat.com> | 2013-11-27 19:08:27 +0000 |
---|---|---|
committer | Steven Hardy <shardy@redhat.com> | 2014-02-03 10:05:16 +0000 |
commit | ab5d961efd062662544218f36ae64277d39763fd (patch) | |
tree | 6e1dae7ccaa8ee26b750e4f9196c861d4d21f631 | |
parent | 9279833b8d331392c13a45b563904e18d3a3461e (diff) | |
download | heat-ab5d961efd062662544218f36ae64277d39763fd.tar.gz |
Catch error deleting trust on stack delete2013.2.2
When deleting a stack, it's possible for deleting the trust to fail,
for example if the user deleting the stack is not the user who created
it, or an admin (which raises a Forbidden error), or due to some
other transient error e.g connection to keystone interrupted.
Currently in this case, we fail to mark the stack deleted in the DB
and leave the status "DELETE, COMPLETE", which is misleading.
Conflicts:
heat/tests/test_parser.py
Closes-Bug: #1247200
(cherry picked from commit 214ba503757e5bd9bf5a5fab6692c4e94d0536fa)
Change-Id: Ie8e9ea48bc4f44e56ff4764123fcca733f5bd458
-rw-r--r-- | heat/engine/parser.py | 12 | ||||
-rw-r--r-- | heat/tests/test_parser.py | 30 |
2 files changed, 40 insertions, 2 deletions
diff --git a/heat/engine/parser.py b/heat/engine/parser.py index 6943f352d..ba97e72c2 100644 --- a/heat/engine/parser.py +++ b/heat/engine/parser.py @@ -558,14 +558,22 @@ class Stack(object): stack_status = self.FAILED reason = '%s timed out' % action.title() - self.state_set(action, stack_status, reason) if stack_status != self.FAILED: # If we created a trust, delete it stack = db_api.stack_get(self.context, self.id) user_creds = db_api.user_creds_get(stack.user_creds_id) trust_id = user_creds.get('trust_id') if trust_id: - self.clients.keystone().delete_trust(trust_id) + try: + self.clients.keystone().delete_trust(trust_id) + except Exception as ex: + logger.exception(ex) + stack_status = self.FAILED + reason = "Error deleting trust: %s" % str(ex) + + self.state_set(action, stack_status, reason) + + if stack_status != self.FAILED: # delete the stack db_api.stack_delete(self.context, self.id) self.id = None diff --git a/heat/tests/test_parser.py b/heat/tests/test_parser.py index e7c2b79b2..8f15df975 100644 --- a/heat/tests/test_parser.py +++ b/heat/tests/test_parser.py @@ -15,6 +15,8 @@ import json import time +from keystoneclient import exceptions as kc_exceptions + from oslo.config import cfg from heat.engine import environment @@ -819,6 +821,34 @@ class StackTest(HeatTestCase): (parser.Stack.DELETE, parser.Stack.COMPLETE)) @utils.stack_delete_after + def test_delete_trust_fail(self): + cfg.CONF.set_override('deferred_auth_method', 'trusts') + + class FakeKeystoneClientFail(FakeKeystoneClient): + def delete_trust(self, trust_id): + raise kc_exceptions.Forbidden("Denied!") + + self.m.StubOutWithMock(clients.OpenStackClients, 'keystone') + clients.OpenStackClients.keystone().MultipleTimes().AndReturn( + FakeKeystoneClientFail()) + self.m.ReplayAll() + + self.stack = parser.Stack( + self.ctx, 'delete_trust', template.Template({})) + stack_id = self.stack.store() + + db_s = db_api.stack_get(self.ctx, stack_id) + self.assertIsNotNone(db_s) + + self.stack.delete() + + db_s = db_api.stack_get(self.ctx, stack_id) + self.assertIsNotNone(db_s) + self.assertEqual(self.stack.state, + (parser.Stack.DELETE, parser.Stack.FAILED)) + self.assertIn('Error deleting trust', self.stack.status_reason) + + @utils.stack_delete_after def test_suspend_resume(self): self.m.ReplayAll() tmpl = {'Resources': {'AResource': {'Type': 'GenericResourceType'}}} |