Completed
Push — master ( bb5487...4fc1d0 )
by Manas
13:01 queued 05:18
created

st2actions.handlers.get_handler()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

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