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.
Test Failed
Push — develop-v1.6.0 ( 9d5181...7efb31 )
by
unknown
04:49
created

create_request()   F

Complexity

Conditions 12

Size

Total Lines 79

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
dl 0
loc 79
rs 2.0566
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like create_request() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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 six
17
18
from st2common import log as logging
19
from st2common.constants import action as action_constants
20
from st2common.exceptions.db import StackStormDBObjectNotFoundError
21
from st2common.exceptions.trace import TraceNotFoundException
22
from st2common.persistence.liveaction import LiveAction
23
from st2common.persistence.execution import ActionExecution
24
from st2common.services import executions
25
from st2common.services import trace as trace_service
0 ignored issues
show
Bug introduced by
The name trace does not seem to exist in module st2common.services.
Loading history...
26
from st2common.util import date as date_utils
27
from st2common.util import action_db as action_utils
28
from st2common.util import schema as util_schema
29
30
31
__all__ = [
32
    'request',
33
    'create_request',
34
    'publish_request',
35
    'is_action_canceled_or_canceling'
36
]
37
38
LOG = logging.getLogger(__name__)
39
40
41
def _get_immutable_params(parameters):
42
    if not parameters:
43
        return []
44
    return [k for k, v in six.iteritems(parameters) if v.get('immutable', False)]
45
46
47
def create_request(liveaction):
48
    """
49
    Create an action execution.
50
51
    :return: (liveaction, execution)
52
    :rtype: tuple
53
    """
54
    # Use the user context from the parent action execution. Subtasks in a workflow
55
    # action can be invoked by a system user and so we want to use the user context
56
    # from the original workflow action.
57
    parent_context = executions.get_parent_context(liveaction)
58
    if parent_context:
59
        parent_user = parent_context.get('user', None)
60
        if parent_user:
61
            liveaction.context['user'] = parent_user
62
63
    # Validate action.
64
    action_db = action_utils.get_action_by_ref(liveaction.action)
65
    if not action_db:
66
        raise ValueError('Action "%s" cannot be found.' % liveaction.action)
67
    if not action_db.enabled:
68
        raise ValueError('Unable to execute. Action "%s" is disabled.' % liveaction.action)
69
70
    runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name'])
71
72
    if not hasattr(liveaction, 'parameters'):
73
        liveaction.parameters = dict()
74
75
    # Validate action parameters.
76
    schema = util_schema.get_schema_for_action_parameters(action_db)
77
    validator = util_schema.get_validator()
78
    util_schema.validate(liveaction.parameters, schema, validator, use_default=True,
79
                         allow_default_none=True)
80
81
    # validate that no immutable params are being overriden. Although possible to
82
    # ignore the override it is safer to inform the user to avoid surprises.
83
    immutables = _get_immutable_params(action_db.parameters)
84
    immutables.extend(_get_immutable_params(runnertype_db.runner_parameters))
85
    overridden_immutables = [p for p in six.iterkeys(liveaction.parameters) if p in immutables]
86
    if len(overridden_immutables) > 0:
87
        raise ValueError('Override of immutable parameter(s) %s is unsupported.'
88
                         % str(overridden_immutables))
89
90
    # Set notification settings for action.
91
    # XXX: There are cases when we don't want notifications to be sent for a particular
92
    # execution. So we should look at liveaction.parameters['notify']
93
    # and not set liveaction.notify.
94
    if not _is_notify_empty(action_db.notify):
95
        liveaction.notify = action_db.notify
96
97
    # Write to database and send to message queue.
98
    liveaction.status = action_constants.LIVEACTION_STATUS_REQUESTED
99
    liveaction.start_timestamp = date_utils.get_datetime_utc_now()
100
101
    # Set the "action_is_workflow" attribute
102
    liveaction.action_is_workflow = action_db.is_workflow()
103
104
    # Publish creation after both liveaction and actionexecution are created.
105
    liveaction = LiveAction.add_or_update(liveaction, publish=False)
106
107
    # Get trace_db if it exists. This could throw. If it throws, we have to cleanup
108
    # liveaction object so we don't see things in requested mode.
109
    trace_db = None
110
    try:
111
        _, trace_db = trace_service.get_trace_db_by_live_action(liveaction)
112
    except StackStormDBObjectNotFoundError as e:
113
        _cleanup_liveaction(liveaction)
114
        raise TraceNotFoundException(str(e))
115
116
    execution = executions.create_execution_object(liveaction, publish=False)
117
118
    if trace_db:
119
        trace_service.add_or_update_given_trace_db(
120
            trace_db=trace_db,
121
            action_executions=[
122
                trace_service.get_trace_component_for_action_execution(execution, liveaction)
123
            ])
124
125
    return liveaction, execution
126
127
128
def publish_request(liveaction, execution):
129
    """
130
    Publish an action execution.
131
132
    :return: (liveaction, execution)
133
    :rtype: tuple
134
    """
135
    # Assume that this is a creation.
136
    LiveAction.publish_create(liveaction)
137
    LiveAction.publish_status(liveaction)
138
    ActionExecution.publish_create(execution)
139
140
    extra = {'liveaction_db': liveaction, 'execution_db': execution}
141
    LOG.audit('Action execution requested. LiveAction.id=%s, ActionExecution.id=%s' %
142
              (liveaction.id, execution.id), extra=extra)
143
144
    return liveaction, execution
145
146
147
def request(liveaction):
148
    liveaction, execution = create_request(liveaction)
149
    liveaction, execution = publish_request(liveaction, execution)
150
151
    return liveaction, execution
152
153
154
def update_status(liveaction, new_status, result=None, publish=True):
155
    if liveaction.status == new_status:
156
        return liveaction
157
158
    old_status = liveaction.status
159
160
    liveaction = action_utils.update_liveaction_status(
161
        status=new_status, result=result, liveaction_id=liveaction.id, publish=False)
162
163
    action_execution = executions.update_execution(liveaction)
164
165
    msg = ('The status of action execution is changed from %s to %s. '
166
           '<LiveAction.id=%s, ActionExecution.id=%s>' % (old_status,
167
           new_status, liveaction.id, action_execution.id))
168
169
    extra = {
170
        'action_execution_db': action_execution,
171
        'liveaction_db': liveaction
172
    }
173
174
    LOG.audit(msg, extra=extra)
175
    LOG.info(msg)
176
177
    if publish:
178
        LiveAction.publish_status(liveaction)
179
180
    return liveaction
181
182
183
def is_action_canceled_or_canceling(liveaction_id):
184
    liveaction_db = action_utils.get_liveaction_by_id(liveaction_id)
185
    return liveaction_db.status in [action_constants.LIVEACTION_STATUS_CANCELED,
186
                                    action_constants.LIVEACTION_STATUS_CANCELING]
187
188
189
def request_cancellation(liveaction, requester):
190
    """
191
    Request cancellation of an action execution.
192
193
    :return: (liveaction, execution)
194
    :rtype: tuple
195
    """
196
    if liveaction.status == action_constants.LIVEACTION_STATUS_CANCELING:
197
        return liveaction
198
199
    if liveaction.status not in action_constants.LIVEACTION_CANCELABLE_STATES:
200
        raise Exception('Unable to cancel execution because it is already in a completed state.')
201
202
    result = {
203
        'message': 'Action canceled by user.',
204
        'user': requester
205
    }
206
207
    # There is real work only when liveaction is still running.
208
    status = (action_constants.LIVEACTION_STATUS_CANCELING
209
              if liveaction.status == action_constants.LIVEACTION_STATUS_RUNNING
210
              else action_constants.LIVEACTION_STATUS_CANCELED)
211
212
    update_status(liveaction, status, result=result)
213
214
    execution = ActionExecution.get(liveaction__id=str(liveaction.id))
215
216
    return (liveaction, execution)
217
218
219
def _cleanup_liveaction(liveaction):
220
    try:
221
        LiveAction.delete(liveaction)
222
    except:
223
        LOG.exception('Failed cleaning up LiveAction: %s.', liveaction)
224
        pass
0 ignored issues
show
Unused Code introduced by
Unnecessary pass statement
Loading history...
225
226
227
def _is_notify_empty(notify_db):
228
    """
229
    notify_db is considered to be empty if notify_db is None and neither
230
    of on_complete, on_success and on_failure have values.
231
    """
232
    if not notify_db:
233
        return True
234
    return not (notify_db.on_complete or notify_db.on_success or notify_db.on_failure)
235