Use a HeatIdentifier instance to create Parameters

This is the first commit in order to implement native pseudo parameters
for HOT templates.

Now to create a Parameters instance, a HeatIdentifier is used instead
of two variables (stack_name and stack_id)

Change-Id: Ifc914f8f6c943da73da5984452d424cf180b91e7
Implements: blueprint native-pseudo-params
This commit is contained in:
Pablo Andres Fuente 2014-01-21 17:18:21 -03:00
parent 0fe67485f9
commit 99697aa0a9
14 changed files with 91 additions and 66 deletions

View File

@ -102,7 +102,7 @@ class RackspaceDnsTest(common.HeatTestCase):
stack_name = '%s_stack' % name
t = parsed_t
template = parser.Template(t)
stack = parser.Stack(None,
stack = parser.Stack(utils.dummy_context(),
stack_name,
template,
environment.Environment({'name': 'test'}),

View File

@ -329,17 +329,22 @@ class Parameters(collections.Mapping):
The parameters of a stack, with type checking, defaults &c. specified by
the stack's template.
'''
def __init__(self, stack_name, tmpl, user_params={}, stack_id=None,
def __init__(self, stack_identifier, tmpl, user_params={},
validate_value=True):
'''
Create the parameter container for a stack from the stack name and
template, optionally setting the user-supplied parameter values.
'''
def parameters():
stack_id = stack_identifier.arn() \
if stack_identifier is not None else 'None'
stack_name = stack_identifier and stack_identifier.stack_name
yield Parameter(PARAM_STACK_ID,
Schema(Schema.STRING, _('Stack ID'),
default=str(stack_id)))
if stack_name is not None:
if stack_name:
yield Parameter(PARAM_STACK_NAME,
Schema(Schema.STRING, _('Stack Name'),
default=stack_name))
@ -390,11 +395,14 @@ class Parameters(collections.Mapping):
return dict((n, func(p))
for n, p in self.params.iteritems() if filter_func(p))
def set_stack_id(self, stack_id):
def set_stack_id(self, stack_identifier):
'''
Set the AWS::StackId pseudo parameter value
Set the StackId pseudo parameter value
'''
self.params[PARAM_STACK_ID].schema.set_default(stack_id)
if stack_identifier is not None:
self.params[PARAM_STACK_ID].schema.set_default(
stack_identifier.arn())
return True
def _validate(self, user_params):
schemata = self.tmpl.param_schemata()

View File

@ -32,7 +32,6 @@ from heat.engine import template
from heat.engine import timestamp
from heat.engine import update
from heat.engine.notification import stack as notification
from heat.engine.parameters import Parameters
from heat.engine.template import Template
from heat.engine.clients import Clients
from heat.db import api as db_api
@ -45,8 +44,6 @@ from heat.common.exception import StackValidationFailed
logger = logging.getLogger(__name__)
(PARAM_STACK_NAME, PARAM_REGION) = ('AWS::StackName', 'AWS::Region')
class Stack(collections.Mapping):
@ -104,8 +101,8 @@ class Stack(collections.Mapping):
resources.initialise()
self.env = env or environment.Environment({})
self.parameters = Parameters(self.name, self.t,
user_params=self.env.params)
self.parameters = self.t.parameters(self.identifier(),
user_params=self.env.params)
self._set_param_stackid()
@ -160,16 +157,10 @@ class Stack(collections.Mapping):
def _set_param_stackid(self):
'''
Update self.parameters with the current ARN which is then provided
via the Parameters class as the AWS::StackId pseudo parameter
via the Parameters class as the StackId pseudo parameter
'''
# This can fail if constructor called without a valid context,
# as it is in many tests
try:
stack_arn = self.identifier().arn()
except (AttributeError, ValueError, TypeError):
if not self.parameters.set_stack_id(self.identifier()):
logger.warning(_("Unable to set parameters StackId identifier"))
else:
self.parameters.set_stack_id(stack_arn)
@staticmethod
def _get_dependencies(resources):
@ -744,9 +735,12 @@ def resolve_static_data(template, stack, parameters, snippet):
Example:
>>> from heat.common import template_format
>>> from heat.common import identifier
>>> template_str = '# JSON or YAML encoded template'
>>> template = Template(template_format.parse(template_str))
>>> parameters = Parameters('stack', template, {'KeyName': 'my_key'})
>>> parameters = template.parameters(
... identifier.HeatIdentifier('tenant_id', 'stack', 'stack_id'),
... {}, {'KeyName': 'my_key'})
>>> resolve_static_data(template, None, parameters, {'Ref': 'KeyName'})
'my_key'
'''

View File

@ -463,7 +463,7 @@ class Resource(object):
logger.info('creating %s' % str(self))
# Re-resolve the template, since if the resource Ref's
# the AWS::StackId pseudo parameter, it will change after
# the StackId pseudo parameter, it will change after
# the parser.Stack is stored (which is after the resources
# are __init__'d, but before they are create()'d)
self.t = self.stack.resolve_static_data(self.json_snippet)

View File

@ -443,7 +443,7 @@ class EngineService(service.Service):
env = environment.Environment(params)
updated_stack = parser.Stack(cnxt, stack_name, tmpl,
env, **common_params)
updated_stack.parameters.set_stack_id(current_stack.identifier().arn())
updated_stack.parameters.set_stack_id(current_stack.identifier())
self._validate_deferred_auth_context(cnxt, updated_stack)
updated_stack.validate()
@ -504,7 +504,7 @@ class EngineService(service.Service):
except Exception as ex:
return {'Error': str(ex)}
tmpl_params = parser.Parameters(None, tmpl, validate_value=False)
tmpl_params = tmpl.parameters(None, {}, validate_value=False)
is_real_param = lambda p: p.name not in parameters.PSEUDO_PARAMETERS
params = tmpl_params.map(api.format_validate_parameter, is_real_param)

View File

@ -154,7 +154,7 @@ class StackResource(resource.Resource):
disable_rollback=True,
parent_resource=self,
owner_id=self.stack.id)
stack.parameters.set_stack_id(nested_stack.identifier().arn())
stack.parameters.set_stack_id(nested_stack.identifier())
stack.validate()
if not hasattr(type(self), 'attributes_schema'):

View File

@ -476,6 +476,11 @@ class Template(collections.Mapping):
return dict((name, parameters.Schema.from_dict(schema))
for name, schema in params)
def parameters(self, stack_identifier, user_params, validate_value=True):
return parameters.Parameters(stack_identifier, self,
user_params=user_params,
validate_value=validate_value)
def _resolve(match, handle, snippet, transform=None):
'''

View File

@ -18,6 +18,7 @@ import heat.engine.api as api
from heat.common import template_format
from heat.engine import parser
from heat.engine import parameters
from heat.engine import resource
from heat.engine.event import Event
from heat.common.identifier import EventIdentifier
@ -628,7 +629,7 @@ class FormatValidateParameterTest(HeatTestCase):
t = template_format.parse(self.template % self.param)
tmpl = parser.Template(t)
tmpl_params = parser.Parameters(None, tmpl, validate_value=False)
tmpl_params = parameters.Parameters(None, tmpl, validate_value=False)
param = tmpl_params.params[self.param_name]
param_formated = api.format_validate_parameter(param)
self.assertEqual(self.expected, param_formated)

View File

@ -13,9 +13,9 @@
# under the License.
from heat.common import template_format
from heat.common import exception
from heat.common import identifier
from heat.engine import parser
from heat.engine import hot
from heat.engine import parameters
from heat.engine import template
from heat.engine import constraints
@ -331,7 +331,9 @@ class HOTParamValidatorTest(HeatTestCase):
tmpl = parser.Template(hot_tpl)
def run_parameters(value):
parameters.Parameters("stack_testit", tmpl, {'db_name': value})
tmpl.parameters(
identifier.HeatIdentifier('', "stack_testit", None),
{'db_name': value})
return True
value = 'wp'

View File

@ -21,7 +21,7 @@ from heat.engine import parser
from heat.engine import scheduler
from heat.engine.resources import os_database
from heat.tests.common import HeatTestCase
from heat.tests.utils import setup_dummy_db
from heat.tests import utils
wp_template = '''
@ -90,13 +90,13 @@ class OSDBInstanceTest(HeatTestCase):
def setUp(self):
super(OSDBInstanceTest, self).setUp()
self.fc = self.m.CreateMockAnything()
setup_dummy_db()
utils.setup_dummy_db()
def _setup_test_clouddbinstance(self, name, parsed_t):
stack_name = '%s_stack' % name
t = parsed_t
template = parser.Template(t)
stack = parser.Stack(None,
stack = parser.Stack(utils.dummy_context(),
stack_name,
template,
environment.Environment({'name': 'test'}),

View File

@ -17,6 +17,7 @@ import testtools
import json
from heat.common import exception
from heat.common import identifier
from heat.engine import parameters
from heat.engine import template
from heat.engine import constraints as constr
@ -315,23 +316,32 @@ class ParametersTest(testtools.TestCase):
def new_parameters(self, stack_name, tmpl, user_params={}, stack_id=None,
validate_value=True):
tmpl = template.Template(tmpl)
return parameters.Parameters(stack_name, tmpl, user_params, stack_id,
validate_value)
return tmpl.parameters(
identifier.HeatIdentifier('', stack_name, stack_id),
user_params, validate_value)
def test_pseudo_params(self):
params = self.new_parameters('test_stack', {"Parameters": {}})
stack_name = 'test_stack'
params = self.new_parameters(stack_name, {"Parameters": {}})
self.assertEqual('test_stack', params['AWS::StackName'])
self.assertEqual('None', params['AWS::StackId'])
self.assertEqual(
'arn:openstack:heat:::stacks/{0}/{1}'.format(stack_name, 'None'),
params['AWS::StackId'])
self.assertIn('AWS::Region', params)
def test_pseudo_param_stackid(self):
params = self.new_parameters('test_stack', {'Parameters': {}},
stack_id='123::foo')
stack_name = 'test_stack'
params = self.new_parameters(stack_name, {'Parameters': {}},
stack_id='abc123')
self.assertEqual('123::foo', params['AWS::StackId'])
params.set_stack_id('456::bar')
self.assertEqual('456::bar', params['AWS::StackId'])
self.assertEqual(
'arn:openstack:heat:::stacks/{0}/{1}'.format(stack_name, 'abc123'),
params['AWS::StackId'])
stack_identifier = identifier.HeatIdentifier('', '', 'def456')
params.set_stack_id(stack_identifier)
self.assertEqual(stack_identifier.arn(), params['AWS::StackId'])
def test_schema_invariance(self):
params1 = self.new_parameters('test', params_schema,
@ -369,13 +379,17 @@ class ParametersTest(testtools.TestCase):
def test_map_str(self):
template = {'Parameters': {'Foo': {'Type': 'String'},
'Bar': {'Type': 'Number'}}}
params = self.new_parameters('test_params', template,
stack_name = 'test_params'
params = self.new_parameters(stack_name, template,
{'Foo': 'foo', 'Bar': '42'})
expected = {'Foo': 'foo',
'Bar': '42',
'AWS::Region': 'ap-southeast-1',
'AWS::StackId': 'None',
'AWS::StackId':
'arn:openstack:heat:::stacks/{0}/{1}'.format(
stack_name,
'None'),
'AWS::StackName': 'test_params'}
self.assertEqual(expected, params.map(str))

View File

@ -21,12 +21,12 @@ from oslo.config import cfg
from heat.engine import environment
from heat.common import exception
from heat.common import identifier
from heat.common import template_format
from heat.common import urlfetch
from heat.engine import clients
from heat.engine import resource
from heat.engine import parser
from heat.engine import parameters
from heat.engine import scheduler
from heat.engine import template
@ -194,7 +194,8 @@ Mappings:
def test_param_ref_missing(self):
tmpl = {'Parameters': {'foo': {'Type': 'String', 'Required': True}}}
tmpl = parser.Template(tmpl)
params = parameters.Parameters('test', tmpl, validate_value=False)
params = tmpl.parameters(identifier.HeatIdentifier('', 'test', None),
{}, validate_value=False)
snippet = {"Ref": "foo"}
self.assertRaises(exception.UserParameterMissing,
parser.Template.resolve_param_refs,

View File

@ -394,8 +394,8 @@ class ProviderTemplateTest(HeatTestCase):
"LinuxDistribution": "U10"
}
}
stack = parser.Stack(None, 'test_stack', parser.Template({}),
stack_id=str(uuid.uuid4()))
stack = parser.Stack(utils.dummy_context(), 'test_stack',
parser.Template({}), stack_id=str(uuid.uuid4()))
templ_resource = resource.Resource("test_templ_resource", json_snippet,
stack)
self.m.VerifyAll()

View File

@ -757,7 +757,7 @@ class ResourceDependenciesTest(HeatTestCase):
'foo': {'Type': 'GenericResourceType'},
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['foo']
res.add_dependencies(self.deps)
@ -777,7 +777,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['bar']
res.add_dependencies(self.deps)
@ -800,7 +800,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['bar']
res.add_dependencies(self.deps)
@ -821,7 +821,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['bar']
res.add_dependencies(self.deps)
@ -843,7 +843,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['bar']
res.add_dependencies(self.deps)
@ -866,7 +866,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['bar']
res.add_dependencies(self.deps)
@ -890,7 +890,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['bar']
res.add_dependencies(self.deps)
@ -911,7 +911,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
ex = self.assertRaises(exception.InvalidTemplateReference,
getattr, stack, 'dependencies')
self.assertIn('"baz" (in bar.Properties.Foo)', str(ex))
@ -929,7 +929,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
ex = self.assertRaises(exception.InvalidTemplateReference,
getattr, stack, 'dependencies')
self.assertIn('"baz" (in bar.Properties.Foo)', str(ex))
@ -946,7 +946,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['bar']
res.add_dependencies(self.deps)
@ -968,7 +968,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['bar']
res.add_dependencies(self.deps)
@ -989,7 +989,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['bar']
res.add_dependencies(self.deps)
@ -1011,7 +1011,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['bar']
res.add_dependencies(self.deps)
@ -1035,7 +1035,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['bar']
res.add_dependencies(self.deps)
@ -1060,7 +1060,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['bar']
res.add_dependencies(self.deps)
@ -1081,7 +1081,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
ex = self.assertRaises(exception.InvalidTemplateReference,
getattr, stack, 'dependencies')
self.assertIn('"baz" (in bar.Properties.Foo)', str(ex))
@ -1099,7 +1099,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
ex = self.assertRaises(exception.InvalidTemplateReference,
getattr, stack, 'dependencies')
self.assertIn('"baz" (in bar.Properties.Foo)', str(ex))
@ -1121,7 +1121,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
ex = self.assertRaises(exception.InvalidTemplateReference,
getattr, stack, 'dependencies')
self.assertIn('"baz" (in bar.Properties.Foo.Fn::Join[1][3])', str(ex))
@ -1144,7 +1144,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
ex = self.assertRaises(exception.InvalidTemplateReference,
getattr, stack, 'dependencies')
self.assertIn('"baz" (in bar.Properties.Foo.Fn::Join[1][3])', str(ex))
@ -1159,7 +1159,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
res = stack['bar']
res.add_dependencies(self.deps)
@ -1177,7 +1177,7 @@ class ResourceDependenciesTest(HeatTestCase):
}
}
})
stack = parser.Stack(None, 'test', tmpl)
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
ex = self.assertRaises(exception.InvalidTemplateReference,
getattr, stack, 'dependencies')
self.assertIn('"wibble" (in foo)', str(ex))