Added tags attribute to the template parameter

In some scenarios, it is required to categorize the parameter.
Associating tags with the parameter, it is will be easy to
categorize the parameter and add simple validations to users.
This patch introduces a new attribute 'tags' with the parameters,
which is a list of strings.

Change-Id: I20fc95d606b0b8a08d3b46bf33f4860bff49c74f
This commit is contained in:
Saravanan KR 2017-09-21 17:03:47 +05:30
parent 554add6004
commit a1a0609e8e
8 changed files with 154 additions and 21 deletions

View File

@ -437,6 +437,7 @@ default value defined as nested elements.
constraints:
<parameter constraints>
immutable: <true | false>
tags: <list of parameter categories>
param name
The name of the parameter.
@ -478,6 +479,11 @@ immutable
set to ``true`` and the parameter value is changed.
This attribute is optional and defaults to ``false``.
tags
A list of strings to specify the category of a parameter. This value is
used to categorize a parameter so that users can group the parameters.
This attribute is optional.
The table below describes all currently supported types with examples:
+----------------------+-------------------------------+------------------+

View File

@ -524,6 +524,9 @@ def format_validate_parameter(param):
if param.user_value:
res[rpc_api.PARAM_VALUE] = param.user_value
if param.tags():
res[rpc_api.PARAM_TAG] = param.tags()
_build_parameter_constraints(res, param)
return res

View File

@ -79,6 +79,22 @@ class HOTParamSchema(parameters.Schema):
raise exception.InvalidSchemaError(
message=_("No constraint expressed"))
@classmethod
def _constraints(cls, param_name, schema_dict):
constraints = schema_dict.get(cls.CONSTRAINTS)
if constraints is None:
return
if not isinstance(constraints, list):
raise exception.InvalidSchemaError(
message=_("Invalid parameter constraints for parameter "
"%s, expected a list") % param_name)
for constraint in constraints:
cls._check_dict(constraint, PARAM_CONSTRAINTS,
'parameter constraints')
yield cls._constraint_from_def(constraint)
@classmethod
def from_dict(cls, param_name, schema_dict):
"""Return a Parameter Schema object from a legacy schema dictionary.
@ -89,27 +105,12 @@ class HOTParamSchema(parameters.Schema):
"""
cls._validate_dict(param_name, schema_dict)
def constraints():
constraints = schema_dict.get(cls.CONSTRAINTS)
if constraints is None:
return
if not isinstance(constraints, list):
raise exception.InvalidSchemaError(
message=_("Invalid parameter constraints for parameter "
"%s, expected a list") % param_name)
for constraint in constraints:
cls._check_dict(constraint, PARAM_CONSTRAINTS,
'parameter constraints')
yield cls._constraint_from_def(constraint)
# make update_allowed true by default on TemplateResources
# as the template should deal with this.
return cls(schema_dict[cls.TYPE],
description=schema_dict.get(HOTParamSchema.DESCRIPTION),
default=schema_dict.get(HOTParamSchema.DEFAULT),
constraints=list(constraints()),
constraints=list(cls._constraints(param_name, schema_dict)),
hidden=schema_dict.get(HOTParamSchema.HIDDEN, False),
label=schema_dict.get(HOTParamSchema.LABEL),
immutable=schema_dict.get(HOTParamSchema.IMMUTABLE, False))
@ -131,6 +132,35 @@ class HOTParamSchema20170224(HOTParamSchema):
constraint)
class HOTParamSchema20180302(HOTParamSchema20170224):
KEYS_20180302 = (TAGS,) = ('tags',)
KEYS = HOTParamSchema20170224.KEYS + KEYS_20180302
PARAMETER_KEYS = KEYS
@classmethod
def from_dict(cls, param_name, schema_dict):
"""Return a Parameter Schema object from a legacy schema dictionary.
:param param_name: name of the parameter owning the schema; used
for more verbose logging
:type param_name: str
"""
cls._validate_dict(param_name, schema_dict)
# make update_allowed true by default on TemplateResources
# as the template should deal with this.
return cls(schema_dict[cls.TYPE],
description=schema_dict.get(HOTParamSchema.DESCRIPTION),
default=schema_dict.get(HOTParamSchema.DEFAULT),
constraints=list(cls._constraints(param_name, schema_dict)),
hidden=schema_dict.get(HOTParamSchema.HIDDEN, False),
label=schema_dict.get(HOTParamSchema.LABEL),
immutable=schema_dict.get(HOTParamSchema.IMMUTABLE, False),
tags=schema_dict.get(HOTParamSchema20180302.TAGS))
class HOTParameters(parameters.Parameters):
PSEUDO_PARAMETERS = (
PARAM_STACK_ID, PARAM_STACK_NAME, PARAM_REGION, PARAM_PROJECT_ID

View File

@ -695,3 +695,5 @@ class HOTemplate20180302(HOTemplate20170901):
'yaql': hot_funcs.Yaql,
'contains': hot_funcs.Contains
}
param_schema_class = parameters.HOTParamSchema20180302

View File

@ -42,10 +42,10 @@ class Schema(constr.Schema):
KEYS = (
TYPE, DESCRIPTION, DEFAULT, SCHEMA, CONSTRAINTS, HIDDEN,
LABEL, IMMUTABLE
LABEL, IMMUTABLE, TAGS,
) = (
'Type', 'Description', 'Default', 'Schema', 'Constraints', 'NoEcho',
'Label', 'Immutable'
'Label', 'Immutable', 'Tags',
)
PARAMETER_KEYS = PARAMETER_KEYS
@ -59,7 +59,8 @@ class Schema(constr.Schema):
)
def __init__(self, data_type, description=None, default=None, schema=None,
constraints=None, hidden=False, label=None, immutable=False):
constraints=None, hidden=False, label=None, immutable=False,
tags=None):
super(Schema, self).__init__(data_type=data_type,
description=description,
default=default,
@ -69,6 +70,7 @@ class Schema(constr.Schema):
label=label,
immutable=immutable)
self.hidden = hidden
self.tags = tags
# Schema class validates default value for lists assuming list type. For
# comma delimited list string supported in parameters Schema class, the
@ -129,6 +131,11 @@ class Schema(constr.Schema):
message=_("Missing parameter type for parameter: %s") %
param_name)
if not isinstance(schema_dict.get(cls.TAGS, []), list):
raise exception.InvalidSchemaError(
message=_("Tags property should be a list for parameter: %s") %
param_name)
@classmethod
def from_dict(cls, param_name, schema_dict):
"""Return a Parameter Schema object from a legacy schema dictionary.
@ -276,6 +283,10 @@ class Parameter(object):
"""Return the label or param name."""
return self.schema.label or self.name
def tags(self):
"""Return the tags associated with the parameter"""
return self.schema.tags or []
def has_default(self):
"""Return whether the parameter has a default value."""
return (self.schema.default is not None or

View File

@ -193,13 +193,13 @@ VALIDATE_PARAM_KEYS = (
PARAM_MIN_LENGTH, PARAM_MAX_VALUE, PARAM_MIN_VALUE,
PARAM_STEP, PARAM_OFFSET,
PARAM_DESCRIPTION, PARAM_CONSTRAINT_DESCRIPTION, PARAM_LABEL,
PARAM_CUSTOM_CONSTRAINT, PARAM_VALUE
PARAM_CUSTOM_CONSTRAINT, PARAM_VALUE, PARAM_TAG
) = (
'Type', 'Default', 'NoEcho',
'AllowedValues', 'AllowedPattern', 'MaxLength',
'MinLength', 'MaxValue', 'MinValue', 'Step', 'Offset',
'Description', 'ConstraintDescription', 'Label',
'CustomConstraint', 'Value'
'CustomConstraint', 'Value', 'Tags'
)
VALIDATE_PARAM_TYPES = (

View File

@ -924,6 +924,46 @@ resources:
external_id: foobar
'''
test_template_hot_parameter_tags_older = '''
heat_template_version: 2013-05-23
parameters:
KeyName:
type: string
description: Name of an existing key pair to use for the instance
label: Nova KeyPair Name
tags:
- feature1
- feature2
'''
test_template_hot_parameter_tags_pass = '''
heat_template_version: 2018-03-02
parameters:
KeyName:
type: string
description: Name of an existing key pair to use for the instance
label: Nova KeyPair Name
tags:
- feature1
- feature2
'''
test_template_hot_parameter_tags_fail = '''
heat_template_version: 2018-03-02
parameters:
KeyName:
type: string
description: Name of an existing key pair to use for the instance
label: Nova KeyPair Name
tags: feature
'''
class ValidateTest(common.HeatTestCase):
def setUp(self):
@ -1859,3 +1899,39 @@ parameter_groups:
self.ctx, t, {})
self.assertEqual(dependencies.CircularDependencyException,
exc.exc_info[0])
def test_validate_hot_parameter_tags_older(self):
t = template_format.parse(test_template_hot_parameter_tags_older)
exc = self.assertRaises(dispatcher.ExpectedException,
self.engine.validate_template,
self.ctx, t, {})
self.assertEqual(exception.InvalidSchemaError,
exc.exc_info[0])
def test_validate_hot_parameter_tags_pass(self):
t = template_format.parse(test_template_hot_parameter_tags_pass)
res = dict(self.engine.validate_template(self.ctx, t, {}))
parameters = res['Parameters']
expected = {'KeyName': {
'Description': 'Name of an existing key pair to use for the '
'instance',
'NoEcho': 'false',
'Label': 'Nova KeyPair Name',
'Type': 'String',
'Tags': [
'feature1',
'feature2'
]}}
self.assertEqual(expected, parameters)
def test_validate_hot_parameter_tags_fail(self):
t = template_format.parse(test_template_hot_parameter_tags_fail)
exc = self.assertRaises(dispatcher.ExpectedException,
self.engine.validate_template,
self.ctx, t, {})
self.assertEqual(exception.InvalidSchemaError,
exc.exc_info[0])

View File

@ -0,0 +1,5 @@
---
features:
- |
Added a new schema property tags, to parameters, to categorize
parameters based on features.