Test Failed
Pull Request — master (#3163)
by W
05:02
created

MistralCallbackHandler._update_action_execution()   A

Complexity

Conditions 1

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
dl 0
loc 14
rs 9.4285
c 1
b 0
f 0
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 ast
17
import json
18
import re
19
import retrying
20
21
from oslo_config import cfg
22
from mistralclient.api import client as mistral
0 ignored issues
show
Unused Code introduced by
Unused client imported from mistralclient.api as mistral
Loading history...
23
24
from st2actions import handlers
25
from st2common.constants import action as action_constants
26
from st2common import log as logging
27
from st2common.persistence.execution import ActionExecution
28
from st2common.util import url as url_utils
29
from st2common.util.workflow import mistral as utils
30
31
32
LOG = logging.getLogger(__name__)
33
34
35
STATUS_MAP = {
36
    action_constants.LIVEACTION_STATUS_REQUESTED: 'RUNNING',
37
    action_constants.LIVEACTION_STATUS_SCHEDULED: 'RUNNING',
38
    action_constants.LIVEACTION_STATUS_DELAYED: 'RUNNING',
39
    action_constants.LIVEACTION_STATUS_RUNNING: 'RUNNING',
40
    action_constants.LIVEACTION_STATUS_SUCCEEDED: 'SUCCESS',
41
    action_constants.LIVEACTION_STATUS_FAILED: 'ERROR',
42
    action_constants.LIVEACTION_STATUS_TIMED_OUT: 'ERROR',
43
    action_constants.LIVEACTION_STATUS_ABANDONED: 'ERROR',
44
    action_constants.LIVEACTION_STATUS_CANCELING: 'RUNNING',
45
    action_constants.LIVEACTION_STATUS_CANCELED: 'ERROR'
46
}
47
48
49
def get_handler():
50
    return MistralCallbackHandler
51
52
53
def get_action_execution_id_from_url(url):
54
    match = re.search('(.+)/action_executions/(.+)', url)
55
    if not match or len(match.groups()) != 2:
56
        raise ValueError('Unable to extract the action execution ID '
57
                         'from the callback URL (%s).' % (url))
58
59
    return match.group(2)
60
61
62
class MistralCallbackHandler(handlers.ActionExecutionCallbackHandler):
63
64
    @classmethod
65
    @retrying.retry(
66
        retry_on_exception=utils.retry_on_exceptions,
67
        wait_exponential_multiplier=cfg.CONF.mistral.retry_exp_msec,
68
        wait_exponential_max=cfg.CONF.mistral.retry_exp_max_msec,
69
        stop_max_delay=cfg.CONF.mistral.retry_stop_max_msec)
70
    def _update_action_execution(cls, url, data, auth_token):
71
        action_execution_id = get_action_execution_id_from_url(url)
72
73
        LOG.info('Sending callback to %s with data %s.', url, data)
74
75
        base_url = url_utils.get_url_without_trailing_slash(cfg.CONF.mistral.v2_base_url)
76
        client = utils.get_client(base_url, auth_token=auth_token)
77
        client.action_executions.update(action_execution_id, **data)
78
79
    @classmethod
80
    def callback(cls, url, context, status, result):
0 ignored issues
show
Bug introduced by
Arguments number differs from overridden 'callback' method
Loading history...
81
        if status not in action_constants.LIVEACTION_COMPLETED_STATES:
82
            return
83
84
        parent_ex_id = context['parent']['execution_id']
85
        parent_ex = ActionExecution.get_by_id(parent_ex_id)
86
        parent_ex_ctx = parent_ex.context
87
        mistral_ctx = parent_ex_ctx.get('mistral', {})
88
        auth_token = mistral_ctx.get('auth_token', None)
89
90
        try:
91
            if isinstance(result, basestring) and len(result) > 0 and result[0] in ['{', '[']:
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'basestring'
Loading history...
92
                value = ast.literal_eval(result)
93
                if type(value) in [dict, list]:
94
                    result = value
95
96
            output = json.dumps(result) if type(result) in [dict, list] else str(result)
97
            data = {'state': STATUS_MAP[status], 'output': output}
98
99
            cls._update_action_execution(url, data, auth_token)
100
        except Exception as e:
101
            LOG.exception(e)
102