Add "parameter_defaults" to the environment
This give the user a way to set defaults recursively down nested stacks without having to create the parameter in every template (it's ignored if the template does not have the parameter). blueprint env-nested-usability Change-Id: Ie6b4481417204a527d322fd532c341b9acbce473
This commit is contained in:
@@ -29,8 +29,8 @@ what plug-ins the cloud operator has installed.
|
|||||||
Format
|
Format
|
||||||
------
|
------
|
||||||
|
|
||||||
It is a yaml text file with two main sections "resource_registry" and
|
It is a yaml text file with three main sections "resource_registry",
|
||||||
"parameters".
|
"parameters" and "parameter_defaults".
|
||||||
|
|
||||||
------------------
|
------------------
|
||||||
Command line usage
|
Command line usage
|
||||||
@@ -81,8 +81,18 @@ Usage examples
|
|||||||
InstanceType: m1.micro
|
InstanceType: m1.micro
|
||||||
ImageId: F18-x86_64-cfntools
|
ImageId: F18-x86_64-cfntools
|
||||||
|
|
||||||
|
2) Define defaults to parameters
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
This is especially useful when you have many template resources and
|
||||||
|
you want the same value in each. Note: these defaults will get passed
|
||||||
|
down into all template resources.
|
||||||
|
::
|
||||||
|
|
||||||
2) Deal with the mapping of Quantum to Neutron
|
parameter_defaults:
|
||||||
|
KeyName: heat_key
|
||||||
|
|
||||||
|
|
||||||
|
3) Deal with the mapping of Quantum to Neutron
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
::
|
::
|
||||||
|
|
||||||
@@ -92,7 +102,7 @@ Usage examples
|
|||||||
So all existing resources which can be matched with "OS::Neutron*"
|
So all existing resources which can be matched with "OS::Neutron*"
|
||||||
will be mapped to "OS::Quantum*" accordingly.
|
will be mapped to "OS::Quantum*" accordingly.
|
||||||
|
|
||||||
3) Override a resource type with a custom template resource
|
4) Override a resource type with a custom template resource
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
::
|
::
|
||||||
|
|
||||||
@@ -103,7 +113,7 @@ Please note that the template resource URL here must end with ".yaml"
|
|||||||
or ".template", or it will not be treated as a custom template
|
or ".template", or it will not be treated as a custom template
|
||||||
resource. The supported URL types are "http, https and file".
|
resource. The supported URL types are "http, https and file".
|
||||||
|
|
||||||
4) Always map resource type X to Y
|
5) Always map resource type X to Y
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
::
|
::
|
||||||
|
|
||||||
@@ -111,7 +121,7 @@ resource. The supported URL types are "http, https and file".
|
|||||||
"OS::Networking::FloatingIP": "OS::Nova::FloatingIP"
|
"OS::Networking::FloatingIP": "OS::Nova::FloatingIP"
|
||||||
|
|
||||||
|
|
||||||
5) Use default resources except one for a particular resource in the template
|
6) Use default resources except one for a particular resource in the template
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
::
|
::
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ from heat.common.i18n import _
|
|||||||
from heat.common import template_format
|
from heat.common import template_format
|
||||||
|
|
||||||
|
|
||||||
SECTIONS = (PARAMETERS, RESOURCE_REGISTRY) = \
|
SECTIONS = (PARAMETERS, RESOURCE_REGISTRY, PARAMETER_DEFAULTS) = \
|
||||||
('parameters', 'resource_registry')
|
('parameters', 'resource_registry', 'parameter_defaults')
|
||||||
|
|
||||||
|
|
||||||
def parse(env_str):
|
def parse(env_str):
|
||||||
|
|||||||
@@ -69,14 +69,20 @@ class CfnTemplate(template.Template):
|
|||||||
# to be consistent with an empty json section.
|
# to be consistent with an empty json section.
|
||||||
return self.t.get(section) or default
|
return self.t.get(section) or default
|
||||||
|
|
||||||
def param_schemata(self):
|
def param_schemata(self, param_defaults=None):
|
||||||
params = self.t.get(self.PARAMETERS) or {}
|
params = self.t.get(self.PARAMETERS) or {}
|
||||||
|
pdefaults = param_defaults or {}
|
||||||
|
for name, schema in six.iteritems(params):
|
||||||
|
if name in pdefaults:
|
||||||
|
params[name][parameters.DEFAULT] = pdefaults[name]
|
||||||
|
|
||||||
return dict((name, parameters.Schema.from_dict(name, schema))
|
return dict((name, parameters.Schema.from_dict(name, schema))
|
||||||
for name, schema in six.iteritems(params))
|
for name, schema in six.iteritems(params))
|
||||||
|
|
||||||
def parameters(self, stack_identifier, user_params):
|
def parameters(self, stack_identifier, user_params, param_defaults=None):
|
||||||
return parameters.Parameters(stack_identifier, self,
|
return parameters.Parameters(stack_identifier, self,
|
||||||
user_params=user_params)
|
user_params=user_params,
|
||||||
|
param_defaults=param_defaults)
|
||||||
|
|
||||||
def resource_definitions(self, stack):
|
def resource_definitions(self, stack):
|
||||||
def rsrc_defn_item(name, snippet):
|
def rsrc_defn_item(name, snippet):
|
||||||
|
|||||||
@@ -121,8 +121,10 @@ class TemplateResourceInfo(ResourceInfo):
|
|||||||
|
|
||||||
def get_class(self):
|
def get_class(self):
|
||||||
from heat.engine.resources import template_resource
|
from heat.engine.resources import template_resource
|
||||||
|
env = self.registry.environment
|
||||||
return template_resource.generate_class(str(self.name),
|
return template_resource.generate_class(str(self.name),
|
||||||
self.template_name)
|
self.template_name,
|
||||||
|
env)
|
||||||
|
|
||||||
|
|
||||||
class MapResourceInfo(ResourceInfo):
|
class MapResourceInfo(ResourceInfo):
|
||||||
@@ -156,9 +158,10 @@ class GlobResourceInfo(MapResourceInfo):
|
|||||||
class ResourceRegistry(object):
|
class ResourceRegistry(object):
|
||||||
"""By looking at the environment, find the resource implementation."""
|
"""By looking at the environment, find the resource implementation."""
|
||||||
|
|
||||||
def __init__(self, global_registry):
|
def __init__(self, global_registry, env):
|
||||||
self._registry = {'resources': {}}
|
self._registry = {'resources': {}}
|
||||||
self.global_registry = global_registry
|
self.global_registry = global_registry
|
||||||
|
self.environment = env
|
||||||
|
|
||||||
def load(self, json_snippet):
|
def load(self, json_snippet):
|
||||||
self._load_registry([], json_snippet)
|
self._load_registry([], json_snippet)
|
||||||
@@ -363,20 +366,28 @@ class Environment(object):
|
|||||||
else:
|
else:
|
||||||
global_registry = None
|
global_registry = None
|
||||||
|
|
||||||
self.registry = ResourceRegistry(global_registry)
|
self.registry = ResourceRegistry(global_registry, self)
|
||||||
self.registry.load(env.get(env_fmt.RESOURCE_REGISTRY, {}))
|
self.registry.load(env.get(env_fmt.RESOURCE_REGISTRY, {}))
|
||||||
|
|
||||||
|
if env_fmt.PARAMETER_DEFAULTS in env:
|
||||||
|
self.param_defaults = env[env_fmt.PARAMETER_DEFAULTS]
|
||||||
|
else:
|
||||||
|
self.param_defaults = {}
|
||||||
|
|
||||||
if env_fmt.PARAMETERS in env:
|
if env_fmt.PARAMETERS in env:
|
||||||
self.params = env[env_fmt.PARAMETERS]
|
self.params = env[env_fmt.PARAMETERS]
|
||||||
else:
|
else:
|
||||||
self.params = dict((k, v) for (k, v) in six.iteritems(env)
|
self.params = dict((k, v) for (k, v) in six.iteritems(env)
|
||||||
if k != env_fmt.RESOURCE_REGISTRY)
|
if k not in (env_fmt.PARAMETER_DEFAULTS,
|
||||||
|
env_fmt.RESOURCE_REGISTRY))
|
||||||
self.constraints = {}
|
self.constraints = {}
|
||||||
self.stack_lifecycle_plugins = []
|
self.stack_lifecycle_plugins = []
|
||||||
|
|
||||||
def load(self, env_snippet):
|
def load(self, env_snippet):
|
||||||
self.registry.load(env_snippet.get(env_fmt.RESOURCE_REGISTRY, {}))
|
self.registry.load(env_snippet.get(env_fmt.RESOURCE_REGISTRY, {}))
|
||||||
self.params.update(env_snippet.get(env_fmt.PARAMETERS, {}))
|
self.params.update(env_snippet.get(env_fmt.PARAMETERS, {}))
|
||||||
|
self.param_defaults.update(
|
||||||
|
env_snippet.get(env_fmt.PARAMETER_DEFAULTS, {}))
|
||||||
|
|
||||||
def patch_previous_parameters(self, previous_env, clear_parameters=[]):
|
def patch_previous_parameters(self, previous_env, clear_parameters=[]):
|
||||||
"""This instance of Environment is the new environment where
|
"""This instance of Environment is the new environment where
|
||||||
@@ -394,7 +405,8 @@ class Environment(object):
|
|||||||
def user_env_as_dict(self):
|
def user_env_as_dict(self):
|
||||||
"""Get the environment as a dict, ready for storing in the db."""
|
"""Get the environment as a dict, ready for storing in the db."""
|
||||||
return {env_fmt.RESOURCE_REGISTRY: self.registry.as_dict(),
|
return {env_fmt.RESOURCE_REGISTRY: self.registry.as_dict(),
|
||||||
env_fmt.PARAMETERS: self.params}
|
env_fmt.PARAMETERS: self.params,
|
||||||
|
env_fmt.PARAMETER_DEFAULTS: self.param_defaults}
|
||||||
|
|
||||||
def register_class(self, resource_type, resource_class):
|
def register_class(self, resource_type, resource_class):
|
||||||
self.registry.register_class(resource_type, resource_class)
|
self.registry.register_class(resource_type, resource_class)
|
||||||
@@ -425,22 +437,25 @@ class Environment(object):
|
|||||||
return self.stack_lifecycle_plugins
|
return self.stack_lifecycle_plugins
|
||||||
|
|
||||||
|
|
||||||
def get_custom_environment(registry, cust_params):
|
def get_child_environment(parent_env, child_params):
|
||||||
"""Build a customized environment using the given registry and params.
|
"""Build a child environment using the parent environment and params.
|
||||||
This is built from the cust_params and the given registry so some
|
This is built from the child_params and the parent env so some
|
||||||
resources can use user-provided parameters as if they come from an
|
resources can use user-provided parameters as if they come from an
|
||||||
environment.
|
environment.
|
||||||
"""
|
"""
|
||||||
new_env = Environment()
|
new_env = Environment()
|
||||||
new_env.registry = registry
|
new_env.registry = copy.copy(parent_env.registry)
|
||||||
cust_env = {env_fmt.PARAMETERS: {}}
|
new_env.environment = new_env
|
||||||
if cust_params is not None:
|
child_env = {
|
||||||
if env_fmt.PARAMETERS not in cust_params:
|
env_fmt.PARAMETERS: {},
|
||||||
cust_env[env_fmt.PARAMETERS] = cust_params
|
env_fmt.PARAMETER_DEFAULTS: parent_env.param_defaults}
|
||||||
|
if child_params is not None:
|
||||||
|
if env_fmt.PARAMETERS not in child_params:
|
||||||
|
child_env[env_fmt.PARAMETERS] = child_params
|
||||||
else:
|
else:
|
||||||
cust_env.update(cust_params)
|
child_env.update(child_params)
|
||||||
|
|
||||||
new_env.load(cust_env)
|
new_env.load(child_env)
|
||||||
return new_env
|
return new_env
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -171,17 +171,21 @@ class HOTemplate20130523(template.Template):
|
|||||||
return self._translate_section('outputs', 'value', outputs,
|
return self._translate_section('outputs', 'value', outputs,
|
||||||
HOT_TO_CFN_ATTRS)
|
HOT_TO_CFN_ATTRS)
|
||||||
|
|
||||||
def param_schemata(self):
|
def param_schemata(self, param_defaults=None):
|
||||||
parameter_section = self.t.get(self.PARAMETERS)
|
parameter_section = self.t.get(self.PARAMETERS) or {}
|
||||||
if parameter_section is None:
|
pdefaults = param_defaults or {}
|
||||||
parameter_section = {}
|
for name, schema in six.iteritems(parameter_section):
|
||||||
|
if name in pdefaults:
|
||||||
|
parameter_section[name]['default'] = pdefaults[name]
|
||||||
|
|
||||||
params = six.iteritems(parameter_section)
|
params = six.iteritems(parameter_section)
|
||||||
return dict((name, parameters.HOTParamSchema.from_dict(name, schema))
|
return dict((name, parameters.HOTParamSchema.from_dict(name, schema))
|
||||||
for name, schema in params)
|
for name, schema in params)
|
||||||
|
|
||||||
def parameters(self, stack_identifier, user_params):
|
def parameters(self, stack_identifier, user_params, param_defaults=None):
|
||||||
return parameters.HOTParameters(stack_identifier, self,
|
return parameters.HOTParameters(stack_identifier, self,
|
||||||
user_params=user_params)
|
user_params=user_params,
|
||||||
|
param_defaults=param_defaults)
|
||||||
|
|
||||||
def resource_definitions(self, stack):
|
def resource_definitions(self, stack):
|
||||||
allowed_keys = set(_RESOURCE_KEYS)
|
allowed_keys = set(_RESOURCE_KEYS)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class ParameterGroups(object):
|
|||||||
'''
|
'''
|
||||||
def __init__(self, tmpl):
|
def __init__(self, tmpl):
|
||||||
self.tmpl = tmpl
|
self.tmpl = tmpl
|
||||||
self.parameters = tmpl.parameters(None, {})
|
self.parameters = tmpl.parameters(None, {}, param_defaults={})
|
||||||
LOG.debug(self.tmpl)
|
LOG.debug(self.tmpl)
|
||||||
LOG.debug(self.parameters)
|
LOG.debug(self.parameters)
|
||||||
self.parameter_names = []
|
self.parameter_names = []
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ class Parameter(object):
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.schema = schema
|
self.schema = schema
|
||||||
self.user_value = value
|
self.user_value = value
|
||||||
|
self.user_default = None
|
||||||
|
|
||||||
def validate(self, validate_value=True, context=None):
|
def validate(self, validate_value=True, context=None):
|
||||||
'''
|
'''
|
||||||
@@ -264,11 +265,15 @@ class Parameter(object):
|
|||||||
|
|
||||||
def has_default(self):
|
def has_default(self):
|
||||||
'''Return whether the parameter has a default value.'''
|
'''Return whether the parameter has a default value.'''
|
||||||
return self.schema.default is not None
|
return (self.schema.default is not None or
|
||||||
|
self.user_default is not None)
|
||||||
|
|
||||||
def default(self):
|
def default(self):
|
||||||
'''Return the default value of the parameter.'''
|
'''Return the default value of the parameter.'''
|
||||||
return self.schema.default
|
return self.user_default or self.schema.default
|
||||||
|
|
||||||
|
def set_default(self, value):
|
||||||
|
self.user_default = value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
'''Return a string representation of the parameter'''
|
'''Return a string representation of the parameter'''
|
||||||
@@ -421,12 +426,14 @@ class Parameters(collections.Mapping):
|
|||||||
'AWS::StackId', 'AWS::StackName', 'AWS::Region'
|
'AWS::StackId', 'AWS::StackName', 'AWS::Region'
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, stack_identifier, tmpl, user_params=None):
|
def __init__(self, stack_identifier, tmpl, user_params=None,
|
||||||
|
param_defaults=None):
|
||||||
'''
|
'''
|
||||||
Create the parameter container for a stack from the stack name and
|
Create the parameter container for a stack from the stack name and
|
||||||
template, optionally setting the user-supplied parameter values.
|
template, optionally setting the user-supplied parameter values.
|
||||||
'''
|
'''
|
||||||
user_params = user_params or {}
|
user_params = user_params or {}
|
||||||
|
param_defaults = param_defaults or {}
|
||||||
|
|
||||||
def user_parameter(schema_item):
|
def user_parameter(schema_item):
|
||||||
name, schema = schema_item
|
name, schema = schema_item
|
||||||
@@ -445,6 +452,10 @@ class Parameters(collections.Mapping):
|
|||||||
p) for p in itertools.chain(pseudo_parameters,
|
p) for p in itertools.chain(pseudo_parameters,
|
||||||
user_parameters))
|
user_parameters))
|
||||||
|
|
||||||
|
for pd in six.iterkeys(param_defaults):
|
||||||
|
if pd in self.params:
|
||||||
|
self.params[pd].set_default(param_defaults[pd])
|
||||||
|
|
||||||
def validate(self, validate_value=True, context=None):
|
def validate(self, validate_value=True, context=None):
|
||||||
'''
|
'''
|
||||||
Validates all parameters.
|
Validates all parameters.
|
||||||
|
|||||||
@@ -135,9 +135,8 @@ class RemoteStack(resource.Resource):
|
|||||||
raise exception.StackValidationFailed(message=msg)
|
raise exception.StackValidationFailed(message=msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
registry = self.stack.env.registry
|
|
||||||
params = self.properties[self.PARAMETERS]
|
params = self.properties[self.PARAMETERS]
|
||||||
env = environment.get_custom_environment(registry, params)
|
env = environment.get_child_environment(self.stack.env, params)
|
||||||
tmpl = template_format.parse(self.properties[self.TEMPLATE])
|
tmpl = template_format.parse(self.properties[self.TEMPLATE])
|
||||||
args = {
|
args = {
|
||||||
'template': tmpl,
|
'template': tmpl,
|
||||||
@@ -153,9 +152,8 @@ class RemoteStack(resource.Resource):
|
|||||||
raise exception.StackValidationFailed(message=msg)
|
raise exception.StackValidationFailed(message=msg)
|
||||||
|
|
||||||
def handle_create(self):
|
def handle_create(self):
|
||||||
registry = self.stack.env.registry
|
|
||||||
params = self.properties[self.PARAMETERS]
|
params = self.properties[self.PARAMETERS]
|
||||||
env = environment.get_custom_environment(registry, params)
|
env = environment.get_child_environment(self.stack.env, params)
|
||||||
tmpl = template_format.parse(self.properties[self.TEMPLATE])
|
tmpl = template_format.parse(self.properties[self.TEMPLATE])
|
||||||
args = {
|
args = {
|
||||||
'stack_name': self.physical_resource_name_or_FnGetRefId(),
|
'stack_name': self.physical_resource_name_or_FnGetRefId(),
|
||||||
@@ -197,8 +195,7 @@ class RemoteStack(resource.Resource):
|
|||||||
self.name)
|
self.name)
|
||||||
|
|
||||||
params = self.properties[self.PARAMETERS]
|
params = self.properties[self.PARAMETERS]
|
||||||
registry = self.stack.env.registry
|
env = environment.get_child_environment(self.stack.env, params)
|
||||||
env = environment.get_custom_environment(registry, params)
|
|
||||||
tmpl = template_format.parse(self.properties[self.TEMPLATE])
|
tmpl = template_format.parse(self.properties[self.TEMPLATE])
|
||||||
fields = {
|
fields = {
|
||||||
'stack_id': self.resource_id,
|
'stack_id': self.resource_id,
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ from heat.engine import stack_resource
|
|||||||
from heat.engine import template
|
from heat.engine import template
|
||||||
|
|
||||||
|
|
||||||
def generate_class(name, template_name):
|
def generate_class(name, template_name, env):
|
||||||
data = TemplateResource.get_template_file(template_name, ('file',))
|
data = TemplateResource.get_template_file(template_name, ('file',))
|
||||||
tmpl = template.Template(template_format.parse(data))
|
tmpl = template.Template(template_format.parse(data))
|
||||||
props, attrs = TemplateResource.get_schemas(tmpl)
|
props, attrs = TemplateResource.get_schemas(tmpl, env.param_defaults)
|
||||||
cls = type(name, (TemplateResource,),
|
cls = type(name, (TemplateResource,),
|
||||||
{'properties_schema': props,
|
{'properties_schema': props,
|
||||||
'attributes_schema': attrs})
|
'attributes_schema': attrs})
|
||||||
@@ -83,9 +83,9 @@ class TemplateResource(stack_resource.StackResource):
|
|||||||
raise exception.NotFound(msg_fmt=msg)
|
raise exception.NotFound(msg_fmt=msg)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_schemas(tmpl):
|
def get_schemas(tmpl, param_defaults):
|
||||||
return ((properties.Properties.schema_from_params(
|
return ((properties.Properties.schema_from_params(
|
||||||
tmpl.param_schemata())),
|
tmpl.param_schemata(param_defaults))),
|
||||||
(attributes.Attributes.schema_from_outputs(
|
(attributes.Attributes.schema_from_outputs(
|
||||||
tmpl[tmpl.OUTPUTS])))
|
tmpl[tmpl.OUTPUTS])))
|
||||||
|
|
||||||
@@ -99,7 +99,8 @@ class TemplateResource(stack_resource.StackResource):
|
|||||||
{"HeatTemplateFormatVersion": "2012-12-12"})
|
{"HeatTemplateFormatVersion": "2012-12-12"})
|
||||||
|
|
||||||
# re-generate the properties and attributes from the template.
|
# re-generate the properties and attributes from the template.
|
||||||
self.properties_schema, self.attributes_schema = self.get_schemas(tmpl)
|
self.properties_schema, self.attributes_schema = self.get_schemas(
|
||||||
|
tmpl, self.stack.env.param_defaults)
|
||||||
|
|
||||||
self.properties = definition.properties(self.properties_schema,
|
self.properties = definition.properties(self.properties_schema,
|
||||||
self.context)
|
self.context)
|
||||||
|
|||||||
@@ -131,8 +131,10 @@ class Stack(collections.Mapping):
|
|||||||
resources.initialise()
|
resources.initialise()
|
||||||
|
|
||||||
self.env = env or environment.Environment({})
|
self.env = env or environment.Environment({})
|
||||||
self.parameters = self.t.parameters(self.identifier(),
|
self.parameters = self.t.parameters(
|
||||||
user_params=self.env.params)
|
self.identifier(),
|
||||||
|
user_params=self.env.params,
|
||||||
|
param_defaults=self.env.param_defaults)
|
||||||
self._set_param_stackid()
|
self._set_param_stackid()
|
||||||
|
|
||||||
if resolve_data:
|
if resolve_data:
|
||||||
|
|||||||
@@ -164,13 +164,12 @@ class StackResource(resource.Resource):
|
|||||||
|
|
||||||
# Note we disable rollback for nested stacks, since they
|
# Note we disable rollback for nested stacks, since they
|
||||||
# should be rolled back by the parent stack on failure
|
# should be rolled back by the parent stack on failure
|
||||||
child_env = environment.get_custom_environment(
|
child_env = environment.get_child_environment(
|
||||||
self.stack.env.registry,
|
self.stack.env, child_params)
|
||||||
child_params)
|
|
||||||
nested = parser.Stack(self.context,
|
nested = parser.Stack(self.context,
|
||||||
stack_name,
|
stack_name,
|
||||||
parsed_template,
|
parsed_template,
|
||||||
child_env,
|
env=child_env,
|
||||||
timeout_mins=timeout_mins,
|
timeout_mins=timeout_mins,
|
||||||
disable_rollback=True,
|
disable_rollback=True,
|
||||||
parent_resource=self,
|
parent_resource=self,
|
||||||
|
|||||||
@@ -139,12 +139,12 @@ class Template(collections.Mapping):
|
|||||||
return len(self.SECTIONS) - len(self.SECTIONS_NO_DIRECT_ACCESS)
|
return len(self.SECTIONS) - len(self.SECTIONS_NO_DIRECT_ACCESS)
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def param_schemata(self):
|
def param_schemata(self, param_defaults=None):
|
||||||
'''Return a dict of parameters.Schema objects for the parameters.'''
|
'''Return a dict of parameters.Schema objects for the parameters.'''
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def parameters(self, stack_identifier, user_params):
|
def parameters(self, stack_identifier, user_params, param_defaults=None):
|
||||||
'''Return a parameters.Parameters object for the stack.'''
|
'''Return a parameters.Parameters object for the stack.'''
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ blarg: wibble
|
|||||||
def test_parameters(self):
|
def test_parameters(self):
|
||||||
params = {'foo': 'bar', 'blarg': 'wibble'}
|
params = {'foo': 'bar', 'blarg': 'wibble'}
|
||||||
body = {'parameters': params,
|
body = {'parameters': params,
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}}
|
'resource_registry': {}}
|
||||||
data = stacks.InstantiationData(body)
|
data = stacks.InstantiationData(body)
|
||||||
self.assertEqual(body, data.environment())
|
self.assertEqual(body, data.environment())
|
||||||
@@ -178,6 +179,7 @@ blarg: wibble
|
|||||||
'environment': {'parameters': {'blarg': 'wibble'}}}
|
'environment': {'parameters': {'blarg': 'wibble'}}}
|
||||||
expect = {'parameters': {'blarg': 'wibble',
|
expect = {'parameters': {'blarg': 'wibble',
|
||||||
'foo': 'bar'},
|
'foo': 'bar'},
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}}
|
'resource_registry': {}}
|
||||||
data = stacks.InstantiationData(body)
|
data = stacks.InstantiationData(body)
|
||||||
self.assertEqual(expect, data.environment())
|
self.assertEqual(expect, data.environment())
|
||||||
@@ -192,6 +194,7 @@ blarg: wibble
|
|||||||
expect = {'parameters': {'blarg': 'wibble',
|
expect = {'parameters': {'blarg': 'wibble',
|
||||||
'foo': 'bar',
|
'foo': 'bar',
|
||||||
'tester': 'Yes'},
|
'tester': 'Yes'},
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}}
|
'resource_registry': {}}
|
||||||
data = stacks.InstantiationData(body)
|
data = stacks.InstantiationData(body)
|
||||||
self.assertEqual(expect, data.environment())
|
self.assertEqual(expect, data.environment())
|
||||||
@@ -206,7 +209,8 @@ blarg: wibble
|
|||||||
env = {'foo': 'bar', 'blarg': 'wibble'}
|
env = {'foo': 'bar', 'blarg': 'wibble'}
|
||||||
body = {'not the environment': env}
|
body = {'not the environment': env}
|
||||||
data = stacks.InstantiationData(body)
|
data = stacks.InstantiationData(body)
|
||||||
self.assertEqual({'parameters': {}, 'resource_registry': {}},
|
self.assertEqual({'parameters': {}, 'parameter_defaults': {},
|
||||||
|
'resource_registry': {}},
|
||||||
data.environment())
|
data.environment())
|
||||||
|
|
||||||
def test_args(self):
|
def test_args(self):
|
||||||
@@ -710,6 +714,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_name': identity.stack_name,
|
{'stack_name': identity.stack_name,
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {'parameters': parameters,
|
'params': {'parameters': parameters,
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}},
|
'resource_registry': {}},
|
||||||
'files': {},
|
'files': {},
|
||||||
'args': {'timeout_mins': 30},
|
'args': {'timeout_mins': 30},
|
||||||
@@ -770,6 +775,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_name': identity.stack_name,
|
{'stack_name': identity.stack_name,
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {'parameters': parameters,
|
'params': {'parameters': parameters,
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}},
|
'resource_registry': {}},
|
||||||
'files': {},
|
'files': {},
|
||||||
'args': {'timeout_mins': 30,
|
'args': {'timeout_mins': 30,
|
||||||
@@ -835,6 +841,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_name': identity.stack_name,
|
{'stack_name': identity.stack_name,
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {'parameters': parameters,
|
'params': {'parameters': parameters,
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}},
|
'resource_registry': {}},
|
||||||
'files': {'my.yaml': 'This is the file contents.'},
|
'files': {'my.yaml': 'This is the file contents.'},
|
||||||
'args': {'timeout_mins': 30},
|
'args': {'timeout_mins': 30},
|
||||||
@@ -877,6 +884,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_name': stack_name,
|
{'stack_name': stack_name,
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {'parameters': parameters,
|
'params': {'parameters': parameters,
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}},
|
'resource_registry': {}},
|
||||||
'files': {},
|
'files': {},
|
||||||
'args': {'timeout_mins': 30},
|
'args': {'timeout_mins': 30},
|
||||||
@@ -892,6 +900,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_name': stack_name,
|
{'stack_name': stack_name,
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {'parameters': parameters,
|
'params': {'parameters': parameters,
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}},
|
'resource_registry': {}},
|
||||||
'files': {},
|
'files': {},
|
||||||
'args': {'timeout_mins': 30},
|
'args': {'timeout_mins': 30},
|
||||||
@@ -907,6 +916,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_name': stack_name,
|
{'stack_name': stack_name,
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {'parameters': parameters,
|
'params': {'parameters': parameters,
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}},
|
'resource_registry': {}},
|
||||||
'files': {},
|
'files': {},
|
||||||
'args': {'timeout_mins': 30},
|
'args': {'timeout_mins': 30},
|
||||||
@@ -959,6 +969,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_name': stack_name,
|
{'stack_name': stack_name,
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {'parameters': parameters,
|
'params': {'parameters': parameters,
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}},
|
'resource_registry': {}},
|
||||||
'files': {},
|
'files': {},
|
||||||
'args': {'timeout_mins': 30},
|
'args': {'timeout_mins': 30},
|
||||||
@@ -1017,6 +1028,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_name': stack_name,
|
{'stack_name': stack_name,
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {'parameters': parameters,
|
'params': {'parameters': parameters,
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}},
|
'resource_registry': {}},
|
||||||
'files': {},
|
'files': {},
|
||||||
'args': {'timeout_mins': 30},
|
'args': {'timeout_mins': 30},
|
||||||
@@ -1415,6 +1427,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_identity': dict(identity),
|
{'stack_identity': dict(identity),
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {'parameters': parameters,
|
'params': {'parameters': parameters,
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}},
|
'resource_registry': {}},
|
||||||
'files': {},
|
'files': {},
|
||||||
'args': {'timeout_mins': 30}})
|
'args': {'timeout_mins': 30}})
|
||||||
@@ -1450,6 +1463,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_identity': dict(identity),
|
{'stack_identity': dict(identity),
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {u'parameters': parameters,
|
'params': {u'parameters': parameters,
|
||||||
|
u'parameter_defaults': {},
|
||||||
u'resource_registry': {}},
|
u'resource_registry': {}},
|
||||||
'files': {},
|
'files': {},
|
||||||
'args': {'timeout_mins': 30}})
|
'args': {'timeout_mins': 30}})
|
||||||
@@ -1509,6 +1523,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_identity': dict(identity),
|
{'stack_identity': dict(identity),
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {'parameters': {},
|
'params': {'parameters': {},
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}},
|
'resource_registry': {}},
|
||||||
'files': {},
|
'files': {},
|
||||||
'args': {rpc_api.PARAM_EXISTING: True,
|
'args': {rpc_api.PARAM_EXISTING: True,
|
||||||
@@ -1544,6 +1559,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_identity': dict(identity),
|
{'stack_identity': dict(identity),
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {'parameters': parameters,
|
'params': {'parameters': parameters,
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}},
|
'resource_registry': {}},
|
||||||
'files': {},
|
'files': {},
|
||||||
'args': {rpc_api.PARAM_EXISTING: True,
|
'args': {rpc_api.PARAM_EXISTING: True,
|
||||||
@@ -1581,6 +1597,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_identity': dict(identity),
|
{'stack_identity': dict(identity),
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {'parameters': {},
|
'params': {'parameters': {},
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}},
|
'resource_registry': {}},
|
||||||
'files': {},
|
'files': {},
|
||||||
'args': {rpc_api.PARAM_EXISTING: True,
|
'args': {rpc_api.PARAM_EXISTING: True,
|
||||||
@@ -1620,6 +1637,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
{'stack_identity': dict(identity),
|
{'stack_identity': dict(identity),
|
||||||
'template': template,
|
'template': template,
|
||||||
'params': {'parameters': parameters,
|
'params': {'parameters': parameters,
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}},
|
'resource_registry': {}},
|
||||||
'files': {},
|
'files': {},
|
||||||
'args': {rpc_api.PARAM_EXISTING: True,
|
'args': {rpc_api.PARAM_EXISTING: True,
|
||||||
@@ -1757,6 +1775,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
('validate_template',
|
('validate_template',
|
||||||
{'template': template,
|
{'template': template,
|
||||||
'params': {'parameters': {},
|
'params': {'parameters': {},
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}}})
|
'resource_registry': {}}})
|
||||||
).AndReturn(engine_response)
|
).AndReturn(engine_response)
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
@@ -1780,6 +1799,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
|
|||||||
('validate_template',
|
('validate_template',
|
||||||
{'template': template,
|
{'template': template,
|
||||||
'params': {'parameters': {},
|
'params': {'parameters': {},
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {}}})
|
'resource_registry': {}}})
|
||||||
).AndReturn({'Error': 'fubar'})
|
).AndReturn({'Error': 'fubar'})
|
||||||
self.m.ReplayAll()
|
self.m.ReplayAll()
|
||||||
|
|||||||
@@ -2286,7 +2286,8 @@ class StackServiceTest(common.HeatTestCase):
|
|||||||
self.assertEqual(expected, schema)
|
self.assertEqual(expected, schema)
|
||||||
|
|
||||||
def _no_template_file(self, function):
|
def _no_template_file(self, function):
|
||||||
info = environment.ResourceInfo(environment.ResourceRegistry,
|
env = environment.Environment()
|
||||||
|
info = environment.ResourceInfo(env.registry,
|
||||||
['ResourceWithWrongRefOnFile'],
|
['ResourceWithWrongRefOnFile'],
|
||||||
'not_existing.yaml')
|
'not_existing.yaml')
|
||||||
mock_iterable = mock.MagicMock(return_value=iter([info]))
|
mock_iterable = mock.MagicMock(return_value=iter([info]))
|
||||||
|
|||||||
@@ -36,12 +36,14 @@ class EnvironmentTest(common.HeatTestCase):
|
|||||||
def test_load_old_parameters(self):
|
def test_load_old_parameters(self):
|
||||||
old = {u'a': u'ff', u'b': u'ss'}
|
old = {u'a': u'ff', u'b': u'ss'}
|
||||||
expected = {u'parameters': old,
|
expected = {u'parameters': old,
|
||||||
|
u'parameter_defaults': {},
|
||||||
u'resource_registry': {u'resources': {}}}
|
u'resource_registry': {u'resources': {}}}
|
||||||
env = environment.Environment(old)
|
env = environment.Environment(old)
|
||||||
self.assertEqual(expected, env.user_env_as_dict())
|
self.assertEqual(expected, env.user_env_as_dict())
|
||||||
|
|
||||||
def test_load_new_env(self):
|
def test_load_new_env(self):
|
||||||
new_env = {u'parameters': {u'a': u'ff', u'b': u'ss'},
|
new_env = {u'parameters': {u'a': u'ff', u'b': u'ss'},
|
||||||
|
u'parameter_defaults': {u'ff': 'new_def'},
|
||||||
u'resource_registry': {u'OS::Food': u'fruity.yaml',
|
u'resource_registry': {u'OS::Food': u'fruity.yaml',
|
||||||
u'resources': {}}}
|
u'resources': {}}}
|
||||||
env = environment.Environment(new_env)
|
env = environment.Environment(new_env)
|
||||||
@@ -52,6 +54,7 @@ class EnvironmentTest(common.HeatTestCase):
|
|||||||
prev_params = {'foo': 'bar', 'tester': 'Yes'}
|
prev_params = {'foo': 'bar', 'tester': 'Yes'}
|
||||||
params = {}
|
params = {}
|
||||||
expected = {'parameters': prev_params,
|
expected = {'parameters': prev_params,
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {'resources': {}}}
|
'resource_registry': {'resources': {}}}
|
||||||
prev_env = environment.Environment(
|
prev_env = environment.Environment(
|
||||||
{'parameters': prev_params,
|
{'parameters': prev_params,
|
||||||
@@ -65,6 +68,7 @@ class EnvironmentTest(common.HeatTestCase):
|
|||||||
prev_params = {'foo': 'bar', 'tester': 'Yes'}
|
prev_params = {'foo': 'bar', 'tester': 'Yes'}
|
||||||
params = {'tester': 'patched'}
|
params = {'tester': 'patched'}
|
||||||
expected = {'parameters': {'foo': 'bar', 'tester': 'patched'},
|
expected = {'parameters': {'foo': 'bar', 'tester': 'patched'},
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {'resources': {}}}
|
'resource_registry': {'resources': {}}}
|
||||||
prev_env = environment.Environment(
|
prev_env = environment.Environment(
|
||||||
{'parameters': prev_params,
|
{'parameters': prev_params,
|
||||||
@@ -79,6 +83,7 @@ class EnvironmentTest(common.HeatTestCase):
|
|||||||
'another_tester': 'Yes'}
|
'another_tester': 'Yes'}
|
||||||
params = {'tester': 'patched'}
|
params = {'tester': 'patched'}
|
||||||
expected = {'parameters': {'foo': 'bar', 'tester': 'patched'},
|
expected = {'parameters': {'foo': 'bar', 'tester': 'patched'},
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {'resources': {}}}
|
'resource_registry': {'resources': {}}}
|
||||||
prev_env = environment.Environment(
|
prev_env = environment.Environment(
|
||||||
{'parameters': prev_params,
|
{'parameters': prev_params,
|
||||||
@@ -92,6 +97,7 @@ class EnvironmentTest(common.HeatTestCase):
|
|||||||
prev_params = {'foo': 'bar', 'tester': 'Yes'}
|
prev_params = {'foo': 'bar', 'tester': 'Yes'}
|
||||||
params = {}
|
params = {}
|
||||||
expected = {'parameters': {'foo': 'bar'},
|
expected = {'parameters': {'foo': 'bar'},
|
||||||
|
'parameter_defaults': {},
|
||||||
'resource_registry': {'resources': {}}}
|
'resource_registry': {'resources': {}}}
|
||||||
prev_env = environment.Environment(
|
prev_env = environment.Environment(
|
||||||
{'parameters': prev_params,
|
{'parameters': prev_params,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class YamlEnvironmentTest(common.HeatTestCase):
|
|||||||
yaml1 = ''
|
yaml1 = ''
|
||||||
yaml2 = '''
|
yaml2 = '''
|
||||||
parameters: {}
|
parameters: {}
|
||||||
|
parameter_defaults: {}
|
||||||
resource_registry: {}
|
resource_registry: {}
|
||||||
'''
|
'''
|
||||||
tpl1 = environment_format.parse(yaml1)
|
tpl1 = environment_format.parse(yaml1)
|
||||||
|
|||||||
@@ -392,13 +392,14 @@ params_schema = json.loads('''{
|
|||||||
|
|
||||||
class ParametersTest(testtools.TestCase):
|
class ParametersTest(testtools.TestCase):
|
||||||
def new_parameters(self, stack_name, tmpl, user_params=None,
|
def new_parameters(self, stack_name, tmpl, user_params=None,
|
||||||
stack_id=None, validate_value=True):
|
stack_id=None, validate_value=True,
|
||||||
|
param_defaults=None):
|
||||||
user_params = user_params or {}
|
user_params = user_params or {}
|
||||||
tmpl.update({'HeatTemplateFormatVersion': '2012-12-12'})
|
tmpl.update({'HeatTemplateFormatVersion': '2012-12-12'})
|
||||||
tmpl = template.Template(tmpl)
|
tmpl = template.Template(tmpl)
|
||||||
params = tmpl.parameters(
|
params = tmpl.parameters(
|
||||||
identifier.HeatIdentifier('', stack_name, stack_id),
|
identifier.HeatIdentifier('', stack_name, stack_id),
|
||||||
user_params)
|
user_params, param_defaults=param_defaults)
|
||||||
params.validate(validate_value)
|
params.validate(validate_value)
|
||||||
return params
|
return params
|
||||||
|
|
||||||
@@ -505,6 +506,21 @@ class ParametersTest(testtools.TestCase):
|
|||||||
'test',
|
'test',
|
||||||
params)
|
params)
|
||||||
|
|
||||||
|
def test_use_user_default(self):
|
||||||
|
template = {'Parameters': {'a': {'Type': 'Number', 'Default': '42'}}}
|
||||||
|
params = self.new_parameters('test_params', template,
|
||||||
|
param_defaults={'a': '77'})
|
||||||
|
|
||||||
|
self.assertEqual(77, params['a'])
|
||||||
|
|
||||||
|
def test_dont_use_user_default(self):
|
||||||
|
template = {'Parameters': {'a': {'Type': 'Number', 'Default': '42'}}}
|
||||||
|
params = self.new_parameters('test_params', template,
|
||||||
|
{'a': '111'},
|
||||||
|
param_defaults={'a': '77'})
|
||||||
|
|
||||||
|
self.assertEqual(111, params['a'])
|
||||||
|
|
||||||
|
|
||||||
class ParameterSchemaTest(testtools.TestCase):
|
class ParameterSchemaTest(testtools.TestCase):
|
||||||
|
|
||||||
|
|||||||
@@ -285,8 +285,8 @@ class RemoteStackTest(tests_common.HeatTestCase):
|
|||||||
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||||
self.assertEqual('c8a19429-7fde-47ea-a42f-40045488226c',
|
self.assertEqual('c8a19429-7fde-47ea-a42f-40045488226c',
|
||||||
rsrc.resource_id)
|
rsrc.resource_id)
|
||||||
registry = rsrc.stack.env.registry
|
env = environment.get_child_environment(rsrc.stack.env,
|
||||||
env = environment.get_custom_environment(registry, {'name': 'foo'})
|
{'name': 'foo'})
|
||||||
args = {
|
args = {
|
||||||
'stack_name': rsrc.physical_resource_name(),
|
'stack_name': rsrc.physical_resource_name(),
|
||||||
'template': template_format.parse(remote_template),
|
'template': template_format.parse(remote_template),
|
||||||
@@ -520,8 +520,8 @@ class RemoteStackTest(tests_common.HeatTestCase):
|
|||||||
|
|
||||||
self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
|
self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
|
||||||
self.assertEqual('bar', rsrc.properties.get('parameters')['name'])
|
self.assertEqual('bar', rsrc.properties.get('parameters')['name'])
|
||||||
registry = rsrc.stack.env.registry
|
env = environment.get_child_environment(rsrc.stack.env,
|
||||||
env = environment.get_custom_environment(registry, {'name': 'bar'})
|
{'name': 'bar'})
|
||||||
fields = {
|
fields = {
|
||||||
'stack_id': rsrc.resource_id,
|
'stack_id': rsrc.resource_id,
|
||||||
'template': template_format.parse(remote_template),
|
'template': template_format.parse(remote_template),
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ class StackResourceTest(common.HeatTestCase):
|
|||||||
self.stack = self.parent_resource.nested()
|
self.stack = self.parent_resource.nested()
|
||||||
self.assertEqual({"foo": "bar"}, self.stack.t.files)
|
self.assertEqual({"foo": "bar"}, self.stack.t.files)
|
||||||
|
|
||||||
@mock.patch('heat.engine.environment.get_custom_environment')
|
@mock.patch('heat.engine.environment.get_child_environment')
|
||||||
@mock.patch.object(stack_resource.parser, 'Stack')
|
@mock.patch.object(stack_resource.parser, 'Stack')
|
||||||
def test_preview_with_implemented_child_resource(self, mock_stack_class,
|
def test_preview_with_implemented_child_resource(self, mock_stack_class,
|
||||||
mock_env_class):
|
mock_env_class):
|
||||||
@@ -231,14 +231,14 @@ class StackResourceTest(common.HeatTestCase):
|
|||||||
parent_resource._validate_nested_resources = validation_mock
|
parent_resource._validate_nested_resources = validation_mock
|
||||||
|
|
||||||
result = parent_resource.preview()
|
result = parent_resource.preview()
|
||||||
mock_env_class.assert_called_once_with(self.parent_stack.env.registry,
|
mock_env_class.assert_called_once_with(self.parent_stack.env,
|
||||||
params)
|
params)
|
||||||
self.assertEqual('preview_nested_stack', result)
|
self.assertEqual('preview_nested_stack', result)
|
||||||
mock_stack_class.assert_called_once_with(
|
mock_stack_class.assert_called_once_with(
|
||||||
mock.ANY,
|
mock.ANY,
|
||||||
'test_stack-test',
|
'test_stack-test',
|
||||||
mock.ANY,
|
mock.ANY,
|
||||||
'environment',
|
env='environment',
|
||||||
timeout_mins=None,
|
timeout_mins=None,
|
||||||
disable_rollback=True,
|
disable_rollback=True,
|
||||||
parent_resource=parent_resource,
|
parent_resource=parent_resource,
|
||||||
@@ -249,7 +249,7 @@ class StackResourceTest(common.HeatTestCase):
|
|||||||
nested_depth=1
|
nested_depth=1
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock.patch('heat.engine.environment.get_custom_environment')
|
@mock.patch('heat.engine.environment.get_child_environment')
|
||||||
@mock.patch.object(stack_resource.parser, 'Stack')
|
@mock.patch.object(stack_resource.parser, 'Stack')
|
||||||
def test_preview_with_implemented_dict_child_resource(self,
|
def test_preview_with_implemented_dict_child_resource(self,
|
||||||
mock_stack_class,
|
mock_stack_class,
|
||||||
@@ -271,14 +271,14 @@ class StackResourceTest(common.HeatTestCase):
|
|||||||
parent_resource._validate_nested_resources = validation_mock
|
parent_resource._validate_nested_resources = validation_mock
|
||||||
|
|
||||||
result = parent_resource.preview()
|
result = parent_resource.preview()
|
||||||
mock_env_class.assert_called_once_with(self.parent_stack.env.registry,
|
mock_env_class.assert_called_once_with(self.parent_stack.env,
|
||||||
params)
|
params)
|
||||||
self.assertEqual('preview_nested_stack', result)
|
self.assertEqual('preview_nested_stack', result)
|
||||||
mock_stack_class.assert_called_once_with(
|
mock_stack_class.assert_called_once_with(
|
||||||
mock.ANY,
|
mock.ANY,
|
||||||
'test_stack-test',
|
'test_stack-test',
|
||||||
mock.ANY,
|
mock.ANY,
|
||||||
'environment',
|
env='environment',
|
||||||
timeout_mins=None,
|
timeout_mins=None,
|
||||||
disable_rollback=True,
|
disable_rollback=True,
|
||||||
parent_resource=parent_resource,
|
parent_resource=parent_resource,
|
||||||
@@ -810,7 +810,7 @@ class StackResourceTest(common.HeatTestCase):
|
|||||||
environment.Environment().AndReturn(env)
|
environment.Environment().AndReturn(env)
|
||||||
|
|
||||||
self.m.StubOutWithMock(parser, 'Stack')
|
self.m.StubOutWithMock(parser, 'Stack')
|
||||||
parser.Stack(ctx, phy_id, templ, env, timeout_mins=None,
|
parser.Stack(ctx, phy_id, templ, env=env, timeout_mins=None,
|
||||||
disable_rollback=True,
|
disable_rollback=True,
|
||||||
parent_resource=self.parent_resource,
|
parent_resource=self.parent_resource,
|
||||||
owner_id=self.parent_stack.id,
|
owner_id=self.parent_stack.id,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import random
|
|||||||
import re
|
import re
|
||||||
import six
|
import six
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import testscenarios
|
||||||
import testtools
|
import testtools
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -63,7 +64,8 @@ def rand_name(name=''):
|
|||||||
return randbits
|
return randbits
|
||||||
|
|
||||||
|
|
||||||
class HeatIntegrationTest(testtools.TestCase):
|
class HeatIntegrationTest(testscenarios.WithScenarios,
|
||||||
|
testtools.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(HeatIntegrationTest, self).setUp()
|
super(HeatIntegrationTest, self).setUp()
|
||||||
|
|||||||
107
heat_integrationtests/functional/test_default_parameters.py
Normal file
107
heat_integrationtests/functional/test_default_parameters.py
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from heat_integrationtests.common import test
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultParametersTest(test.HeatIntegrationTest):
|
||||||
|
|
||||||
|
template = '''
|
||||||
|
heat_template_version: 2013-05-23
|
||||||
|
parameters:
|
||||||
|
length:
|
||||||
|
type: string
|
||||||
|
default: 40
|
||||||
|
resources:
|
||||||
|
random1:
|
||||||
|
type: nested_random.yaml
|
||||||
|
random2:
|
||||||
|
type: OS::Heat::RandomString
|
||||||
|
properties:
|
||||||
|
length: {get_param: length}
|
||||||
|
outputs:
|
||||||
|
random1:
|
||||||
|
value: {get_attr: [random1, random1_value]}
|
||||||
|
random2:
|
||||||
|
value: {get_resource: random2}
|
||||||
|
'''
|
||||||
|
nested_template = '''
|
||||||
|
heat_template_version: 2013-05-23
|
||||||
|
parameters:
|
||||||
|
length:
|
||||||
|
type: string
|
||||||
|
default: 50
|
||||||
|
resources:
|
||||||
|
random1:
|
||||||
|
type: OS::Heat::RandomString
|
||||||
|
properties:
|
||||||
|
length: {get_param: length}
|
||||||
|
outputs:
|
||||||
|
random1_value:
|
||||||
|
value: {get_resource: random1}
|
||||||
|
'''
|
||||||
|
|
||||||
|
scenarios = [
|
||||||
|
('none', dict(param=None, default=None, temp_def=True,
|
||||||
|
expect1=50, expect2=40)),
|
||||||
|
('default', dict(param=None, default=12, temp_def=True,
|
||||||
|
expect1=12, expect2=12)),
|
||||||
|
('both', dict(param=15, default=12, temp_def=True,
|
||||||
|
expect1=12, expect2=15)),
|
||||||
|
('no_temp_default', dict(param=None, default=12, temp_def=False,
|
||||||
|
expect1=12, expect2=12)),
|
||||||
|
]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(DefaultParametersTest, self).setUp()
|
||||||
|
self.client = self.orchestration_client
|
||||||
|
|
||||||
|
def test_defaults(self):
|
||||||
|
stack_name = self._stack_rand_name()
|
||||||
|
|
||||||
|
env = {'parameters': {}, 'parameter_defaults': {}}
|
||||||
|
if self.param:
|
||||||
|
env['parameters'] = {'length': self.param}
|
||||||
|
if self.default:
|
||||||
|
env['parameter_defaults'] = {'length': self.default}
|
||||||
|
|
||||||
|
if not self.temp_def:
|
||||||
|
# remove the default from the parameter in the nested template.
|
||||||
|
ntempl = yaml.load(self.nested_template)
|
||||||
|
del ntempl['parameters']['length']['default']
|
||||||
|
nested_template = yaml.dump(ntempl)
|
||||||
|
else:
|
||||||
|
nested_template = self.nested_template
|
||||||
|
|
||||||
|
self.client.stacks.create(
|
||||||
|
stack_name=stack_name,
|
||||||
|
template=self.template,
|
||||||
|
files={'nested_random.yaml': nested_template},
|
||||||
|
disable_rollback=True,
|
||||||
|
parameters={},
|
||||||
|
environment=env
|
||||||
|
)
|
||||||
|
self.addCleanup(self.client.stacks.delete, stack_name)
|
||||||
|
|
||||||
|
stack = self.client.stacks.get(stack_name)
|
||||||
|
stack_identifier = '%s/%s' % (stack_name, stack.id)
|
||||||
|
|
||||||
|
self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
|
||||||
|
|
||||||
|
stack = self.client.stacks.get(stack_name)
|
||||||
|
for out in stack.outputs:
|
||||||
|
if out['output_key'] == 'random1':
|
||||||
|
self.assertEqual(self.expect1, len(out['output_value']))
|
||||||
|
if out['output_key'] == 'random2':
|
||||||
|
self.assertEqual(self.expect2, len(out['output_value']))
|
||||||
Reference in New Issue
Block a user