summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Hardy <shardy@redhat.com>2013-11-27 19:08:27 +0000
committerSteven Hardy <shardy@redhat.com>2014-02-03 10:05:16 +0000
commitab5d961efd062662544218f36ae64277d39763fd (patch)
tree6e1dae7ccaa8ee26b750e4f9196c861d4d21f631
parent9279833b8d331392c13a45b563904e18d3a3461e (diff)
downloadheat-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.py12
-rw-r--r--heat/tests/test_parser.py30
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'}}}