GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — kale/action-datastore (#6)
by Manas
05:59
created

st2actions.runners.PythonRunner.__init__()   A

Complexity

Conditions 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 7
rs 9.4285
cc 1
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 os
17
import sys
18
import abc
19
import json
20
import uuid
21
import logging as stdlib_logging
0 ignored issues
show
Unused Code introduced by
Unused logging imported as stdlib_logging
Loading history...
22
23
import six
24
from eventlet.green import subprocess
25
26
from st2actions.runners import ActionRunner
27
from st2common.util.green.shell import run_command
28
from st2common import log as logging
29
from st2common.constants.action import ACTION_OUTPUT_RESULT_DELIMITER
30
from st2common.constants.action import LIVEACTION_STATUS_SUCCEEDED
31
from st2common.constants.action import LIVEACTION_STATUS_FAILED
32
from st2common.constants.action import LIVEACTION_STATUS_TIMED_OUT
33
from st2common.constants.error_messages import PACK_VIRTUALENV_DOESNT_EXIST
34
from st2common.util.sandboxing import get_sandbox_path
35
from st2common.util.sandboxing import get_sandbox_python_path
36
from st2common.util.sandboxing import get_sandbox_python_binary_path
37
from st2common.util.sandboxing import get_sandbox_virtualenv_path
38
from st2common.constants.runners import PYTHON_RUNNER_DEFAULT_ACTION_TIMEOUT
39
40
__all__ = [
41
    'get_runner',
42
43
    'PythonRunner',
44
    'Action'
45
]
46
47
LOG = logging.getLogger(__name__)
48
49
# constants to lookup in runner_parameters.
50
RUNNER_ENV = 'env'
51
RUNNER_TIMEOUT = 'timeout'
52
53
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
54
WRAPPER_SCRIPT_NAME = 'python_action_wrapper.py'
55
WRAPPER_SCRIPT_PATH = os.path.join(BASE_DIR, WRAPPER_SCRIPT_NAME)
56
57
58
def get_runner():
59
    return PythonRunner(str(uuid.uuid4()))
60
61
62
@six.add_metaclass(abc.ABCMeta)
63
class Action(object):
64
    """
65
    Base action class other Python actions should inherit from.
66
    """
67
68
    description = None
69
70
    def __init__(self, config=None):
71
        """
72
        :param config: Action config.
73
        :type config: ``dict``
74
        """
75
        self.config = config or {}
76
        # logger and datastore are assigned in PythonActionWrapper._get_action_instance
77
        self.logger = None
78
        self.datastore = None
79
80
    @abc.abstractmethod
81
    def run(self, **kwargs):
82
        pass
83
84
85
class PythonRunner(ActionRunner):
86
87
    def __init__(self, runner_id, timeout=PYTHON_RUNNER_DEFAULT_ACTION_TIMEOUT):
88
        """
89
        :param timeout: Action execution timeout in seconds.
90
        :type timeout: ``int``
91
        """
92
        super(PythonRunner, self).__init__(runner_id=runner_id)
93
        self._timeout = timeout
94
95
    def pre_run(self):
96
        # TODO :This is awful, but the way "runner_parameters" and other variables get
97
        # assigned on the runner instance is even worse. Those arguments should
98
        # be passed to the constructor.
99
        self._env = self.runner_parameters.get(RUNNER_ENV, {})
100
        self._timeout = self.runner_parameters.get(RUNNER_TIMEOUT, self._timeout)
101
102
    def run(self, action_parameters):
103
        pack = self.get_pack_name()
104
        serialized_parameters = json.dumps(action_parameters) if action_parameters else ''
105
        virtualenv_path = get_sandbox_virtualenv_path(pack=pack)
106
        python_path = get_sandbox_python_binary_path(pack=pack)
107
108
        if virtualenv_path and not os.path.isdir(virtualenv_path):
109
            format_values = {'pack': pack, 'virtualenv_path': virtualenv_path}
110
            msg = PACK_VIRTUALENV_DOESNT_EXIST % format_values
111
            raise Exception(msg)
112
113
        if not self.entry_point:
114
            raise Exception('Action "%s" is missing entry_point attribute' % (self.action.name))
115
116
        args = [
117
            python_path,
118
            WRAPPER_SCRIPT_PATH,
119
            '--pack=%s' % (pack),
120
            '--file-path=%s' % (self.entry_point),
121
            '--parameters=%s' % (serialized_parameters),
122
            '--parent-args=%s' % (json.dumps(sys.argv[1:]))
123
        ]
124
125
        # We need to ensure all the st2 dependencies are also available to the
126
        # subprocess
127
        env = os.environ.copy()
128
        env['PATH'] = get_sandbox_path(virtualenv_path=virtualenv_path)
129
        env['PYTHONPATH'] = get_sandbox_python_path(inherit_from_parent=True,
130
                                                    inherit_parent_virtualenv=True)
131
132
        # Include user provided environment variables (if any)
133
        user_env_vars = self._get_env_vars()
134
        env.update(user_env_vars)
135
136
        # Include common st2 environment variables
137
        st2_env_vars = self._get_common_action_env_variables()
138
        env.update(st2_env_vars)
139
140
        exit_code, stdout, stderr, timed_out = run_command(cmd=args, stdout=subprocess.PIPE,
141
                                                           stderr=subprocess.PIPE, shell=False,
142
                                                           env=env, timeout=self._timeout)
143
144
        if timed_out:
145
            error = 'Action failed to complete in %s seconds' % (self._timeout)
146
        else:
147
            error = None
148
149
        if ACTION_OUTPUT_RESULT_DELIMITER in stdout:
150
            split = stdout.split(ACTION_OUTPUT_RESULT_DELIMITER)
151
            assert len(split) == 3
152
            result = split[1].strip()
153
            stdout = split[0] + split[2]
154
        else:
155
            result = None
156
157
        try:
158
            result = json.loads(result)
159
        except:
160
            pass
161
162
        output = {
163
            'stdout': stdout,
164
            'stderr': stderr,
165
            'exit_code': exit_code,
166
            'result': result
167
        }
168
169
        if error:
170
            output['error'] = error
171
172
        if exit_code == 0:
173
            status = LIVEACTION_STATUS_SUCCEEDED
174
        elif timed_out:
175
            status = LIVEACTION_STATUS_TIMED_OUT
176
        else:
177
            status = LIVEACTION_STATUS_FAILED
178
179
        return (status, output, None)
180
181
    def _get_env_vars(self):
182
        """
183
        Return sanitized environment variables which will be used when launching
184
        a subprocess.
185
186
        :rtype: ``dict``
187
        """
188
        # Don't allow user to override PYTHONPATH since this would break things
189
        blacklisted_vars = ['pythonpath']
190
        env_vars = {}
191
192
        if self._env:
193
            env_vars.update(self._env)
194
195
        # Remove "blacklisted" environment variables
196
        to_delete = []
197
        for key, value in env_vars.items():
198
            if key.lower() in blacklisted_vars:
199
                to_delete.append(key)
200
201
        for key in to_delete:
202
            del env_vars[key]
203
204
        return env_vars
205