Test Failed
Push — master ( 21460f...e380d0 )
by Tomaz
01:48
created

st2common/models/utils/action_param_utils.py (1 issue)

1
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
16
from __future__ import absolute_import
17
import copy
18
import six
19
20
from st2common import log as logging
21
from st2common.util import action_db as action_db_util
22
from st2common.util.casts import get_cast
23
24
LOG = logging.getLogger(__name__)
25
26
27
def _merge_param_meta_values(action_meta=None, runner_meta=None):
28
    runner_meta_keys = list(runner_meta.keys()) if runner_meta else []
29
    action_meta_keys = list(action_meta.keys()) if action_meta else []
30
    all_keys = set(runner_meta_keys).union(set(action_meta_keys))
31
32
    merged_meta = {}
33
34
    # ?? Runner immutable param's meta shouldn't be allowed to be modified by action whatsoever.
35
    if runner_meta and runner_meta.get('immutable', False):
36
        merged_meta = runner_meta
37
38
    for key in all_keys:
39
        if key in action_meta_keys and key not in runner_meta_keys:
40
            merged_meta[key] = action_meta[key]
41
        elif key in runner_meta_keys and key not in action_meta_keys:
42
            merged_meta[key] = runner_meta[key]
43
        else:
44
            if key in ['immutable']:
45
                merged_meta[key] = runner_meta.get(key, False) or action_meta.get(key, False)
46
            else:
47
                merged_meta[key] = action_meta.get(key)
48
    return merged_meta
49
50
51
def get_params_view(action_db=None, runner_db=None, merged_only=False):
52
    runner_params = copy.deepcopy(runner_db.runner_parameters) if runner_db else {}
53
    action_params = copy.deepcopy(action_db.parameters) if action_db else {}
54
55
    parameters = set(runner_params.keys()).union(set(action_params.keys()))
56
57
    merged_params = {}
58
    for param in parameters:
59
        merged_params[param] = _merge_param_meta_values(action_meta=action_params.get(param),
60
                                                        runner_meta=runner_params.get(param))
61
62
    if merged_only:
63
        return merged_params
64
65
    def is_required(param_meta):
66
        return param_meta.get('required', False)
67
68
    def is_immutable(param_meta):
69
        return param_meta.get('immutable', False)
70
71
    immutable = {param for param in parameters if is_immutable(merged_params.get(param))}
72
    required = {param for param in parameters if is_required(merged_params.get(param))}
73
    required = required - immutable
74
    optional = parameters - required - immutable
75
76
    required_params = {k: merged_params[k] for k in required}
77
    optional_params = {k: merged_params[k] for k in optional}
78
    immutable_params = {k: merged_params[k] for k in immutable}
79
80
    return (required_params, optional_params, immutable_params)
81
82
83
def cast_params(action_ref, params, cast_overrides=None):
0 ignored issues
show
Empty function docstring
Loading history...
84
    """
85
    """
86
    params = params or {}
87
    action_db = action_db_util.get_action_by_ref(action_ref)
88
89
    if not action_db:
90
        raise ValueError('Action with ref "%s" doesn\'t exist' % (action_ref))
91
92
    action_parameters_schema = action_db.parameters
93
    runnertype_db = action_db_util.get_runnertype_by_name(action_db.runner_type['name'])
94
    runner_parameters_schema = runnertype_db.runner_parameters
95
    # combine into 1 list of parameter schemas
96
    parameters_schema = {}
97
    if runner_parameters_schema:
98
        parameters_schema.update(runner_parameters_schema)
99
    if action_parameters_schema:
100
        parameters_schema.update(action_parameters_schema)
101
    # cast each param individually
102
    for k, v in six.iteritems(params):
103
        parameter_schema = parameters_schema.get(k, None)
104
        if not parameter_schema:
105
            LOG.debug('Will skip cast of param[name: %s, value: %s]. No schema.', k, v)
106
            continue
107
        parameter_type = parameter_schema.get('type', None)
108
        if not parameter_type:
109
            LOG.debug('Will skip cast of param[name: %s, value: %s]. No type.', k, v)
110
            continue
111
        # Pick up cast from teh override and then from the system suppied ones.
112
        cast = cast_overrides.get(parameter_type, None) if cast_overrides else None
113
        if not cast:
114
            cast = get_cast(cast_type=parameter_type)
115
        if not cast:
116
            LOG.debug('Will skip cast of param[name: %s, value: %s]. No cast for %s.', k, v,
117
                      parameter_type)
118
            continue
119
        LOG.debug('Casting param: %s of type %s to type: %s', v, type(v), parameter_type)
120
121
        try:
122
            params[k] = cast(v)
123
        except Exception as e:
124
            v_type = type(v).__name__
125
            msg = ('Failed to cast value "%s" (type: %s) for parameter "%s" of type "%s": %s. '
126
                   'Perhaps the value is of an invalid type?' %
127
                   (v, v_type, k, parameter_type, str(e)))
128
            raise ValueError(msg)
129
130
    return params
131
132
133
def validate_action_parameters(action_ref, inputs):
134
    input_set = set(inputs.keys())
135
136
    # Get the list of action and runner parameters.
137
    parameters = action_db_util.get_action_parameters_specs(action_ref)
138
139
    # Check required parameters that have no default defined.
140
    required = set([param for param, meta in six.iteritems(parameters)
141
                    if meta.get('required', False) and 'default' not in meta])
142
143
    requires = sorted(required.difference(input_set))
144
145
    # Check unexpected parameters:
146
    unexpected = sorted(input_set.difference(set(parameters.keys())))
147
148
    return requires, unexpected
149