Passed
Pull Request — master (#3507)
by W
04:36
created

ActionExecutionsController.put()   F

Complexity

Conditions 14

Size

Total Lines 86

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
dl 0
loc 86
rs 2
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 ActionExecutionsController.put() 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 copy
17
import re
18
import httplib
19
import sys
20
import traceback
21
22
import jsonschema
23
from oslo_config import cfg
24
from six.moves import http_client
25
26
from st2api.controllers.base import BaseRestControllerMixin
27
from st2api.controllers.resource import ResourceController
28
from st2api.controllers.v1.executionviews import ExecutionViewsController
29
from st2api.controllers.v1.executionviews import SUPPORTED_FILTERS
30
from st2common import log as logging
31
from st2common.constants import action as action_constants
32
from st2common.exceptions import actionrunner as runner_exc
33
from st2common.exceptions import apivalidation as validation_exc
34
from st2common.exceptions import param as param_exc
35
from st2common.exceptions import trace as trace_exc
36
from st2common.models.api.action import LiveActionAPI
37
from st2common.models.api.action import LiveActionCreateAPI
38
from st2common.models.api.base import cast_argument_value
39
from st2common.models.api.execution import ActionExecutionAPI
40
from st2common.models.db.auth import UserDB
41
from st2common.persistence.liveaction import LiveAction
42
from st2common.persistence.execution import ActionExecution
43
from st2common.router import abort
44
from st2common.router import Response
45
from st2common.services import action as action_service
46
from st2common.services import executions as execution_service
47
from st2common.services import trace as trace_service
48
from st2common.services import rbac as rbac_service
49
from st2common.util import isotime
50
from st2common.util import action_db as action_utils
51
from st2common.util import param as param_utils
52
from st2common.util.jsonify import try_loads
53
from st2common.rbac.types import PermissionType
54
from st2common.rbac import utils as rbac_utils
55
from st2common.rbac.utils import assert_user_has_resource_db_permission
56
from st2common.rbac.utils import assert_user_is_admin_if_user_query_param_is_provided
57
58
__all__ = [
59
    'ActionExecutionsController'
60
]
61
62
LOG = logging.getLogger(__name__)
63
64
# Note: We initialize filters here and not in the constructor
65
SUPPORTED_EXECUTIONS_FILTERS = copy.deepcopy(SUPPORTED_FILTERS)
66
SUPPORTED_EXECUTIONS_FILTERS.update({
67
    'timestamp_gt': 'start_timestamp.gt',
68
    'timestamp_lt': 'start_timestamp.lt'
69
})
70
71
MONITOR_THREAD_EMPTY_Q_SLEEP_TIME = 5
72
MONITOR_THREAD_NO_WORKERS_SLEEP_TIME = 1
73
74
75
class ActionExecutionsControllerMixin(BaseRestControllerMixin):
76
    """
77
    Mixin class with shared methods.
78
    """
79
80
    model = ActionExecutionAPI
81
    access = ActionExecution
82
83
    # A list of attributes which can be specified using ?exclude_attributes filter
84
    valid_exclude_attributes = [
85
        'result',
86
        'trigger_instance'
87
    ]
88
89
    def _handle_schedule_execution(self, liveaction_api, requester_user, context_string=None,
90
                                   show_secrets=False):
91
        """
92
        :param liveaction: LiveActionAPI object.
93
        :type liveaction: :class:`LiveActionAPI`
94
        """
95
96
        if not requester_user:
97
            requester_user = UserDB(cfg.CONF.system_user.user)
98
99
        # Assert the permissions
100
        action_ref = liveaction_api.action
101
        action_db = action_utils.get_action_by_ref(action_ref)
102
        user = liveaction_api.user or requester_user.name
103
        pack = action_db.pack
104
105
        assert_user_has_resource_db_permission(user_db=requester_user, resource_db=action_db,
106
                                               permission_type=PermissionType.ACTION_EXECUTE)
107
108
        # Validate that the authenticated user is admin if user query param is provided
109
        assert_user_is_admin_if_user_query_param_is_provided(user_db=requester_user,
110
                                                             user=user)
111
112
        try:
113
            return self._schedule_execution(liveaction=liveaction_api,
114
                                            requester_user=requester_user,
115
                                            user=user,
116
                                            context_string=context_string,
117
                                            show_secrets=show_secrets,
118
                                            pack=pack)
119
        except ValueError as e:
120
            LOG.exception('Unable to execute action.')
121
            abort(http_client.BAD_REQUEST, str(e))
122
        except jsonschema.ValidationError as e:
123
            LOG.exception('Unable to execute action. Parameter validation failed.')
124
            abort(http_client.BAD_REQUEST, re.sub("u'([^']*)'", r"'\1'", e.message))
125
        except trace_exc.TraceNotFoundException as e:
126
            abort(http_client.BAD_REQUEST, str(e))
127
        except validation_exc.ValueValidationException as e:
128
            raise e
129
        except Exception as e:
130
            LOG.exception('Unable to execute action. Unexpected error encountered.')
131
            abort(http_client.INTERNAL_SERVER_ERROR, str(e))
132
133
    def _schedule_execution(self,
134
                            liveaction,
135
                            requester_user,
136
                            user=None,
137
                            context_string=None,
138
                            show_secrets=False,
139
                            pack=None):
140
        # Initialize execution context if it does not exist.
141
        if not hasattr(liveaction, 'context'):
142
            liveaction.context = dict()
143
144
        liveaction.context['user'] = user
145
        liveaction.context['pack'] = pack
146
        LOG.debug('User is: %s' % liveaction.context['user'])
147
148
        # Retrieve other st2 context from request header.
149
        if context_string:
150
            context = try_loads(context_string)
151
            if not isinstance(context, dict):
152
                raise ValueError('Unable to convert st2-context from the headers into JSON.')
153
            liveaction.context.update(context)
154
155
        # Include RBAC context (if RBAC is available and enabled)
156
        if cfg.CONF.rbac.enable:
157
            user_db = UserDB(name=user)
158
            role_dbs = rbac_service.get_roles_for_user(user_db=user_db, include_remote=True)
159
            roles = [role_db.name for role_db in role_dbs]
160
            liveaction.context['rbac'] = {
161
                'user': user,
162
                'roles': roles
163
            }
164
165
        # Schedule the action execution.
166
        liveaction_db = LiveActionAPI.to_model(liveaction)
167
        liveaction_db, actionexecution_db = action_service.create_request(liveaction_db)
168
169
        action_db = action_utils.get_action_by_ref(liveaction_db.action)
170
        runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name'])
171
172
        try:
173
            liveaction_db.parameters = param_utils.render_live_params(
174
                runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters,
175
                liveaction_db.context)
176
        except param_exc.ParamException:
177
            # By this point the execution is already in the DB therefore need to mark it failed.
178
            _, e, tb = sys.exc_info()
179
            action_service.update_status(
180
                liveaction=liveaction_db,
181
                new_status=action_constants.LIVEACTION_STATUS_FAILED,
182
                result={'error': str(e), 'traceback': ''.join(traceback.format_tb(tb, 20))})
183
            # Might be a good idea to return the actual ActionExecution rather than bubble up
184
            # the execption.
185
            raise validation_exc.ValueValidationException(str(e))
186
187
        liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False)
188
189
        _, actionexecution_db = action_service.publish_request(liveaction_db, actionexecution_db)
190
        mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets)
191
        execution_api = ActionExecutionAPI.from_model(actionexecution_db, mask_secrets=mask_secrets)
192
193
        return Response(json=execution_api, status=http_client.CREATED)
194
195
    def _get_result_object(self, id):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in id.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
196
        """
197
        Retrieve result object for the provided action execution.
198
199
        :param id: Action execution ID.
200
        :type id: ``str``
201
202
        :rtype: ``dict``
203
        """
204
        fields = ['result']
205
        action_exec_db = self.access.impl.model.objects.filter(id=id).only(*fields).get()
206
        return action_exec_db.result
207
208
    def _get_children(self, id_, requester_user, depth=-1, result_fmt=None,
209
                      show_secrets=False):
210
        # make sure depth is int. Url encoding will make it a string and needs to
211
        # be converted back in that case.
212
        depth = int(depth)
213
        LOG.debug('retrieving children for id: %s with depth: %s', id_, depth)
214
        descendants = execution_service.get_descendants(actionexecution_id=id_,
215
                                                        descendant_depth=depth,
216
                                                        result_fmt=result_fmt)
217
218
        mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets)
219
        return [self.model.from_model(descendant, mask_secrets=mask_secrets) for
220
                descendant in descendants]
221
222
223
class BaseActionExecutionNestedController(ActionExecutionsControllerMixin, ResourceController):
224
    # Note: We need to override "get_one" and "get_all" to return 404 since nested controller
225
    # don't implement thos methods
226
227
    # ResourceController attributes
228
    query_options = {}
229
    supported_filters = {}
230
231
    def get_all(self):
232
        abort(httplib.NOT_FOUND)
233
234
    def get_one(self, id):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in id.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
235
        abort(httplib.NOT_FOUND)
236
237
238
class ActionExecutionChildrenController(BaseActionExecutionNestedController):
239
    def get_one(self, id, requester_user, depth=-1, result_fmt=None, show_secrets=False):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in id.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
Bug introduced by
Arguments number differs from overridden 'get_one' method
Loading history...
240
        """
241
        Retrieve children for the provided action execution.
242
243
        :rtype: ``list``
244
        """
245
246
        instance = self._get_by_id(resource_id=id)
247
248
        permission_type = PermissionType.EXECUTION_VIEW
249
        rbac_utils.assert_user_has_resource_db_permission(user_db=requester_user,
250
                                                          resource_db=instance,
251
                                                          permission_type=permission_type)
252
253
        return self._get_children(id_=id, depth=depth, result_fmt=result_fmt,
254
                                  requester_user=requester_user, show_secrets=show_secrets)
255
256
257
class ActionExecutionAttributeController(BaseActionExecutionNestedController):
258
    valid_exclude_attributes = ['action__pack', 'action__uid'] + \
259
        ActionExecutionsControllerMixin.valid_exclude_attributes
260
261
    def get(self, id, attribute, requester_user):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in id.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
262
        """
263
        Retrieve a particular attribute for the provided action execution.
264
265
        Handles requests:
266
267
            GET /executions/<id>/attribute/<attribute name>
268
269
        :rtype: ``dict``
270
        """
271
        fields = [attribute, 'action__pack', 'action__uid']
272
        fields = self._validate_exclude_fields(fields)
273
        action_exec_db = self.access.impl.model.objects.filter(id=id).only(*fields).get()
274
275
        permission_type = PermissionType.EXECUTION_VIEW
276
        rbac_utils.assert_user_has_resource_db_permission(user_db=requester_user,
277
                                                          resource_db=action_exec_db,
278
                                                          permission_type=permission_type)
279
280
        result = getattr(action_exec_db, attribute, None)
281
        return result
282
283
284
class ActionExecutionReRunController(ActionExecutionsControllerMixin, ResourceController):
285
    supported_filters = {}
286
    exclude_fields = [
287
        'result',
288
        'trigger_instance'
289
    ]
290
291
    class ExecutionSpecificationAPI(object):
292
        def __init__(self, parameters=None, tasks=None, reset=None, user=None):
293
            self.parameters = parameters or {}
294
            self.tasks = tasks or []
295
            self.reset = reset or []
296
            self.user = user
297
298
        def validate(self):
299
            if (self.tasks or self.reset) and self.parameters:
300
                raise ValueError('Parameters override is not supported when '
301
                                 're-running task(s) for a workflow.')
302
303
            if self.parameters:
304
                assert isinstance(self.parameters, dict)
305
306
            if self.tasks:
307
                assert isinstance(self.tasks, list)
308
309
            if self.reset:
310
                assert isinstance(self.reset, list)
311
312
            if list(set(self.reset) - set(self.tasks)):
313
                raise ValueError('List of tasks to reset does not match the tasks to rerun.')
314
315
            return self
316
317
    def post(self, spec_api, id, requester_user, no_merge=False, show_secrets=False):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in id.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
318
        """
319
        Re-run the provided action execution optionally specifying override parameters.
320
321
        Handles requests:
322
323
            POST /executions/<id>/re_run
324
        """
325
326
        if (spec_api.tasks or spec_api.reset) and spec_api.parameters:
327
            raise ValueError('Parameters override is not supported when '
328
                             're-running task(s) for a workflow.')
329
330
        if spec_api.parameters:
331
            assert isinstance(spec_api.parameters, dict)
332
333
        if spec_api.tasks:
334
            assert isinstance(spec_api.tasks, list)
335
336
        if spec_api.reset:
337
            assert isinstance(spec_api.reset, list)
338
339
        if list(set(spec_api.reset) - set(spec_api.tasks)):
340
            raise ValueError('List of tasks to reset does not match the tasks to rerun.')
341
342
        no_merge = cast_argument_value(value_type=bool, value=no_merge)
343
        existing_execution = self._get_one_by_id(id=id, exclude_fields=self.exclude_fields,
344
                                                 requester_user=requester_user,
345
                                                 permission_type=PermissionType.EXECUTION_VIEW)
346
347
        if spec_api.tasks and existing_execution.runner['name'] != 'mistral-v2':
348
            raise ValueError('Task option is only supported for Mistral workflows.')
349
350
        # Merge in any parameters provided by the user
351
        new_parameters = {}
352
        if not no_merge:
353
            new_parameters.update(getattr(existing_execution, 'parameters', {}))
354
        new_parameters.update(spec_api.parameters)
355
356
        # Create object for the new execution
357
        action_ref = existing_execution.action['ref']
358
359
        # Include additional option(s) for the execution
360
        context = {
361
            're-run': {
362
                'ref': id,
363
            }
364
        }
365
366
        if spec_api.tasks:
367
            context['re-run']['tasks'] = spec_api.tasks
368
369
        if spec_api.reset:
370
            context['re-run']['reset'] = spec_api.reset
371
372
        # Add trace to the new execution
373
        trace = trace_service.get_trace_db_by_action_execution(
374
            action_execution_id=existing_execution.id)
375
376
        if trace:
377
            context['trace_context'] = {'id_': str(trace.id)}
378
379
        new_liveaction_api = LiveActionCreateAPI(action=action_ref,
380
                                                 context=context,
381
                                                 parameters=new_parameters,
382
                                                 user=spec_api.user)
383
384
        return self._handle_schedule_execution(liveaction_api=new_liveaction_api,
385
                                               requester_user=requester_user,
386
                                               show_secrets=show_secrets)
387
388
389
class ActionExecutionsController(ActionExecutionsControllerMixin, ResourceController):
390
    """
391
        Implements the RESTful web endpoint that handles
392
        the lifecycle of ActionExecutions in the system.
393
    """
394
395
    # Nested controllers
396
    views = ExecutionViewsController()
397
398
    children = ActionExecutionChildrenController()
399
    attribute = ActionExecutionAttributeController()
400
    re_run = ActionExecutionReRunController()
401
402
    # ResourceController attributes
403
    query_options = {
404
        'sort': ['-start_timestamp', 'action.ref']
405
    }
406
    supported_filters = SUPPORTED_EXECUTIONS_FILTERS
407
    filter_transform_functions = {
408
        'timestamp_gt': lambda value: isotime.parse(value=value),
409
        'timestamp_lt': lambda value: isotime.parse(value=value)
410
    }
411
412
    def get_all(self, requester_user, exclude_attributes=None, sort=None, offset=0, limit=None,
413
                show_secrets=False, **raw_filters):
414
        """
415
        List all executions.
416
417
        Handles requests:
418
            GET /executions[?exclude_attributes=result,trigger_instance]
419
420
        :param exclude_attributes: Comma delimited string of attributes to exclude from the object.
421
        :type exclude_attributes: ``str``
422
        """
423
        if exclude_attributes:
424
            exclude_fields = exclude_attributes.split(',')
425
        else:
426
            exclude_fields = None
427
428
        exclude_fields = self._validate_exclude_fields(exclude_fields=exclude_fields)
429
430
        # Use a custom sort order when filtering on a timestamp so we return a correct result as
431
        # expected by the user
432
        query_options = None
433
        if raw_filters.get('timestamp_lt', None) or raw_filters.get('sort_desc', None):
434
            query_options = {'sort': ['-start_timestamp', 'action.ref']}
435
        elif raw_filters.get('timestamp_gt', None) or raw_filters.get('sort_asc', None):
436
            query_options = {'sort': ['+start_timestamp', 'action.ref']}
437
438
        from_model_kwargs = {
439
            'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets)
440
        }
441
        return self._get_action_executions(exclude_fields=exclude_fields,
442
                                           from_model_kwargs=from_model_kwargs,
443
                                           sort=sort,
444
                                           offset=offset,
445
                                           limit=limit,
446
                                           query_options=query_options,
447
                                           raw_filters=raw_filters)
448
449
    def get_one(self, id, requester_user, exclude_attributes=None, show_secrets=False):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in id.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
450
        """
451
        Retrieve a single execution.
452
453
        Handles requests:
454
            GET /executions/<id>[?exclude_attributes=result,trigger_instance]
455
456
        :param exclude_attributes: Comma delimited string of attributes to exclude from the object.
457
        :type exclude_attributes: ``str``
458
        """
459
        if exclude_attributes:
460
            exclude_fields = exclude_attributes.split(',')
461
        else:
462
            exclude_fields = None
463
464
        exclude_fields = self._validate_exclude_fields(exclude_fields=exclude_fields)
465
466
        from_model_kwargs = {
467
            'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets)
468
        }
469
        return self._get_one_by_id(id=id, exclude_fields=exclude_fields,
470
                                   requester_user=requester_user,
471
                                   from_model_kwargs=from_model_kwargs,
472
                                   permission_type=PermissionType.EXECUTION_VIEW)
473
474
    def post(self, liveaction_api, requester_user, context_string=None, show_secrets=False):
475
        return self._handle_schedule_execution(liveaction_api=liveaction_api,
476
                                               requester_user=requester_user,
477
                                               context_string=context_string,
478
                                               show_secrets=show_secrets)
479
480
    def put(self, id, liveaction_api, requester_user, show_secrets=False):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in id.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
481
        """
482
        Updates a single execution.
483
484
        Handles requests:
485
            PUT /executions/<id>
486
487
        """
488
        if not requester_user:
489
            requester_user = UserDB(cfg.CONF.system_user.user)
490
491
        from_model_kwargs = {
492
            'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets)
493
        }
494
495
        execution_api = self._get_one_by_id(id=id, requester_user=requester_user,
496
                                            from_model_kwargs=from_model_kwargs,
497
                                            permission_type=PermissionType.EXECUTION_STOP)
498
499
        if not execution_api:
500
            abort(http_client.NOT_FOUND, 'Execution with id %s not found.' % id)
501
502
        liveaction_id = execution_api.liveaction['id']
503
        if not liveaction_id:
504
            abort(http_client.INTERNAL_SERVER_ERROR,
505
                  'Execution object missing link to liveaction %s.' % liveaction_id)
506
507
        try:
508
            liveaction_db = LiveAction.get_by_id(liveaction_id)
509
        except:
510
            abort(http_client.INTERNAL_SERVER_ERROR,
511
                  'Execution object missing link to liveaction %s.' % liveaction_id)
512
513
        if liveaction_db.status in action_constants.LIVEACTION_COMPLETED_STATES:
514
            abort(http_client.BAD_REQUEST, 'Execution is already in completed state.')
515
516
        if (getattr(liveaction_api, 'result', None) is not None and
517
                liveaction_db.status in [
518
                    action_constants.LIVEACTION_STATUS_PAUSING,
519
                    action_constants.LIVEACTION_STATUS_PAUSED,
520
                    action_constants.LIVEACTION_STATUS_RESUMING]):
521
            LOG.warning(
522
                'The given result attribute of the liveaction update for %s '
523
                'is ignored for status change to pause or resume.',
524
                liveaction_id
525
            )
526
527
        try:
528
            if (liveaction_api.status == action_constants.LIVEACTION_STATUS_PAUSING or
529
                    liveaction_api.status == action_constants.LIVEACTION_STATUS_PAUSED):
530
                liveaction_db, actionexecution_db = action_service.request_pause(
531
                    liveaction_db, requester_user.name or cfg.CONF.system_user.user)
532
            elif liveaction_api.status == action_constants.LIVEACTION_STATUS_RESUMING:
533
                liveaction_db, actionexecution_db = action_service.request_resume(
534
                    liveaction_db, requester_user.name or cfg.CONF.system_user.user)
535
            else:
536
                liveaction_db = action_service.update_status(
537
                    liveaction_db,
538
                    liveaction_api.status,
539
                    result=getattr(liveaction_api, 'result', None)
540
                )
541
542
                actionexecution_db = ActionExecution.get(liveaction__id=str(liveaction_db.id))
543
        except runner_exc.InvalidActionRunnerOperationError as e:
544
            LOG.exception('Failed updating liveaction %s. %s', liveaction_db.id, str(e))
545
            abort(
546
                http_client.BAD_REQUEST,
547
                'Failed updating execution because the specific type of request is not supported.'
548
            )
549
        except runner_exc.UnexpectedActionExecutionStatusError as e:
550
            LOG.exception('Failed updating liveaction %s. %s', liveaction_db.id, str(e))
551
            abort(
552
                http_client.BAD_REQUEST,
553
                'Failed updating execution. %s' % str(e)
554
            )
555
        except Exception as e:
556
            LOG.exception('Failed updating liveaction %s. %s', liveaction_db.id, str(e))
557
            abort(
558
                http_client.INTERNAL_SERVER_ERROR,
559
                'Failed updating execution due to unexpected error.'
560
            )
561
562
        mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets)
563
        execution_api = ActionExecutionAPI.from_model(actionexecution_db, mask_secrets=mask_secrets)
564
565
        return execution_api
566
567
    def delete(self, id, requester_user, show_secrets=False):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in id.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
568
        """
569
        Stops a single execution.
570
571
        Handles requests:
572
            DELETE /executions/<id>
573
574
        """
575
        if not requester_user:
576
            requester_user = UserDB(cfg.CONF.system_user.user)
577
578
        from_model_kwargs = {
579
            'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets)
580
        }
581
        execution_api = self._get_one_by_id(id=id, requester_user=requester_user,
582
                                            from_model_kwargs=from_model_kwargs,
583
                                            permission_type=PermissionType.EXECUTION_STOP)
584
585
        if not execution_api:
586
            abort(http_client.NOT_FOUND, 'Execution with id %s not found.' % id)
587
588
        liveaction_id = execution_api.liveaction['id']
589
        if not liveaction_id:
590
            abort(http_client.INTERNAL_SERVER_ERROR,
591
                  'Execution object missing link to liveaction %s.' % liveaction_id)
592
593
        try:
594
            liveaction_db = LiveAction.get_by_id(liveaction_id)
595
        except:
596
            abort(http_client.INTERNAL_SERVER_ERROR,
597
                  'Execution object missing link to liveaction %s.' % liveaction_id)
598
599
        if liveaction_db.status == action_constants.LIVEACTION_STATUS_CANCELED:
600
            LOG.info(
601
                'Action %s already in "canceled" state; \
602
                returning execution object.' % liveaction_db.id
603
            )
604
            return execution_api
605
606
        if liveaction_db.status not in action_constants.LIVEACTION_CANCELABLE_STATES:
607
            abort(http_client.OK, 'Action cannot be canceled. State = %s.' % liveaction_db.status)
608
609
        try:
610
            (liveaction_db, execution_db) = action_service.request_cancellation(
611
                liveaction_db, requester_user.name or cfg.CONF.system_user.user)
612
        except:
613
            LOG.exception('Failed requesting cancellation for liveaction %s.', liveaction_db.id)
614
            abort(http_client.INTERNAL_SERVER_ERROR, 'Failed canceling execution.')
615
616
        return ActionExecutionAPI.from_model(execution_db,
617
                                             mask_secrets=from_model_kwargs['mask_secrets'])
618
619
    def _get_action_executions(self, exclude_fields=None, sort=None, offset=0, limit=None,
620
                               query_options=None, raw_filters=None, from_model_kwargs=None):
621
        """
622
        :param exclude_fields: A list of object fields to exclude.
623
        :type exclude_fields: ``list``
624
        """
625
626
        if limit is None:
627
            limit = self.default_limit
628
629
        limit = int(limit)
630
631
        LOG.debug('Retrieving all action executions with filters=%s', raw_filters)
632
        return super(ActionExecutionsController, self)._get_all(exclude_fields=exclude_fields,
633
                                                                from_model_kwargs=from_model_kwargs,
634
                                                                sort=sort,
635
                                                                offset=offset,
636
                                                                limit=limit,
637
                                                                query_options=query_options,
638
                                                                raw_filters=raw_filters)
639
640
641
action_executions_controller = ActionExecutionsController()
642
action_execution_rerun_controller = ActionExecutionReRunController()
643
action_execution_attribute_controller = ActionExecutionAttributeController()
644
action_execution_children_controller = ActionExecutionChildrenController()
645