Merge "Keep encrypted_param_names environment internal to heat"

This commit is contained in:
Jenkins 2016-06-30 22:00:02 +00:00 committed by Gerrit Code Review
commit 84cb131c5d
6 changed files with 86 additions and 15 deletions

View File

@ -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):

View File

@ -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()

View File

@ -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)

View File

@ -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):

View File

@ -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'}}

View File

@ -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()