Keep encrypted_param_names environment internal to heat
Currently this is reflected in the user_env_as_dict output, which means not only is it stored in the DB (which we want), but also passed around to nested stack (which we don't want because it's derived from the parent stack hidden parameters), and also to the user via stack environment show (the API returns it but heatclient currently hides it), which we also don't want because it's not a valid key in user-provided environments. Change-Id: If5821ccb4a8bbf98012a2541ddd3c8e91455e5cc Closes-Bug: #1590507
This commit is contained in:
parent
9befccd0ac
commit
b47c002556
@ -704,12 +704,21 @@ class Environment(object):
|
||||
env_snippet.get(env_fmt.PARAMETER_DEFAULTS, {}))
|
||||
self._update_event_sinks(env_snippet.get(env_fmt.EVENT_SINKS, []))
|
||||
|
||||
def env_as_dict(self):
|
||||
"""Get the entire environment as a dict."""
|
||||
user_env = self.user_env_as_dict()
|
||||
user_env.update(
|
||||
# Any data here is to be stored in the DB but not reflected
|
||||
# as part of the user environment (e.g to pass to nested stacks
|
||||
# or made visible to the user via API calls etc
|
||||
{env_fmt.ENCRYPTED_PARAM_NAMES: self.encrypted_param_names})
|
||||
return user_env
|
||||
|
||||
def user_env_as_dict(self):
|
||||
"""Get the environment as a dict, ready for storing in the db."""
|
||||
"""Get the environment as a dict, only user-allowed keys."""
|
||||
return {env_fmt.RESOURCE_REGISTRY: self.registry.as_dict(),
|
||||
env_fmt.PARAMETERS: self.params,
|
||||
env_fmt.PARAMETER_DEFAULTS: self.param_defaults,
|
||||
env_fmt.ENCRYPTED_PARAM_NAMES: self.encrypted_param_names,
|
||||
env_fmt.EVENT_SINKS: self._event_sinks}
|
||||
|
||||
def register_class(self, resource_type, resource_class, path=None):
|
||||
|
@ -855,7 +855,7 @@ class EngineService(service.Service):
|
||||
# any environment provided into the existing one and attempt
|
||||
# to use the existing stack template, if one is not provided.
|
||||
if args.get(rpc_api.PARAM_EXISTING):
|
||||
existing_env = current_stack.env.user_env_as_dict()
|
||||
existing_env = current_stack.env.env_as_dict()
|
||||
existing_params = existing_env[env_fmt.PARAMETERS]
|
||||
clear_params = set(args.get(rpc_api.PARAM_CLEAR_PARAMETERS, []))
|
||||
retained = dict((k, v) for k, v in existing_params.items()
|
||||
|
@ -138,7 +138,7 @@ class Template(collections.Mapping):
|
||||
rt = {
|
||||
'template': self.t,
|
||||
'files_id': self.files.store(context),
|
||||
'environment': self.env.user_env_as_dict()
|
||||
'environment': self.env.env_as_dict()
|
||||
}
|
||||
if self.id is None:
|
||||
new_rt = template_object.RawTemplate.create(context, rt)
|
||||
|
@ -22,6 +22,7 @@ from heat.common import exception
|
||||
from heat.common import messaging
|
||||
from heat.common import service_utils
|
||||
from heat.common import template_format
|
||||
from heat.db import api as db_api
|
||||
from heat.engine.clients.os import glance
|
||||
from heat.engine.clients.os import nova
|
||||
from heat.engine import environment
|
||||
@ -216,6 +217,65 @@ class ServiceStackUpdateTest(common.HeatTestCase):
|
||||
tmpl.env.params)
|
||||
self.assertEqual(stk.identifier(), result)
|
||||
|
||||
def test_stack_update_existing_encrypted_parameters(self):
|
||||
# Create the stack with encryption enabled
|
||||
# On update encrypted_param_names should be used from existing stack
|
||||
hidden_param_template = u'''
|
||||
heat_template_version: 2013-05-23
|
||||
parameters:
|
||||
param2:
|
||||
type: string
|
||||
description: value2.
|
||||
hidden: true
|
||||
resources:
|
||||
a_resource:
|
||||
type: GenericResourceType
|
||||
'''
|
||||
cfg.CONF.set_override('encrypt_parameters_and_properties', True,
|
||||
enforce_type=True)
|
||||
|
||||
stack_name = 'service_update_test_stack_encrypted_parameters'
|
||||
t = template_format.parse(hidden_param_template)
|
||||
env1 = environment.Environment({'param2': 'bar'})
|
||||
stk = stack.Stack(self.ctx, stack_name,
|
||||
templatem.Template(t, env=env1))
|
||||
stk.store()
|
||||
stk.set_stack_user_project_id('1234')
|
||||
|
||||
# Verify that hidden parameters are stored encrypted
|
||||
db_tpl = db_api.raw_template_get(self.ctx, stk.t.id)
|
||||
db_params = db_tpl.environment['parameters']
|
||||
self.assertEqual('cryptography_decrypt_v1', db_params['param2'][0])
|
||||
self.assertNotEqual("foo", db_params['param2'][1])
|
||||
|
||||
# Verify that loaded stack has decrypted paramters
|
||||
loaded_stack = stack.Stack.load(self.ctx, stack_id=stk.id)
|
||||
params = loaded_stack.t.env.params
|
||||
self.assertEqual('bar', params.get('param2'))
|
||||
|
||||
update_params = {'encrypted_param_names': [],
|
||||
'parameter_defaults': {},
|
||||
'event_sinks': [],
|
||||
'parameters': {},
|
||||
'resource_registry': {'resources': {}}}
|
||||
api_args = {rpc_api.PARAM_TIMEOUT: 60,
|
||||
rpc_api.PARAM_EXISTING: True}
|
||||
|
||||
with mock.patch('heat.engine.stack.Stack') as mock_stack:
|
||||
stk.update = mock.Mock()
|
||||
mock_stack.load.return_value = loaded_stack
|
||||
mock_stack.validate.return_value = None
|
||||
result = self.man.update_stack(self.ctx, stk.identifier(),
|
||||
t,
|
||||
update_params,
|
||||
None, api_args)
|
||||
tmpl = mock_stack.call_args[0][2]
|
||||
self.assertEqual({u'param2': u'bar'}, tmpl.env.params)
|
||||
# encrypted_param_names must be passed from existing to new
|
||||
# stack otherwise the updated stack won't decrypt the params
|
||||
self.assertEqual([u'param2'], tmpl.env.encrypted_param_names)
|
||||
self.assertEqual(stk.identifier(), result)
|
||||
|
||||
def test_stack_update_existing_parameters_remove(self):
|
||||
"""Test case for updating stack with changed parameters.
|
||||
|
||||
@ -288,7 +348,7 @@ class ServiceStackUpdateTest(common.HeatTestCase):
|
||||
stk = utils.parse_stack(t, stack_name=stack_name, params=intial_params,
|
||||
files=initial_files)
|
||||
stk.set_stack_user_project_id('1234')
|
||||
self.assertEqual(intial_params, stk.t.env.user_env_as_dict())
|
||||
self.assertEqual(intial_params, stk.t.env.env_as_dict())
|
||||
|
||||
expected_reg = {'OS::Foo': 'foo.yaml',
|
||||
'OS::Foo2': 'newfoo2.yaml',
|
||||
@ -317,7 +377,7 @@ class ServiceStackUpdateTest(common.HeatTestCase):
|
||||
api_args)
|
||||
tmpl = mock_stack.call_args[0][2]
|
||||
self.assertEqual(expected_env,
|
||||
tmpl.env.user_env_as_dict())
|
||||
tmpl.env.env_as_dict())
|
||||
self.assertEqual(expected_files,
|
||||
tmpl.files.files)
|
||||
self.assertEqual(stk.identifier(), result)
|
||||
@ -361,7 +421,7 @@ class ServiceStackUpdateTest(common.HeatTestCase):
|
||||
None, api_args)
|
||||
tmpl = mock_stack.call_args[0][2]
|
||||
self.assertEqual(expected_env,
|
||||
tmpl.env.user_env_as_dict())
|
||||
tmpl.env.env_as_dict())
|
||||
self.assertEqual(stk.identifier(), result)
|
||||
|
||||
def test_stack_update_reuses_api_params(self):
|
||||
|
@ -47,6 +47,8 @@ class EnvironmentTest(common.HeatTestCase):
|
||||
u'event_sinks': [],
|
||||
u'resource_registry': {u'resources': {}}}
|
||||
env = environment.Environment(old)
|
||||
self.assertEqual(expected, env.env_as_dict())
|
||||
del(expected['encrypted_param_names'])
|
||||
self.assertEqual(expected, env.user_env_as_dict())
|
||||
|
||||
def test_load_new_env(self):
|
||||
@ -57,6 +59,8 @@ class EnvironmentTest(common.HeatTestCase):
|
||||
u'resource_registry': {u'OS::Food': u'fruity.yaml',
|
||||
u'resources': {}}}
|
||||
env = environment.Environment(new_env)
|
||||
self.assertEqual(new_env, env.env_as_dict())
|
||||
del(new_env['encrypted_param_names'])
|
||||
self.assertEqual(new_env, env.user_env_as_dict())
|
||||
|
||||
def test_global_registry(self):
|
||||
@ -155,7 +159,7 @@ class EnvironmentTest(common.HeatTestCase):
|
||||
'b.yaml',
|
||||
path=['resources', 'res_x', 'test::two'])
|
||||
|
||||
self.assertEqual(env.user_env_as_dict(), env2.user_env_as_dict())
|
||||
self.assertEqual(env.env_as_dict(), env2.env_as_dict())
|
||||
|
||||
def test_constraints(self):
|
||||
env = environment.Environment({})
|
||||
@ -520,7 +524,7 @@ class ChildEnvTest(common.HeatTestCase):
|
||||
'event_sinks': [],
|
||||
'resource_registry': {'resources': {}}}
|
||||
cenv = environment.get_child_environment(penv, new_params)
|
||||
self.assertEqual(expected, cenv.user_env_as_dict())
|
||||
self.assertEqual(expected, cenv.env_as_dict())
|
||||
|
||||
def test_params_normal(self):
|
||||
new_params = {'parameters': {'foo': 'bar', 'tester': 'Yes'}}
|
||||
@ -531,7 +535,7 @@ class ChildEnvTest(common.HeatTestCase):
|
||||
'resource_registry': {'resources': {}}}
|
||||
expected.update(new_params)
|
||||
cenv = environment.get_child_environment(penv, new_params)
|
||||
self.assertEqual(expected, cenv.user_env_as_dict())
|
||||
self.assertEqual(expected, cenv.env_as_dict())
|
||||
|
||||
def test_params_parent_overwritten(self):
|
||||
new_params = {'parameters': {'foo': 'bar', 'tester': 'Yes'}}
|
||||
@ -543,7 +547,7 @@ class ChildEnvTest(common.HeatTestCase):
|
||||
'resource_registry': {'resources': {}}}
|
||||
expected.update(new_params)
|
||||
cenv = environment.get_child_environment(penv, new_params)
|
||||
self.assertEqual(expected, cenv.user_env_as_dict())
|
||||
self.assertEqual(expected, cenv.env_as_dict())
|
||||
|
||||
def test_registry_merge_simple(self):
|
||||
env1 = {u'resource_registry': {u'OS::Food': u'fruity.yaml'}}
|
||||
|
@ -844,8 +844,7 @@ class WithTemplateTest(StackResourceBaseTest):
|
||||
child_env = {'parameter_defaults': {},
|
||||
'event_sinks': [],
|
||||
'parameters': self.params,
|
||||
'resource_registry': {'resources': {}},
|
||||
'encrypted_param_names': []}
|
||||
'resource_registry': {'resources': {}}}
|
||||
self.parent_resource.child_params = mock.Mock(
|
||||
return_value=self.params)
|
||||
res_name = self.parent_resource.physical_resource_name()
|
||||
@ -891,8 +890,7 @@ class WithTemplateTest(StackResourceBaseTest):
|
||||
child_env = {'parameter_defaults': {},
|
||||
'event_sinks': [],
|
||||
'parameters': self.params,
|
||||
'resource_registry': {'resources': {}},
|
||||
'encrypted_param_names': []}
|
||||
'resource_registry': {'resources': {}}}
|
||||
self.parent_resource.child_params = mock.Mock(
|
||||
return_value=self.params)
|
||||
res_name = self.parent_resource.physical_resource_name()
|
||||
|
Loading…
x
Reference in New Issue
Block a user