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.
Passed
Push — pip_8.1.2 ( 36f804 )
by
unknown
06:44
created

ActionAliasExecutionController.post()   F

Complexity

Conditions 11

Size

Total Lines 70

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
c 1
b 0
f 0
dl 0
loc 70
rs 3.6

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 ActionAliasExecutionController.post() 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 jsonschema
17
from jinja2.exceptions import UndefinedError
18
from pecan import (abort, rest, request)
19
import six
20
21
from st2common import log as logging
22
from st2common.models.api.base import jsexpose
23
from st2common.exceptions.db import StackStormDBObjectNotFoundError
24
from st2common.models.api.action import AliasExecutionAPI
25
from st2common.models.api.action import ActionAliasAPI
26
from st2common.models.api.auth import get_system_username
27
from st2common.models.api.execution import ActionExecutionAPI
28
from st2common.models.db.liveaction import LiveActionDB
29
from st2common.models.db.notification import NotificationSchema, NotificationSubSchema
30
from st2common.models.utils import action_param_utils
31
from st2common.models.utils.action_alias_utils import extract_parameters_for_action_alias_db
32
from st2common.persistence.actionalias import ActionAlias
33
from st2common.services import action as action_service
34
from st2common.util import action_db as action_utils
35
from st2common.util import reference
36
from st2common.util.api import get_requester
37
from st2common.util.jinja import render_values as render
38
from st2common.rbac.types import PermissionType
39
from st2common.rbac.utils import assert_request_user_has_resource_db_permission
40
41
42
http_client = six.moves.http_client
43
44
LOG = logging.getLogger(__name__)
45
46
CAST_OVERRIDES = {
47
    'array': (lambda cs_x: [v.strip() for v in cs_x.split(',')])
48
}
49
50
51
class ActionAliasExecutionController(rest.RestController):
52
53
    @jsexpose(body_cls=AliasExecutionAPI, status_code=http_client.CREATED)
54
    def post(self, payload):
55
        action_alias_name = payload.name if payload else None
56
57
        if not action_alias_name:
58
            abort(http_client.BAD_REQUEST, 'Alias execution "name" is required')
59
60
        format_str = payload.format or ''
61
        command = payload.command or ''
62
63
        try:
64
            action_alias_db = ActionAlias.get_by_name(action_alias_name)
65
        except ValueError:
66
            action_alias_db = None
67
68
        if not action_alias_db:
69
            msg = 'Unable to identify action alias with name "%s".' % (action_alias_name)
70
            abort(http_client.NOT_FOUND, msg)
71
            return
72
73
        if not action_alias_db.enabled:
74
            msg = 'Action alias with name "%s" is disabled.' % (action_alias_name)
75
            abort(http_client.BAD_REQUEST, msg)
76
            return
77
78
        execution_parameters = extract_parameters_for_action_alias_db(
79
            action_alias_db=action_alias_db,
80
            format_str=format_str,
81
            param_stream=command)
82
        notify = self._get_notify_field(payload)
83
84
        context = {
85
            'action_alias_ref': reference.get_ref_from_model(action_alias_db),
86
            'api_user': payload.user,
87
            'user': get_requester(),
88
            'source_channel': payload.source_channel
89
        }
90
91
        execution = self._schedule_execution(action_alias_db=action_alias_db,
92
                                             params=execution_parameters,
93
                                             notify=notify,
94
                                             context=context)
95
96
        result = {
97
            'execution': execution,
98
            'actionalias': ActionAliasAPI.from_model(action_alias_db)
99
        }
100
101
        if action_alias_db.ack:
102
            try:
103
                if 'format' in action_alias_db.ack:
104
                    result.update({
105
                        'message': render({'alias': action_alias_db.ack['format']}, result)['alias']
106
                    })
107
            except UndefinedError as e:
108
                result.update({
109
                    'message': 'Cannot render "format" in field "ack" for alias. ' + e.message
110
                })
111
112
            try:
113
                if 'extra' in action_alias_db.ack:
114
                    result.update({
115
                        'extra': render(action_alias_db.ack['extra'], result)
116
                    })
117
            except UndefinedError as e:
118
                result.update({
119
                    'extra': 'Cannot render "extra" in field "ack" for alias. ' + e.message
120
                })
121
122
        return result
123
124
    def _tokenize_alias_execution(self, alias_execution):
125
        tokens = alias_execution.strip().split(' ', 1)
126
        return (tokens[0], tokens[1] if len(tokens) > 1 else None)
127
128
    def _get_notify_field(self, payload):
129
        on_complete = NotificationSubSchema()
130
        route = (getattr(payload, 'notification_route', None) or
131
                 getattr(payload, 'notification_channel', None))
132
        on_complete.routes = [route]
133
        on_complete.data = {
134
            'user': payload.user,
135
            'source_channel': payload.source_channel
136
        }
137
        notify = NotificationSchema()
138
        notify.on_complete = on_complete
139
        return notify
140
141
    def _schedule_execution(self, action_alias_db, params, notify, context):
142
        action_ref = action_alias_db.action_ref
143
        action_db = action_utils.get_action_by_ref(action_ref)
144
145
        if not action_db:
146
            raise StackStormDBObjectNotFoundError('Action with ref "%s" not found ' % (action_ref))
147
148
        assert_request_user_has_resource_db_permission(request=request, resource_db=action_db,
149
            permission_type=PermissionType.ACTION_EXECUTE)
150
151
        try:
152
            # prior to shipping off the params cast them to the right type.
153
            params = action_param_utils.cast_params(action_ref=action_alias_db.action_ref,
154
                                                    params=params,
155
                                                    cast_overrides=CAST_OVERRIDES)
156
            if not context:
157
                context = {
158
                    'action_alias_ref': reference.get_ref_from_model(action_alias_db),
159
                    'user': get_system_username()
160
                }
161
            liveaction = LiveActionDB(action=action_alias_db.action_ref, context=context,
162
                                      parameters=params, notify=notify)
163
            _, action_execution_db = action_service.request(liveaction)
164
            return ActionExecutionAPI.from_model(action_execution_db)
165
        except ValueError as e:
166
            LOG.exception('Unable to execute action.')
167
            abort(http_client.BAD_REQUEST, str(e))
168
        except jsonschema.ValidationError as e:
169
            LOG.exception('Unable to execute action. Parameter validation failed.')
170
            abort(http_client.BAD_REQUEST, str(e))
171
        except Exception as e:
172
            LOG.exception('Unable to execute action. Unexpected error encountered.')
173
            abort(http_client.INTERNAL_SERVER_ERROR, str(e))
174