]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Enforce credentials requirement on stack create/update.
authorSteve Baker <sbaker@redhat.com>
Wed, 3 Jul 2013 23:50:49 +0000 (11:50 +1200)
committerSteve Baker <sbaker@redhat.com>
Thu, 4 Jul 2013 22:03:07 +0000 (10:03 +1200)
Credentials need to be supplied whenever they are stored with the stack,
which is during stack create and update.

Some users have been relying on their auth token to perform all heat
operations (as all other openstack services support) however this has
led them to experience obscure errors when wait handles or alarms are
triggered.

Failing early with a clear error message will stop this class of errors.

Fixes bug: #1194303

Change-Id: I3edef3dee843bb06760be6294b798761eba30cb8

heat/api/openstack/v1/util.py
heat/engine/service.py
heat/tests/test_engine_service.py

index 76920868d5b470b0d5f1b6d4d4e1d81f76c76b32..b578e1cb6e99ab611fcd9a99b335f8b82eed3add 100644 (file)
@@ -85,6 +85,7 @@ def remote_error(ex):
         'StackValidationFailed': exc.HTTPBadRequest,
         'InvalidTemplateReference': exc.HTTPBadRequest,
         'UnknownUserParameter': exc.HTTPBadRequest,
+        'MissingCredentialError': exc.HTTPBadRequest,
     }
 
     Exc = error_map.get(ex.exc_type, exc.HTTPInternalServerError)
index 5abb939f13e2f94bfde3152d138397c12ce95a83..81d8e1a47eb86f580ce2e97598b36768d00c7892 100644 (file)
@@ -184,6 +184,12 @@ class EngineService(service.Service):
         stacks = db_api.stack_get_all_by_tenant(cnxt) or []
         return list(format_stack_details(stacks))
 
+    def _validate_mandatory_credentials(self, cnxt):
+        if cnxt.username is None:
+            raise exception.MissingCredentialError(required='X-Auth-User')
+        if cnxt.password is None:
+            raise exception.MissingCredentialError(required='X-Auth-Key')
+
     @request_context
     def create_stack(self, cnxt, stack_name, template, params, files, args):
         """
@@ -201,6 +207,8 @@ class EngineService(service.Service):
         """
         logger.info('template is %s' % template)
 
+        self._validate_mandatory_credentials(cnxt)
+
         def _stack_create(stack):
             # Create the stack, and create the periodic task if successful
             stack.create()
@@ -246,6 +254,8 @@ class EngineService(service.Service):
         """
         logger.info('template is %s' % template)
 
+        self._validate_mandatory_credentials(cnxt)
+
         # Get the database representation of the existing stack
         db_stack = self._get_stack(cnxt, stack_identity)
 
index b524aed25ae885a1c70b3dd6a5b11f0323d972c1..c696a46cf216b6087b007d1907027dd4f973dfc8 100644 (file)
@@ -67,12 +67,14 @@ wp_template = '''
 
 
 def create_context(mocks, user='stacks_test_user',
-                   tenant='test_admin', ctx=None):
-    ctx = ctx or context.get_admin_context()
+                   tenant='test_admin', password='stacks_test_password'):
+    ctx = context.get_admin_context()
     mocks.StubOutWithMock(ctx, 'username')
     mocks.StubOutWithMock(ctx, 'tenant_id')
+    mocks.StubOutWithMock(ctx, 'password')
     ctx.username = user
     ctx.tenant_id = tenant
+    ctx.password = password
     return ctx
 
 
@@ -318,6 +320,21 @@ class stackServiceCreateUpdateDeleteTest(HeatTestCase):
                           self.ctx, stack_name,
                           stack.t, {}, None, {})
 
+    def test_stack_create_no_credentials(self):
+        stack_name = 'service_create_test_stack'
+        params = {'foo': 'bar'}
+        template = '{ "Template": "data" }'
+
+        ctx = self.ctx = create_context(self.m, password=None)
+        self.assertRaises(exception.MissingCredentialError,
+                          self.man.create_stack, ctx, stack_name, template,
+                          params, None, {})
+
+        ctx = self.ctx = create_context(self.m, user=None)
+        self.assertRaises(exception.MissingCredentialError,
+                          self.man.create_stack, ctx, stack_name, template,
+                          params, None, {})
+
     def test_stack_validate(self):
         stack_name = 'service_create_test_validate'
         stack = get_wordpress_stack(stack_name, self.ctx)
@@ -464,6 +481,25 @@ class stackServiceCreateUpdateDeleteTest(HeatTestCase):
                           None, {})
         self.m.VerifyAll()
 
+    def test_stack_update_no_credentials(self):
+        stack_name = 'service_update_nonexist_test_stack'
+        params = {'foo': 'bar'}
+        template = '{ "Template": "data" }'
+
+        stack = get_wordpress_stack(stack_name, self.ctx)
+
+        ctx = self.ctx = create_context(self.m, password=None)
+        self.assertRaises(exception.MissingCredentialError,
+                          self.man.update_stack,
+                          ctx, stack.identifier(), template, params,
+                          None, {})
+
+        ctx = self.ctx = create_context(self.m, user=None)
+        self.assertRaises(exception.MissingCredentialError,
+                          self.man.update_stack,
+                          ctx, stack.identifier(), template, params,
+                          None, {})
+
 
 class stackServiceSuspendResumeTest(HeatTestCase):