Display stack owner when formatting stacks
Stacks are launched by users but scoped to tenants, so users in the same tenant currently have no way to know owns each stack. The same is especially true to unscoped stack lists. Since humans are much better with names than they are with numbers, this adds the stack owner username to the data returned with each stack. Co-Authored-By: Anderson Mesquita <andersonvom@gmail.com> Implements: blueprint stack-display-fields Change-Id: Ia1386531025096e0eeaf9e98b478c4453fc8cb01
This commit is contained in:
parent
227c659a50
commit
25788a13c2
|
@ -19,14 +19,17 @@ from heat.rpc import api as engine_api
|
|||
|
||||
_collection_name = 'stacks'
|
||||
|
||||
basic_keys = (engine_api.STACK_ID,
|
||||
engine_api.STACK_NAME,
|
||||
engine_api.STACK_DESCRIPTION,
|
||||
engine_api.STACK_STATUS,
|
||||
engine_api.STACK_STATUS_DATA,
|
||||
engine_api.STACK_CREATION_TIME,
|
||||
engine_api.STACK_DELETION_TIME,
|
||||
engine_api.STACK_UPDATED_TIME)
|
||||
basic_keys = (
|
||||
engine_api.STACK_ID,
|
||||
engine_api.STACK_NAME,
|
||||
engine_api.STACK_DESCRIPTION,
|
||||
engine_api.STACK_STATUS,
|
||||
engine_api.STACK_STATUS_DATA,
|
||||
engine_api.STACK_CREATION_TIME,
|
||||
engine_api.STACK_DELETION_TIME,
|
||||
engine_api.STACK_UPDATED_TIME,
|
||||
engine_api.STACK_OWNER,
|
||||
)
|
||||
|
||||
|
||||
def format_stack(req, stack, keys=None, tenant_safe=True):
|
||||
|
|
|
@ -102,6 +102,7 @@ def format_stack(stack):
|
|||
api.STACK_CAPABILITIES: [], # TODO Not implemented yet
|
||||
api.STACK_DISABLE_ROLLBACK: stack.disable_rollback,
|
||||
api.STACK_TIMEOUT: stack.timeout_mins,
|
||||
api.STACK_OWNER: stack.username,
|
||||
}
|
||||
|
||||
# allow users to view the outputs of stacks
|
||||
|
|
|
@ -64,7 +64,7 @@ class Stack(collections.Mapping):
|
|||
adopt_stack_data=None, stack_user_project_id=None,
|
||||
created_time=None, updated_time=None,
|
||||
user_creds_id=None, tenant_id=None,
|
||||
use_stored_context=False):
|
||||
use_stored_context=False, username=None):
|
||||
'''
|
||||
Initialise from a context, name, Template object and (optionally)
|
||||
Environment object. The database ID may also be initialised, if the
|
||||
|
@ -107,6 +107,7 @@ class Stack(collections.Mapping):
|
|||
# This will use the provided tenant ID when loading the stack
|
||||
# from the DB or get it from the context for new stacks.
|
||||
self.tenant_id = tenant_id or self.context.tenant_id
|
||||
self.username = username or self.context.username
|
||||
|
||||
resources.initialise()
|
||||
|
||||
|
@ -266,7 +267,8 @@ class Stack(collections.Mapping):
|
|||
created_time=stack.created_at,
|
||||
updated_time=stack.updated_at,
|
||||
user_creds_id=stack.user_creds_id, tenant_id=stack.tenant,
|
||||
use_stored_context=use_stored_context)
|
||||
use_stored_context=use_stored_context,
|
||||
username=stack.username)
|
||||
|
||||
def store(self, backup=False):
|
||||
'''
|
||||
|
@ -278,7 +280,7 @@ class Stack(collections.Mapping):
|
|||
'raw_template_id': self.t.store(self.context),
|
||||
'parameters': self.env.user_env_as_dict(),
|
||||
'owner_id': self.owner_id,
|
||||
'username': self.context.username,
|
||||
'username': self.username,
|
||||
'tenant': self.tenant_id,
|
||||
'action': self.action,
|
||||
'status': self.status,
|
||||
|
|
|
@ -28,7 +28,7 @@ STACK_KEYS = (
|
|||
STACK_DESCRIPTION, STACK_TMPL_DESCRIPTION,
|
||||
STACK_PARAMETERS, STACK_OUTPUTS, STACK_ACTION,
|
||||
STACK_STATUS, STACK_STATUS_DATA, STACK_CAPABILITIES,
|
||||
STACK_DISABLE_ROLLBACK, STACK_TIMEOUT,
|
||||
STACK_DISABLE_ROLLBACK, STACK_TIMEOUT, STACK_OWNER,
|
||||
) = (
|
||||
'stack_name', 'stack_identity',
|
||||
'creation_time', 'updated_time', 'deletion_time',
|
||||
|
@ -36,7 +36,7 @@ STACK_KEYS = (
|
|||
'description', 'template_description',
|
||||
'parameters', 'outputs', 'stack_action',
|
||||
'stack_status', 'stack_status_reason', 'capabilities',
|
||||
'disable_rollback', 'timeout_mins',
|
||||
'disable_rollback', 'timeout_mins', 'stack_owner',
|
||||
)
|
||||
|
||||
STACK_OUTPUT_KEYS = (
|
||||
|
|
|
@ -233,6 +233,7 @@ class FormatTest(HeatTestCase):
|
|||
'outputs': [],
|
||||
'stack_action': '',
|
||||
'stack_name': 'test_stack',
|
||||
'stack_owner': 'test_username',
|
||||
'stack_status': '',
|
||||
'stack_status_reason': '',
|
||||
'template_description': 'No description',
|
||||
|
|
|
@ -929,6 +929,17 @@ class StackTest(HeatTestCase):
|
|||
tenant_id=None)
|
||||
self.assertEqual('foo', stack.tenant_id)
|
||||
|
||||
def test_stack_reads_username(self):
|
||||
stack = parser.Stack(self.ctx, 'test_stack', self.tmpl,
|
||||
username='bar')
|
||||
self.assertEqual('bar', stack.username)
|
||||
|
||||
def test_stack_reads_username_from_context_if_empty(self):
|
||||
self.ctx.username = 'foo'
|
||||
stack = parser.Stack(self.ctx, 'test_stack', self.tmpl,
|
||||
username=None)
|
||||
self.assertEqual('foo', stack.username)
|
||||
|
||||
def test_stack_string_repr(self):
|
||||
stack = parser.Stack(self.ctx, 'test_stack', self.tmpl)
|
||||
expected = 'Stack "%s" [%s]' % (stack.name, stack.id)
|
||||
|
@ -1107,7 +1118,8 @@ class StackTest(HeatTestCase):
|
|||
updated_time=None,
|
||||
user_creds_id=stack.user_creds_id,
|
||||
tenant_id='test_tenant_id',
|
||||
use_stored_context=False)
|
||||
use_stored_context=False,
|
||||
username=IgnoreArg())
|
||||
|
||||
self.m.ReplayAll()
|
||||
parser.Stack.load(self.ctx, stack_id=self.stack.id,
|
||||
|
@ -1215,6 +1227,20 @@ class StackTest(HeatTestCase):
|
|||
stack = parser.Stack.load(self.ctx, stack_id=stack_id)
|
||||
self.assertEqual('foobar', stack.tenant_id)
|
||||
|
||||
def test_load_reads_username_from_db(self):
|
||||
self.ctx.username = 'foobar'
|
||||
self.stack = parser.Stack(self.ctx, 'stack_name', self.tmpl)
|
||||
self.stack.store()
|
||||
stack_id = self.stack.id
|
||||
|
||||
self.ctx.username = None
|
||||
stack = parser.Stack.load(self.ctx, stack_id=stack_id)
|
||||
self.assertEqual('foobar', stack.username)
|
||||
|
||||
self.ctx.username = 'not foobar'
|
||||
stack = parser.Stack.load(self.ctx, stack_id=stack_id)
|
||||
self.assertEqual('foobar', stack.username)
|
||||
|
||||
def test_created_time(self):
|
||||
self.stack = parser.Stack(self.ctx, 'creation_time_test',
|
||||
self.tmpl)
|
||||
|
@ -3272,6 +3298,14 @@ class StackTest(HeatTestCase):
|
|||
expected_err = 'Attempt to use stored_context with no user_creds'
|
||||
self.assertEqual(expected_err, six.text_type(ex))
|
||||
|
||||
def test_store_gets_username_from_stack(self):
|
||||
self.stack = parser.Stack(self.ctx, 'username_stack',
|
||||
self.tmpl, username='foobar')
|
||||
self.ctx.username = 'not foobar'
|
||||
self.stack.store()
|
||||
db_stack = db_api.stack_get(self.ctx, self.stack.id)
|
||||
self.assertEqual('foobar', db_stack.username)
|
||||
|
||||
def test_init_stored_context_false(self):
|
||||
ctx_init = utils.dummy_context(user='mystored_user',
|
||||
password='mystored_pass')
|
||||
|
|
Loading…
Reference in New Issue