Repository: incubator-ariatosca Updated Branches: refs/heads/ARIA-313-fix-handling-the-required-field-of-inputs [created] fd380f448
ARIA-313 Fix handling the `required` field of inputs I split the logic of merging provided and declared input values into three steps: 1. Validate that no undeclared inputs were provided. 2. Validate that all required inputs were provided with a value. 3. The actual merging process, which includes type checking. Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/fd380f44 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/fd380f44 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/fd380f44 Branch: refs/heads/ARIA-313-fix-handling-the-required-field-of-inputs Commit: fd380f44888aa2b18209a831d0855547ba1634bb Parents: c2b8e65 Author: Avia Efrat <[email protected]> Authored: Wed Jul 26 15:11:21 2017 +0300 Committer: Avia Efrat <[email protected]> Committed: Wed Jul 26 15:26:01 2017 +0300 ---------------------------------------------------------------------- aria/modeling/exceptions.py | 4 +- aria/modeling/service_common.py | 13 +++ aria/modeling/service_instance.py | 2 +- aria/modeling/service_template.py | 5 + aria/modeling/utils.py | 83 +++++++-------- aria/orchestrator/workflow_runner.py | 4 + aria/orchestrator/workflows/api/task.py | 5 + aria/parser/consumption/style.py | 5 + aria/parser/presentation/presentation.py | 5 +- .../webserver-dbms-2/webserver-dbms-2.yaml | 2 +- .../simple_v1_0/modeling/__init__.py | 101 ++++++++++--------- .../simple_v1_0/modeling/data_types.py | 5 +- .../simple_v1_0/modeling/interfaces.py | 8 +- .../simple_v1_0/modeling/parameters.py | 3 +- tests/orchestrator/test_workflow_runner.py | 6 +- 15 files changed, 147 insertions(+), 104 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/aria/modeling/exceptions.py ---------------------------------------------------------------------- diff --git a/aria/modeling/exceptions.py b/aria/modeling/exceptions.py index 573efaf..cddc049 100644 --- a/aria/modeling/exceptions.py +++ b/aria/modeling/exceptions.py @@ -45,7 +45,7 @@ class CannotEvaluateFunctionException(ModelingException): """ -class MissingRequiredParametersException(ParameterException): +class MissingRequiredInputsException(ParameterException): """ ARIA modeling exception: Required parameters have been omitted. """ @@ -57,7 +57,7 @@ class ParametersOfWrongTypeException(ParameterException): """ -class UndeclaredParametersException(ParameterException): +class UndeclaredInputsException(ParameterException): """ ARIA modeling exception: Undeclared parameters have been provided. """ http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/aria/modeling/service_common.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py index b533a88..3d7b4de 100644 --- a/aria/modeling/service_common.py +++ b/aria/modeling/service_common.py @@ -22,6 +22,7 @@ ARIA modeling service common module from sqlalchemy import ( Column, Text, + Boolean ) from sqlalchemy.ext.declarative import declared_attr @@ -84,6 +85,18 @@ class InputBase(ParameterMixin): __tablename__ = 'input' + required = Column(Boolean, doc=""" + Is the input mandatory. + + :type: :obj:`bool` + """) + + @classmethod + def wrap(cls, name, value, description=None, required=True): + input = super(InputBase, cls).wrap(name, value, description) + input.required = required + return input + # region many_to_one relationships @declared_attr http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/aria/modeling/service_instance.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py index 889465c..ae6a0a0 100644 --- a/aria/modeling/service_instance.py +++ b/aria/modeling/service_instance.py @@ -1939,7 +1939,7 @@ class OperationBase(InstanceModelMixin): """) retry_interval = Column(Integer, doc=""" - Interval between task retry attemps (in seconds). + Interval between task retry attempts (in seconds). :type: :obj:`float` """) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/aria/modeling/service_template.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py index 22912e2..5819e11 100644 --- a/aria/modeling/service_template.py +++ b/aria/modeling/service_template.py @@ -343,6 +343,11 @@ class ServiceTemplateBase(TemplateModelMixin): context = ConsumptionContext.get_thread_local() context.modeling.instance = service + utils.validate_no_undeclared_inputs(declared_inputs=self.inputs, + supplied_inputs=inputs) + utils.validate_required_inputs_are_supplied(declared_inputs=self.inputs, + supplied_inputs=inputs) + service.inputs = utils.merge_parameter_values(inputs, self.inputs, model_cls=models.Input) # TODO: now that we have inputs, we should scan properties and inputs and evaluate functions http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/aria/modeling/utils.py ---------------------------------------------------------------------- diff --git a/aria/modeling/utils.py b/aria/modeling/utils.py index e0fd11b..8e0b0d5 100644 --- a/aria/modeling/utils.py +++ b/aria/modeling/utils.py @@ -64,81 +64,84 @@ class NodeTemplateContainerHolder(object): return self.container.service_template -def merge_parameter_values(parameter_values, declared_parameters, model_cls): +def validate_no_undeclared_inputs(declared_inputs, supplied_inputs): + + undeclared_inputs = [input for input in supplied_inputs if input not in declared_inputs] + if undeclared_inputs: + raise exceptions.UndeclaredInputsException( + 'Undeclared inputs have been provided: {0}; Declared inputs: {1}' + .format(string_list_as_string(list(undeclared_inputs)), + string_list_as_string(declared_inputs.keys()))) + + +def validate_required_inputs_are_supplied(declared_inputs, supplied_inputs): + required_inputs = [input for input in declared_inputs.values() if input.required] + missing_required_inputs = [input for input in required_inputs + if input.name not in supplied_inputs and not input.value] + if missing_required_inputs: + raise exceptions.MissingRequiredInputsException( + 'Required inputs {0} have not been provided values' + .format(string_list_as_string(missing_required_inputs))) + + +def merge_parameter_values(provided_values, declared_parameters, model_cls): """ Merges parameter values according to those declared by a type. Exceptions will be raised for validation errors. - :param parameter_values: provided parameter values or None - :type parameter_values: {:obj:`basestring`: object} - :param declared_parameters: declared parameters + :param provided_values: provided parameter values or None + :type provided_values: {:obj:`basestring`: object} + :param declared_parameters: declared code_parameters :type declared_parameters: {:obj:`basestring`: :class:`~aria.modeling.models.Parameter`} - :return: the merged parameters + :param model_cls: the model class that should be created from a provided value + :type model_cls: :class:`~aria.modeling.models.Input` or :class:`~aria.modeling.models.Argument` + :return: the merged code_parameters :rtype: {:obj:`basestring`: :class:`~aria.modeling.models.Parameter`} - :raises ~aria.modeling.exceptions.UndeclaredParametersException: if a key in + :raises ~aria.modeling.exceptions.UndeclaredInputsException: if a key in ``parameter_values`` does not exist in ``declared_parameters`` - :raises ~aria.modeling.exceptions.MissingRequiredParametersException: if a key in + :raises ~aria.modeling.exceptions.MissingRequiredInputsException: if a key in ``declared_parameters`` does not exist in ``parameter_values`` and also has no default value :raises ~aria.modeling.exceptions.ParametersOfWrongTypeException: if a value in ``parameter_values`` does not match its type in ``declared_parameters`` """ - parameter_values = parameter_values or {} - - undeclared_names = list(set(parameter_values.keys()).difference(declared_parameters.keys())) - if undeclared_names: - raise exceptions.UndeclaredParametersException( - 'Undeclared parameters have been provided: {0}; Declared: {1}' - .format(string_list_as_string(undeclared_names), - string_list_as_string(declared_parameters.keys()))) + provided_values = provided_values or {} + provided_values_of_wrong_type = OrderedDict() + model_parameters = OrderedDict() - parameters = OrderedDict() - - missing_names = [] - wrong_type_values = OrderedDict() for declared_parameter_name, declared_parameter in declared_parameters.iteritems(): - if declared_parameter_name in parameter_values: - # Value has been provided - value = parameter_values[declared_parameter_name] + if declared_parameter_name in provided_values: + # a value has been provided + value = provided_values[declared_parameter_name] # Validate type type_name = declared_parameter.type_name try: validate_value_type(value, type_name) except ValueError: - wrong_type_values[declared_parameter_name] = type_name + provided_values_of_wrong_type[declared_parameter_name] = type_name except RuntimeError: - # TODO: This error shouldn't be raised (or caught), but right now we lack support + # TODO This error shouldn't be raised (or caught), but right now we lack support # for custom data_types, which will raise this error. Skipping their validation. pass - - # Wrap in Parameter model - parameters[declared_parameter_name] = model_cls( # pylint: disable=unexpected-keyword-arg + model_parameters[declared_parameter_name] = model_cls( # pylint: disable=unexpected-keyword-arg name=declared_parameter_name, type_name=type_name, description=declared_parameter.description, value=value) - elif declared_parameter.value is not None: - # Copy default value from declaration - parameters[declared_parameter_name] = declared_parameter.instantiate(None) else: - # Required value has not been provided - missing_names.append(declared_parameter_name) - - if missing_names: - raise exceptions.MissingRequiredParametersException( - 'Declared parameters {0} have not been provided values' - .format(string_list_as_string(missing_names))) + # Copy default value from declaration + model_parameters[declared_parameter_name] = declared_parameter.instantiate(None) - if wrong_type_values: + if provided_values_of_wrong_type: error_message = StringIO() - for param_name, param_type in wrong_type_values.iteritems(): + for param_name, param_type in provided_values_of_wrong_type.iteritems(): error_message.write('Parameter "{0}" is not of declared type "{1}"{2}' .format(param_name, param_type, os.linesep)) raise exceptions.ParametersOfWrongTypeException(error_message.getvalue()) - return parameters + return model_parameters def coerce_dict_values(the_dict, report_issues=False): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/aria/orchestrator/workflow_runner.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/workflow_runner.py b/aria/orchestrator/workflow_runner.py index a85e7d3..d88e7bc 100644 --- a/aria/orchestrator/workflow_runner.py +++ b/aria/orchestrator/workflow_runner.py @@ -137,6 +137,10 @@ class WorkflowRunner(object): else: workflow_inputs = self.service.workflows[self._workflow_name].inputs + modeling_utils.validate_no_undeclared_inputs(declared_inputs=workflow_inputs, + supplied_inputs=inputs) + modeling_utils.validate_required_inputs_are_supplied(declared_inputs=workflow_inputs, + supplied_inputs=inputs) execution.inputs = modeling_utils.merge_parameter_values(inputs, workflow_inputs, model_cls=models.Input) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/aria/orchestrator/workflows/api/task.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/workflows/api/task.py b/aria/orchestrator/workflows/api/task.py index 4c518fc..9ea5485 100644 --- a/aria/orchestrator/workflows/api/task.py +++ b/aria/orchestrator/workflows/api/task.py @@ -137,6 +137,11 @@ class OperationTask(BaseTask): operation = self.actor.interfaces[self.interface_name].operations[self.operation_name] self.plugin = operation.plugin self.function = operation.function + + modeling_utils.validate_required_inputs_are_supplied( + declared_inputs=operation.inputs, + supplied_inputs=operation.arguments) + self.arguments = modeling_utils.merge_parameter_values(arguments, operation.arguments, model_cls=models.Argument) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/aria/parser/consumption/style.py ---------------------------------------------------------------------- diff --git a/aria/parser/consumption/style.py b/aria/parser/consumption/style.py index 72892b9..0cd6a2d 100644 --- a/aria/parser/consumption/style.py +++ b/aria/parser/consumption/style.py @@ -48,3 +48,8 @@ class Style(object): @staticmethod def meta(value): return Colored.green(value) + + @staticmethod + def required(value): + return Colored.white(value) + http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/aria/parser/presentation/presentation.py ---------------------------------------------------------------------- diff --git a/aria/parser/presentation/presentation.py b/aria/parser/presentation/presentation.py index fe55b05..fb71a1e 100644 --- a/aria/parser/presentation/presentation.py +++ b/aria/parser/presentation/presentation.py @@ -29,10 +29,11 @@ class Value(object): Encapsulates a typed value assignment. """ - def __init__(self, type_name, value, description): + def __init__(self, type_name, value, description, required): self.type = deepcopy_with_locators(type_name) self.value = deepcopy_with_locators(value) self.description = deepcopy_with_locators(description) + self.required = deepcopy_with_locators(required) def _dump(self, context): if self.type is not None: @@ -41,6 +42,8 @@ class Value(object): puts(context.style.literal(self.value)) if self.description is not None: puts(context.style.meta(self.description)) + if self.required is not None: + puts(context.style.required(self.required)) class PresentationBase(HasCachedMethods): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/examples/tosca-simple-1.0/use-cases/webserver-dbms-2/webserver-dbms-2.yaml ---------------------------------------------------------------------- diff --git a/examples/tosca-simple-1.0/use-cases/webserver-dbms-2/webserver-dbms-2.yaml b/examples/tosca-simple-1.0/use-cases/webserver-dbms-2/webserver-dbms-2.yaml index 91f0b35..469c907 100644 --- a/examples/tosca-simple-1.0/use-cases/webserver-dbms-2/webserver-dbms-2.yaml +++ b/examples/tosca-simple-1.0/use-cases/webserver-dbms-2/webserver-dbms-2.yaml @@ -50,7 +50,7 @@ topology_template: interfaces: Standard: configure: - implementation: scripts/nodejs/configure.sh + implementation: scripts/nodejs/c\onfigure.sh inputs: github_url: { get_property: [ SELF, github_url ] } mongodb_ip: { get_attribute: [ mongo_server, private_address ] } http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py index 4d8e1db..441e4ca 100644 --- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py +++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py @@ -94,12 +94,10 @@ def create_service_template_model(context): # pylint: disable=too-many-locals,to # Topology template topology_template = context.presentation.get('service_template', 'topology_template') if topology_template is not None: - create_parameter_models_from_values(model.inputs, - topology_template._get_input_values(context), - model_cls=Input) - create_parameter_models_from_values(model.outputs, - topology_template._get_output_values(context), - model_cls=Output) + create_input_models_from_values(model.inputs, + topology_template._get_input_values(context)) + create_output_models_from_values(model.outputs, + topology_template._get_output_values(context)) # Plugin specifications policies = context.presentation.get('service_template', 'topology_template', 'policies') @@ -171,12 +169,10 @@ def create_node_template_model(context, service_template, node_template): if node_template.description: model.description = node_template.description.value - create_parameter_models_from_values(model.properties, - node_template._get_property_values(context), - model_cls=Property) - create_parameter_models_from_values(model.attributes, - node_template._get_attribute_default_values(context), - model_cls=Attribute) + create_property_models_from_values(model.properties, + node_template._get_property_values(context)) + create_attribute_models_from_values(model.attributes, + node_template._get_attribute_default_values(context)) create_interface_template_models(context, service_template, model.interface_templates, node_template._get_interfaces(context)) @@ -221,8 +217,7 @@ def create_group_template_model(context, service_template, group): if group.description: model.description = group.description.value - create_parameter_models_from_values(model.properties, group._get_property_values(context), - model_cls=Property) + create_property_models_from_values(model.properties, group._get_property_values(context)) create_interface_template_models(context, service_template, model.interface_templates, group._get_interfaces(context)) @@ -245,8 +240,7 @@ def create_policy_template_model(context, service_template, policy): if policy.description: model.description = policy.description.value - create_parameter_models_from_values(model.properties, policy._get_property_values(context), - model_cls=Property) + create_property_models_from_values(model.properties, policy._get_property_values(context)) node_templates, groups = policy._get_targets(context) if node_templates: @@ -356,19 +350,12 @@ def create_capability_template_model(context, service_template, capability): def create_interface_template_model(context, service_template, interface): interface_type = interface._get_type(context) interface_type = service_template.interface_types.get_descendant(interface_type._name) - model = InterfaceTemplate(name=interface._name, - type=interface_type) + model = InterfaceTemplate(name=interface._name, type=interface_type) if interface_type.description: model.description = interface_type.description - inputs = interface.inputs - if inputs: - for input_name, the_input in inputs.iteritems(): - model.inputs[input_name] = Input(name=input_name, # pylint: disable=unexpected-keyword-arg - type_name=the_input.value.type, - value=the_input.value.value, - description=the_input.value.description) + create_parameter_models_from_assignments(model.inputs, interface.inputs, model_cls=Input) operations = interface.operations if operations: @@ -430,14 +417,7 @@ def create_operation_template_model(context, service_template, operation): model.configurations[key] = Configuration.wrap(key, value, description='Operation configuration.') - inputs = operation.inputs - if inputs: - for input_name, the_input in inputs.iteritems(): - model.inputs[input_name] = Input(name=input_name, # pylint: disable=unexpected-keyword-arg - type_name=the_input.value.type, - value=the_input.value.value, - description=the_input.value.description) - + create_parameter_models_from_assignments(model.inputs, operation.inputs, model_cls=Input) return model @@ -462,8 +442,7 @@ def create_artifact_template_model(context, service_template, artifact): for k, v in credential.iteritems(): model.repository_credential[k] = v - create_parameter_models_from_values(model.properties, artifact._get_property_values(context), - model_cls=Property) + create_property_models_from_values(model.properties, artifact._get_property_values(context)) return model @@ -526,10 +505,9 @@ def create_workflow_operation_template_model(context, service_template, policy): if prop_name == 'implementation': model.function = prop.value else: - model.inputs[prop_name] = Input(name=prop_name, # pylint: disable=unexpected-keyword-arg - type_name=prop.type, - value=prop.value, - description=prop.description) + input_model = create_parameter_model_from_value(prop, prop_name, model_cls=Input) + input_model.required = prop.required + model.inputs[prop_name] = input_model used_reserved_names = WORKFLOW_DECORATOR_RESERVED_ARGUMENTS.intersection(model.inputs.keys()) if used_reserved_names: @@ -539,7 +517,6 @@ def create_workflow_operation_template_model(context, service_template, policy): string_list_as_string(used_reserved_names)), locator=policy._locator, level=Issue.EXTERNAL) - return model @@ -577,14 +554,44 @@ def create_types(context, root, types): container.children.append(model) -def create_parameter_models_from_values(properties, source_properties, model_cls): +def create_input_models_from_values(inputs_field, template_inputs): + if template_inputs: + for template_input_name, template_input in template_inputs.iteritems(): + model_input = create_parameter_model_from_value(template_input, template_input_name, + model_cls=Input) + model_input.required = template_input.required + inputs_field[model_input.name] = model_input - if source_properties: - for property_name, prop in source_properties.iteritems(): - properties[property_name] = model_cls(name=property_name, # pylint: disable=unexpected-keyword-arg - type_name=prop.type, - value=prop.value, - description=prop.description) + +def create_output_models_from_values(outputs_field, template_outputs): + for template_output_name, template_output in template_outputs.iteritems(): + outputs_field[template_output_name] = \ + create_parameter_model_from_value(template_output, + template_output_name, + model_cls=Output) + + +def create_property_models_from_values(properties_field, template_properties): + for template_property_name, template_property in template_properties.iteritems(): + properties_field[template_property_name] = \ + create_parameter_model_from_value(template_property, + template_property_name, + model_cls=Property) + + +def create_attribute_models_from_values(attributes_field, template_attributes): + for template_attribute_name, template_attribute in template_attributes.iteritems(): + attributes_field[template_attribute_name] = \ + create_parameter_model_from_value(template_attribute, + template_attribute_name, + model_cls=Attribute) + + +def create_parameter_model_from_value(template_parameter, template_parameter_name, model_cls): + return model_cls(name=template_parameter_name, + type_name=template_parameter.type, + value=template_parameter.value, + description=template_parameter.description) def create_parameter_models_from_assignments(properties, source_properties, model_cls): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py index fbb8280..9dee0f2 100644 --- a/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py +++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py @@ -438,10 +438,7 @@ def coerce_to_primitive(context, presentation, primitive_type, constraints, valu # Check constraints apply_constraints_to_value(context, presentation, constraints, value) - except ValueError as e: - report_issue_for_bad_format(context, presentation, primitive_type, value, aspect, e) - value = None - except TypeError as e: + except (ValueError, TypeError) as e: report_issue_for_bad_format(context, presentation, primitive_type, value, aspect, e) value = None http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py index d5f447c..a25c7f8 100644 --- a/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py +++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py @@ -61,7 +61,7 @@ def get_and_override_input_definitions_from_type(context, presentation): inputs = OrderedDict() # Get inputs from type - the_type = presentation._get_type(context) # IntefaceType + the_type = presentation._get_type(context) # InterfaceType type_inputs = the_type._get_inputs(context) if the_type is not None else None if type_inputs: for input_name, type_input in type_inputs.iteritems(): @@ -213,9 +213,9 @@ def convert_interface_definition_from_type_to_raw_template(context, presentation raw = OrderedDict() # Copy default values for inputs - inputs = presentation._get_inputs(context) - if inputs is not None: - raw['inputs'] = convert_parameter_definitions_to_values(context, inputs) + interface_inputs = presentation._get_inputs(context) + if interface_inputs is not None: + raw['inputs'] = convert_parameter_definitions_to_values(context, interface_inputs) # Copy operations operations = presentation._get_operations(context) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py index 87c1a3b..f271b4d 100644 --- a/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py +++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py @@ -203,7 +203,8 @@ def coerce_parameter_value(context, presentation, definition, value, aspect=None type_name = getattr(definition, 'type', None) description = getattr(definition, 'description', None) description = description.value if description is not None else None - return Value(type_name, value, description) + required = getattr(definition, 'required', None) + return Value(type_name, value, description, required) def convert_parameter_definitions_to_values(context, definitions): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/fd380f44/tests/orchestrator/test_workflow_runner.py ---------------------------------------------------------------------- diff --git a/tests/orchestrator/test_workflow_runner.py b/tests/orchestrator/test_workflow_runner.py index 30176ae..bf6a7b9 100644 --- a/tests/orchestrator/test_workflow_runner.py +++ b/tests/orchestrator/test_workflow_runner.py @@ -216,7 +216,7 @@ def test_execution_inputs_override_workflow_inputs(request): def test_execution_inputs_undeclared_inputs(request): mock_workflow = _setup_mock_workflow_in_service(request) - with pytest.raises(modeling_exceptions.UndeclaredParametersException): + with pytest.raises(modeling_exceptions.UndeclaredInputsException): _create_workflow_runner(request, mock_workflow, inputs={'undeclared_input': 'value'}) @@ -224,7 +224,7 @@ def test_execution_inputs_missing_required_inputs(request): mock_workflow = _setup_mock_workflow_in_service( request, inputs={'required_input': models.Input.wrap('required_input', value=None)}) - with pytest.raises(modeling_exceptions.MissingRequiredParametersException): + with pytest.raises(modeling_exceptions.MissingRequiredInputsException): _create_workflow_runner(request, mock_workflow, inputs={}) @@ -238,7 +238,7 @@ def test_execution_inputs_wrong_type_inputs(request): def test_execution_inputs_builtin_workflow_with_inputs(request): # built-in workflows don't have inputs - with pytest.raises(modeling_exceptions.UndeclaredParametersException): + with pytest.raises(modeling_exceptions.UndeclaredInputsException): _create_workflow_runner(request, 'install', inputs={'undeclared_input': 'value'})
