Passed
Pull Request — master (#3640)
by Lakshmi
06:19
created

ActionExecutionsController.put()   F

Complexity

Conditions 14

Size

Total Lines 77

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
dl 0
loc 77
rs 2.1716
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 action ref is valid
100
        action_ref = liveaction_api.action
101
        action_db = action_utils.get_action_by_ref(action_ref)
102
103
        if not action_db:
104
            message = 'Action "%s" cannot be found.' % action_ref
105
            LOG.warning(message)
106
            abort(http_client.BAD_REQUEST, message)
107
108
        # Assert the permissions
109
        assert_user_has_resource_db_permission(user_db=requester_user, resource_db=action_db,
110
                                               permission_type=PermissionType.ACTION_EXECUTE)
111
112
        # Validate that the authenticated user is admin if user query param is provided
113
        user = liveaction_api.user or requester_user.name
114
        assert_user_is_admin_if_user_query_param_is_provided(user_db=requester_user,
115
                                                             user=user)
116
117
        try:
118
            return self._schedule_execution(liveaction=liveaction_api,
119
                                            requester_user=requester_user,
120
                                            user=user,
121
                                            context_string=context_string,
122
                                            show_secrets=show_secrets,
123
                                            pack=action_db.pack)
124
        except ValueError as e:
125
            LOG.exception('Unable to execute action.')
126
            abort(http_client.BAD_REQUEST, str(e))
127
        except jsonschema.ValidationError as e:
128
            LOG.exception('Unable to execute action. Parameter validation failed.')
129
            abort(http_client.BAD_REQUEST, re.sub("u'([^']*)'", r"'\1'", e.message))
130
        except trace_exc.TraceNotFoundException as e:
131
            abort(http_client.BAD_REQUEST, str(e))
132
        except validation_exc.ValueValidationException as e:
133
            raise e
134
        except Exception as e:
135
            LOG.exception('Unable to execute action. Unexpected error encountered.')
136
            abort(http_client.INTERNAL_SERVER_ERROR, str(e))
137
138
    def _schedule_execution(self,
139
                            liveaction,
140
                            requester_user,
141
                            user=None,
142
                            context_string=None,
143
                            show_secrets=False,
144
                            pack=None):
145
        # Initialize execution context if it does not exist.
146
        if not hasattr(liveaction, 'context'):
147
            liveaction.context = dict()
148
149
        liveaction.context['user'] = user
150
        liveaction.context['pack'] = pack
151
        LOG.debug('User is: %s' % liveaction.context['user'])
152
153
        # Retrieve other st2 context from request header.
154
        if context_string:
155
            context = try_loads(context_string)
156
            if not isinstance(context, dict):
157
                raise ValueError('Unable to convert st2-context from the headers into JSON.')
158
            liveaction.context.update(context)
159
160
        # Include RBAC context (if RBAC is available and enabled)
161
        if cfg.CONF.rbac.enable:
162
            user_db = UserDB(name=user)
163
            role_dbs = rbac_service.get_roles_for_user(user_db=user_db, include_remote=True)
164
            roles = [role_db.name for role_db in role_dbs]
165
            liveaction.context['rbac'] = {
166
                'user': user,
167
                'roles': roles
168
            }
169
170
        # Schedule the action execution.
171
        liveaction_db = LiveActionAPI.to_model(liveaction)
172
        liveaction_db, actionexecution_db = action_service.create_request(liveaction_db)
173
174
        action_db = action_utils.get_action_by_ref(liveaction_db.action)
175
        runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name'])
176
177
        try:
178
            liveaction_db.parameters = param_utils.render_live_params(
179
                runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters,
180
                liveaction_db.context)
181
        except param_exc.ParamException:
182
            # By this point the execution is already in the DB therefore need to mark it failed.
183
            _, e, tb = sys.exc_info()
184
            action_service.update_status(
185
                liveaction=liveaction_db,
186
                new_status=action_constants.LIVEACTION_STATUS_FAILED,
187
                result={'error': str(e), 'traceback': ''.join(traceback.format_tb(tb, 20))})
188
            # Might be a good idea to return the actual ActionExecution rather than bubble up
189
            # the execption.
190
            raise validation_exc.ValueValidationException(str(e))
191
192
        liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False)
193
194
        _, actionexecution_db = action_service.publish_request(liveaction_db, actionexecution_db)
195
        mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets)
196
        execution_api = ActionExecutionAPI.from_model(actionexecution_db, mask_secrets=mask_secrets)
197
198
        return Response(json=execution_api, status=http_client.CREATED)
199
200
    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...
201
        """
202
        Retrieve result object for the provided action execution.
203
204
        :param id: Action execution ID.
205
        :type id: ``str``
206
207
        :rtype: ``dict``
208
        """
209
        fields = ['result']
210
        action_exec_db = self.access.impl.model.objects.filter(id=id).only(*fields).get()
211
        return action_exec_db.result
212
213
    def _get_children(self, id_, requester_user, depth=-1, result_fmt=None,
214
                      show_secrets=False):
215
        # make sure depth is int. Url encoding will make it a string and needs to
216
        # be converted back in that case.
217
        depth = int(depth)
218
        LOG.debug('retrieving children for id: %s with depth: %s', id_, depth)
219
        descendants = execution_service.get_descendants(actionexecution_id=id_,
220
                                                        descendant_depth=depth,
221
                                                        result_fmt=result_fmt)
222
223
        mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets)
224
        return [self.model.from_model(descendant, mask_secrets=mask_secrets) for
225
                descendant in descendants]
226
227
228
class BaseActionExecutionNestedController(ActionExecutionsControllerMixin, ResourceController):
229
    # Note: We need to override "get_one" and "get_all" to return 404 since nested controller
230
    # don't implement thos methods
231
232
    # ResourceController attributes
233
    query_options = {}
234
    supported_filters = {}
235
236
    def get_all(self):
237
        abort(httplib.NOT_FOUND)
238
239
    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...
240
        abort(httplib.NOT_FOUND)
241
242
243
class ActionExecutionChildrenController(BaseActionExecutionNestedController):
244
    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...
245
        """
246
        Retrieve children for the provided action execution.
247
248
        :rtype: ``list``
249
        """
250
251
        instance = self._get_by_id(resource_id=id)
252
253
        permission_type = PermissionType.EXECUTION_VIEW
254
        rbac_utils.assert_user_has_resource_db_permission(user_db=requester_user,
255
                                                          resource_db=instance,
256
                                                          permission_type=permission_type)
257
258
        return self._get_children(id_=id, depth=depth, result_fmt=result_fmt,
259
                                  requester_user=requester_user, show_secrets=show_secrets)
260
261
262
class ActionExecutionAttributeController(BaseActionExecutionNestedController):
263
    valid_exclude_attributes = ['action__pack', 'action__uid'] + \
264
        ActionExecutionsControllerMixin.valid_exclude_attributes
265
266
    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...
267
        """
268
        Retrieve a particular attribute for the provided action execution.
269
270
        Handles requests:
271
272
            GET /executions/<id>/attribute/<attribute name>
273
274
        :rtype: ``dict``
275
        """
276
        fields = [attribute, 'action__pack', 'action__uid']
277
        fields = self._validate_exclude_fields(fields)
278
        action_exec_db = self.access.impl.model.objects.filter(id=id).only(*fields).get()
279
280
        permission_type = PermissionType.EXECUTION_VIEW
281
        rbac_utils.assert_user_has_resource_db_permission(user_db=requester_user,
282
                                                          resource_db=action_exec_db,
283
                                                          permission_type=permission_type)
284
285
        result = getattr(action_exec_db, attribute, None)
286
        return result
287
288
289
class ActionExecutionReRunController(ActionExecutionsControllerMixin, ResourceController):
290
    supported_filters = {}
291
    exclude_fields = [
292
        'result',
293
        'trigger_instance'
294
    ]
295
296
    class ExecutionSpecificationAPI(object):
297
        def __init__(self, parameters=None, tasks=None, reset=None, user=None):
298
            self.parameters = parameters or {}
299
            self.tasks = tasks or []
300
            self.reset = reset or []
301
            self.user = user
302
303
        def validate(self):
304
            if (self.tasks or self.reset) and self.parameters:
305
                raise ValueError('Parameters override is not supported when '
306
                                 're-running task(s) for a workflow.')
307
308
            if self.parameters:
309
                assert isinstance(self.parameters, dict)
310
311
            if self.tasks:
312
                assert isinstance(self.tasks, list)
313
314
            if self.reset:
315
                assert isinstance(self.reset, list)
316
317
            if list(set(self.reset) - set(self.tasks)):
318
                raise ValueError('List of tasks to reset does not match the tasks to rerun.')
319
320
            return self
321
322
    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...
323
        """
324
        Re-run the provided action execution optionally specifying override parameters.
325
326
        Handles requests:
327
328
            POST /executions/<id>/re_run
329
        """
330
331
        if (spec_api.tasks or spec_api.reset) and spec_api.parameters:
332
            raise ValueError('Parameters override is not supported when '
333
                             're-running task(s) for a workflow.')
334
335
        if spec_api.parameters:
336
            assert isinstance(spec_api.parameters, dict)
337
338
        if spec_api.tasks:
339
            assert isinstance(spec_api.tasks, list)
340
341
        if spec_api.reset:
342
            assert isinstance(spec_api.reset, list)
343
344
        if list(set(spec_api.reset) - set(spec_api.tasks)):
345
            raise ValueError('List of tasks to reset does not match the tasks to rerun.')
346
347
        no_merge = cast_argument_value(value_type=bool, value=no_merge)
348
        existing_execution = self._get_one_by_id(id=id, exclude_fields=self.exclude_fields,
349
                                                 requester_user=requester_user,
350
                                                 permission_type=PermissionType.EXECUTION_VIEW)
351
352
        if spec_api.tasks and existing_execution.runner['name'] != 'mistral-v2':
353
            raise ValueError('Task option is only supported for Mistral workflows.')
354
355
        # Merge in any parameters provided by the user
356
        new_parameters = {}
357
        if not no_merge:
358
            new_parameters.update(getattr(existing_execution, 'parameters', {}))
359
        new_parameters.update(spec_api.parameters)
360
361
        # Create object for the new execution
362
        action_ref = existing_execution.action['ref']
363
364
        # Include additional option(s) for the execution
365
        context = {
366
            're-run': {
367
                'ref': id,
368
            }
369
        }
370
371
        if spec_api.tasks:
372
            context['re-run']['tasks'] = spec_api.tasks
373
374
        if spec_api.reset:
375
            context['re-run']['reset'] = spec_api.reset
376
377
        # Add trace to the new execution
378
        trace = trace_service.get_trace_db_by_action_execution(
379
            action_execution_id=existing_execution.id)
380
381
        if trace:
382
            context['trace_context'] = {'id_': str(trace.id)}
383
384
        new_liveaction_api = LiveActionCreateAPI(action=action_ref,
385
                                                 context=context,
386
                                                 parameters=new_parameters,
387
                                                 user=spec_api.user)
388
389
        return self._handle_schedule_execution(liveaction_api=new_liveaction_api,
390
                                               requester_user=requester_user,
391
                                               show_secrets=show_secrets)
392
393
394
class ActionExecutionsController(ActionExecutionsControllerMixin, ResourceController):
395
    """
396
        Implements the RESTful web endpoint that handles
397
        the lifecycle of ActionExecutions in the system.
398
    """
399
400
    # Nested controllers
401
    views = ExecutionViewsController()
402
403
    children = ActionExecutionChildrenController()
404
    attribute = ActionExecutionAttributeController()
405
    re_run = ActionExecutionReRunController()
406
407
    # ResourceController attributes
408
    query_options = {
409
        'sort': ['-start_timestamp', 'action.ref']
410
    }
411
    supported_filters = SUPPORTED_EXECUTIONS_FILTERS
412
    filter_transform_functions = {
413
        'timestamp_gt': lambda value: isotime.parse(value=value),
414
        'timestamp_lt': lambda value: isotime.parse(value=value)
415
    }
416
417
    def get_all(self, requester_user, exclude_attributes=None, sort=None, offset=0, limit=None,
418
                show_secrets=False, **raw_filters):
419
        """
420
        List all executions.
421
422
        Handles requests:
423
            GET /executions[?exclude_attributes=result,trigger_instance]
424
425
        :param exclude_attributes: Comma delimited string of attributes to exclude from the object.
426
        :type exclude_attributes: ``str``
427
        """
428
        if exclude_attributes:
429
            exclude_fields = exclude_attributes.split(',')
430
        else:
431
            exclude_fields = None
432
433
        exclude_fields = self._validate_exclude_fields(exclude_fields=exclude_fields)
434
435
        # Use a custom sort order when filtering on a timestamp so we return a correct result as
436
        # expected by the user
437
        query_options = None
438
        if raw_filters.get('timestamp_lt', None) or raw_filters.get('sort_desc', None):
439
            query_options = {'sort': ['-start_timestamp', 'action.ref']}
440
        elif raw_filters.get('timestamp_gt', None) or raw_filters.get('sort_asc', None):
441
            query_options = {'sort': ['+start_timestamp', 'action.ref']}
442
443
        from_model_kwargs = {
444
            'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets)
445
        }
446
        return self._get_action_executions(exclude_fields=exclude_fields,
447
                                           from_model_kwargs=from_model_kwargs,
448
                                           sort=sort,
449
                                           offset=offset,
450
                                           limit=limit,
451
                                           query_options=query_options,
452
                                           raw_filters=raw_filters)
453
454
    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...
455
        """
456
        Retrieve a single execution.
457
458
        Handles requests:
459
            GET /executions/<id>[?exclude_attributes=result,trigger_instance]
460
461
        :param exclude_attributes: Comma delimited string of attributes to exclude from the object.
462
        :type exclude_attributes: ``str``
463
        """
464
        if exclude_attributes:
465
            exclude_fields = exclude_attributes.split(',')
466
        else:
467
            exclude_fields = None
468
469
        exclude_fields = self._validate_exclude_fields(exclude_fields=exclude_fields)
470
471
        from_model_kwargs = {
472
            'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets)
473
        }
474
        return self._get_one_by_id(id=id, exclude_fields=exclude_fields,
475
                                   requester_user=requester_user,
476
                                   from_model_kwargs=from_model_kwargs,
477
                                   permission_type=PermissionType.EXECUTION_VIEW)
478
479
    def post(self, liveaction_api, requester_user, context_string=None, show_secrets=False):
480
        return self._handle_schedule_execution(liveaction_api=liveaction_api,
481
                                               requester_user=requester_user,
482
                                               context_string=context_string,
483
                                               show_secrets=show_secrets)
484
485
    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...
486
        """
487
        Updates a single execution.
488
489
        Handles requests:
490
            PUT /executions/<id>
491
492
        """
493
        if not requester_user:
494
            requester_user = UserDB(cfg.CONF.system_user.user)
495
496
        from_model_kwargs = {
497
            'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets)
498
        }
499
500
        execution_api = self._get_one_by_id(id=id, requester_user=requester_user,
501
                                            from_model_kwargs=from_model_kwargs,
502
                                            permission_type=PermissionType.EXECUTION_STOP)
503
504
        if not execution_api:
505
            abort(http_client.NOT_FOUND, 'Execution with id %s not found.' % id)
506
507
        liveaction_id = execution_api.liveaction['id']
508
        if not liveaction_id:
509
            abort(http_client.INTERNAL_SERVER_ERROR,
510
                  'Execution object missing link to liveaction %s.' % liveaction_id)
511
512
        try:
513
            liveaction_db = LiveAction.get_by_id(liveaction_id)
514
        except:
515
            abort(http_client.INTERNAL_SERVER_ERROR,
516
                  'Execution object missing link to liveaction %s.' % liveaction_id)
517
518
        if liveaction_db.status in action_constants.LIVEACTION_COMPLETED_STATES:
519
            abort(http_client.BAD_REQUEST, 'Execution is already in completed state.')
520
521
        if (getattr(liveaction_api, 'result', None) is not None and
522
                liveaction_api.status in [
523
                    action_constants.LIVEACTION_STATUS_PAUSING,
524
                    action_constants.LIVEACTION_STATUS_PAUSED,
525
                    action_constants.LIVEACTION_STATUS_RESUMING]):
526
            abort(http_client.BAD_REQUEST,
527
                  'The result is not applicable for pausing and resuming execution.')
528
529
        try:
530
            if (liveaction_api.status == action_constants.LIVEACTION_STATUS_PAUSING or
531
                    liveaction_api.status == action_constants.LIVEACTION_STATUS_PAUSED):
532
                liveaction_db, actionexecution_db = action_service.request_pause(
533
                    liveaction_db, requester_user.name or cfg.CONF.system_user.user)
534
            elif liveaction_api.status == action_constants.LIVEACTION_STATUS_RESUMING:
535
                liveaction_db, actionexecution_db = action_service.request_resume(
536
                    liveaction_db, requester_user.name or cfg.CONF.system_user.user)
537
            else:
538
                liveaction_db = action_service.update_status(
539
                    liveaction_db,
540
                    liveaction_api.status,
541
                    result=getattr(liveaction_api, 'result', None)
542
                )
543
544
                actionexecution_db = ActionExecution.get(liveaction__id=str(liveaction_db.id))
545
        except runner_exc.InvalidActionRunnerOperationError as e:
546
            LOG.exception('Failed updating liveaction %s. %s', liveaction_db.id, str(e))
547
            abort(http_client.BAD_REQUEST, 'Failed updating execution. %s' % str(e))
548
        except runner_exc.UnexpectedActionExecutionStatusError as e:
549
            LOG.exception('Failed updating liveaction %s. %s', liveaction_db.id, str(e))
550
            abort(http_client.BAD_REQUEST, 'Failed updating execution. %s' % str(e))
551
        except Exception as e:
552
            LOG.exception('Failed updating liveaction %s. %s', liveaction_db.id, str(e))
553
            abort(
554
                http_client.INTERNAL_SERVER_ERROR,
555
                'Failed updating execution due to unexpected error.'
556
            )
557
558
        mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets)
559
        execution_api = ActionExecutionAPI.from_model(actionexecution_db, mask_secrets=mask_secrets)
560
561
        return execution_api
562
563
    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...
564
        """
565
        Stops a single execution.
566
567
        Handles requests:
568
            DELETE /executions/<id>
569
570
        """
571
        if not requester_user:
572
            requester_user = UserDB(cfg.CONF.system_user.user)
573
574
        from_model_kwargs = {
575
            'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets)
576
        }
577
        execution_api = self._get_one_by_id(id=id, requester_user=requester_user,
578
                                            from_model_kwargs=from_model_kwargs,
579
                                            permission_type=PermissionType.EXECUTION_STOP)
580
581
        if not execution_api:
582
            abort(http_client.NOT_FOUND, 'Execution with id %s not found.' % id)
583
584
        liveaction_id = execution_api.liveaction['id']
585
        if not liveaction_id:
586
            abort(http_client.INTERNAL_SERVER_ERROR,
587
                  'Execution object missing link to liveaction %s.' % liveaction_id)
588
589
        try:
590
            liveaction_db = LiveAction.get_by_id(liveaction_id)
591
        except:
592
            abort(http_client.INTERNAL_SERVER_ERROR,
593
                  'Execution object missing link to liveaction %s.' % liveaction_id)
594
595
        if liveaction_db.status == action_constants.LIVEACTION_STATUS_CANCELED:
596
            LOG.info(
597
                'Action %s already in "canceled" state; \
598
                returning execution object.' % liveaction_db.id
599
            )
600
            return execution_api
601
602
        if liveaction_db.status not in action_constants.LIVEACTION_CANCELABLE_STATES:
603
            abort(http_client.OK, 'Action cannot be canceled. State = %s.' % liveaction_db.status)
604
605
        try:
606
            (liveaction_db, execution_db) = action_service.request_cancellation(
607
                liveaction_db, requester_user.name or cfg.CONF.system_user.user)
608
        except:
609
            LOG.exception('Failed requesting cancellation for liveaction %s.', liveaction_db.id)
610
            abort(http_client.INTERNAL_SERVER_ERROR, 'Failed canceling execution.')
611
612
        return ActionExecutionAPI.from_model(execution_db,
613
                                             mask_secrets=from_model_kwargs['mask_secrets'])
614
615
    def _get_action_executions(self, exclude_fields=None, sort=None, offset=0, limit=None,
616
                               query_options=None, raw_filters=None, from_model_kwargs=None):
617
        """
618
        :param exclude_fields: A list of object fields to exclude.
619
        :type exclude_fields: ``list``
620
        """
621
622
        if limit is None:
623
            limit = self.default_limit
624
625
        limit = int(limit)
626
627
        LOG.debug('Retrieving all action executions with filters=%s', raw_filters)
628
        return super(ActionExecutionsController, self)._get_all(exclude_fields=exclude_fields,
629
                                                                from_model_kwargs=from_model_kwargs,
630
                                                                sort=sort,
631
                                                                offset=offset,
632
                                                                limit=limit,
633
                                                                query_options=query_options,
634
                                                                raw_filters=raw_filters)
635
636
637
action_executions_controller = ActionExecutionsController()
638
action_execution_rerun_controller = ActionExecutionReRunController()
639
action_execution_attribute_controller = ActionExecutionAttributeController()
640
action_execution_children_controller = ActionExecutionChildrenController()
641