Test Failed
Pull Request — master (#3658)
by Lakshmi
20:11
created

ActionRunner.get_pack_ref()   A

Complexity

Conditions 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
c 0
b 0
f 0
dl 0
loc 10
rs 9.4285
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
import abc
17
import six
18
from oslo_config import cfg
19
20
from st2common import log as logging
21
from st2common.constants.pack import DEFAULT_PACK_NAME
22
from st2common.exceptions.actionrunner import ActionRunnerCreateError
23
from st2common.util import action_db as action_utils
24
from st2common.util.loader import register_runner, register_callback_module
25
from st2common.util.api import get_full_public_api_url
26
from st2common.util.deprecation import deprecated
27
28
__all__ = [
29
    'ActionRunner',
30
    'AsyncActionRunner',
31
    'ShellRunnerMixin',
32
33
    'get_runner'
34
]
35
36
37
LOG = logging.getLogger(__name__)
38
39
# constants to lookup in runner_parameters
40
RUNNER_COMMAND = 'cmd'
41
42
43
def get_runner(module_name):
44
    """Load the module and return an instance of the runner."""
45
46
    LOG.debug('Runner loading python module: %s', module_name)
47
    try:
48
        # TODO: Explore modifying this to support register_plugin
49
        module = register_runner(module_name)
50
    except Exception as e:
51
        LOG.exception('Failed to import module %s.', module_name)
52
        raise ActionRunnerCreateError(e)
53
54
    LOG.debug('Instance of runner module: %s', module)
55
56
    runner = module.get_runner()
57
    LOG.debug('Instance of runner: %s', runner)
58
    return runner
59
60
61
@six.add_metaclass(abc.ABCMeta)
62
class ActionRunner(object):
63
    """
64
        The interface that must be implemented by each StackStorm
65
        Action Runner implementation.
66
    """
67
68
    def __init__(self, runner_id):
69
        """
70
        :param id: Runner id.
71
        :type id: ``str``
72
        """
73
        self.runner_id = runner_id
74
75
        self.runner_type_db = None
76
        self.container_service = None
77
        self.runner_parameters = None
78
        self.action = None
79
        self.action_name = None
80
        self.liveaction = None
81
        self.liveaction_id = None
82
        self.execution = None
83
        self.execution_id = None
84
        self.entry_point = None
85
        self.libs_dir_path = None
86
        self.context = None
87
        self.callback = None
88
        self.auth_token = None
89
        self.rerun_ex_ref = None
90
91
    def pre_run(self):
92
        runner_enabled = getattr(self.runner_type_db, 'enabled', True)
93
        runner_name = getattr(self.runner_type_db, 'name', 'unknown')
94
        if not runner_enabled:
95
            msg = ('Runner "%s" has been disabled by the administrator' %
96
                   (runner_name))
97
            raise ValueError(msg)
98
99
    # Run will need to take an action argument
100
    # Run may need result data argument
101
    @abc.abstractmethod
102
    def run(self, action_parameters):
103
        raise NotImplementedError()
104
105
    def cancel(self):
106
        pass
107
108
    def post_run(self, status, result):
109
        callback = self.callback or {}
110
111
        if callback and not (set(['url', 'source']) - set(callback.keys())):
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after not.
Loading history...
112
            callback_url = callback['url']
113
            callback_module_name = callback['source']
114
115
            try:
116
                callback_module = register_callback_module(callback_module_name)
117
            except:
118
                LOG.exception('Failed importing callback module: %s', callback_module_name)
119
120
            callback_handler = callback_module.get_instance()
121
122
            callback_handler.callback(
123
                callback_url,
124
                self.context,
125
                status,
126
                result
127
            )
128
129
    @deprecated
130
    def get_pack_name(self):
131
        return self.get_pack_ref()
132
133
    def get_pack_ref(self):
134
        """
135
        Retrieve pack name for the action which is being currently executed.
136
137
        :rtype: ``str``
138
        """
139
        if self.action:
140
            return self.action.pack
141
142
        return DEFAULT_PACK_NAME
143
144
    def get_user(self):
145
        """
146
        Retrieve a name of the user which triggered this action execution.
147
148
        :rtype: ``str``
149
        """
150
        context = getattr(self, 'context', {}) or {}
151
        user = context.get('user', cfg.CONF.system_user.user)
152
153
        return user
154
155
    def _get_common_action_env_variables(self):
156
        """
157
        Retrieve common ST2_ACTION_ environment variables which will be available to the action.
158
159
        Note: Environment variables are prefixed with ST2_ACTION_* so they don't clash with CLI
160
        environment variables.
161
162
        :rtype: ``dict``
163
        """
164
        result = {}
165
        result['ST2_ACTION_PACK_NAME'] = self.get_pack_ref()
166
        result['ST2_ACTION_EXECUTION_ID'] = str(self.execution_id)
167
        result['ST2_ACTION_API_URL'] = get_full_public_api_url()
168
169
        if self.auth_token:
170
            result['ST2_ACTION_AUTH_TOKEN'] = self.auth_token.token
171
172
        return result
173
174
    def __str__(self):
175
        attrs = ', '.join(['%s=%s' % (k, v) for k, v in six.iteritems(self.__dict__)])
176
        return '%s@%s(%s)' % (self.__class__.__name__, str(id(self)), attrs)
177
178
179
@six.add_metaclass(abc.ABCMeta)
180
class AsyncActionRunner(ActionRunner):
181
    pass
182
183
184
class ShellRunnerMixin(object):
185
    """
186
    Class which contains utility functions to be used by shell runners.
187
    """
188
189
    def _transform_named_args(self, named_args):
190
        """
191
        Transform named arguments to the final form.
192
193
        :param named_args: Named arguments.
194
        :type named_args: ``dict``
195
196
        :rtype: ``dict``
197
        """
198
        if named_args:
199
            return {self._kwarg_op + k: v for (k, v) in six.iteritems(named_args)}
200
        return None
201
202
    def _get_script_args(self, action_parameters):
203
        """
204
        :param action_parameters: Action parameters.
205
        :type action_parameters: ``dict``
206
207
        :return: (positional_args, named_args)
208
        :rtype: (``str``, ``dict``)
209
        """
210
        # TODO: return list for positional args, command classes should escape it
211
        # and convert it to string
212
213
        is_script_run_as_cmd = self.runner_parameters.get(RUNNER_COMMAND, None)
214
215
        pos_args = ''
216
        named_args = {}
217
218
        if is_script_run_as_cmd:
219
            pos_args = self.runner_parameters.get(RUNNER_COMMAND, '')
220
            named_args = action_parameters
221
        else:
222
            pos_args, named_args = action_utils.get_args(action_parameters, self.action)
223
224
        return pos_args, named_args
225