Passed
Push — master ( 10b726...2f8890 )
by
unknown
03:57
created

ActionExecutionAPI   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 125
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 125
rs 10
wmc 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
B to_model() 0 20 5
B from_model() 0 16 5
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
18
import six
19
20
from st2common.constants.action import LIVEACTION_STATUSES
21
from st2common.util import isotime
22
from st2common.models.api.base import BaseAPI
23
from st2common.models.db.execution import ActionExecutionDB
24
from st2common.models.api.trigger import TriggerTypeAPI, TriggerAPI, TriggerInstanceAPI
25
from st2common.models.api.rule import RuleAPI
26
from st2common.models.api.action import RunnerTypeAPI, ActionAPI, LiveActionAPI
27
from st2common import log as logging
28
29
30
LOG = logging.getLogger(__name__)
31
32
REQUIRED_ATTR_SCHEMAS = {
33
    "action": copy.deepcopy(ActionAPI.schema),
34
    "runner": copy.deepcopy(RunnerTypeAPI.schema),
35
    "liveaction": copy.deepcopy(LiveActionAPI.schema),
36
}
37
38
for k, v in six.iteritems(REQUIRED_ATTR_SCHEMAS):
39
    v.update({"required": True})
40
41
42
class ActionExecutionAPI(BaseAPI):
43
    model = ActionExecutionDB
44
    SKIP = ['start_timestamp', 'end_timestamp']
45
    schema = {
46
        "title": "ActionExecution",
47
        "description": "Record of the execution of an action.",
48
        "type": "object",
49
        "properties": {
50
            "id": {
51
                "type": "string",
52
                "required": True
53
            },
54
            "trigger": TriggerAPI.schema,
55
            "trigger_type": TriggerTypeAPI.schema,
56
            "trigger_instance": TriggerInstanceAPI.schema,
57
            "rule": RuleAPI.schema,
58
            "action": REQUIRED_ATTR_SCHEMAS['action'],
59
            "runner": REQUIRED_ATTR_SCHEMAS['runner'],
60
            "liveaction": REQUIRED_ATTR_SCHEMAS['liveaction'],
61
            "status": {
62
                "description": "The current status of the action execution.",
63
                "type": "string",
64
                "enum": LIVEACTION_STATUSES
65
            },
66
            "start_timestamp": {
67
                "description": "The start time when the action is executed.",
68
                "type": "string",
69
                "pattern": isotime.ISO8601_UTC_REGEX
70
            },
71
            "end_timestamp": {
72
                "description": "The timestamp when the action has finished.",
73
                "type": "string",
74
                "pattern": isotime.ISO8601_UTC_REGEX
75
            },
76
            "parameters": {
77
                "description": "Input parameters for the action.",
78
                "type": "object",
79
                "patternProperties": {
80
                    "^\w+$": {
0 ignored issues
show
Bug introduced by
A suspicious escape sequence \w was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
81
                        "anyOf": [
82
                            {"type": "array"},
83
                            {"type": "boolean"},
84
                            {"type": "integer"},
85
                            {"type": "number"},
86
                            {"type": "object"},
87
                            {"type": "string"}
88
                        ]
89
                    }
90
                }
91
            },
92
            "context": {
93
                "type": "object"
94
            },
95
            "result": {
96
                "anyOf": [{"type": "array"},
97
                          {"type": "boolean"},
98
                          {"type": "integer"},
99
                          {"type": "number"},
100
                          {"type": "object"},
101
                          {"type": "string"}]
102
            },
103
            "parent": {"type": "string"},
104
            "children": {
105
                "type": "array",
106
                "items": {"type": "string"},
107
                "uniqueItems": True
108
            },
109
            "log": {
110
                "description": "Contains information about execution state transitions.",
111
                "type": "array",
112
                "items": {
113
                    "type": "object",
114
                    "properties": {
115
                        "timestamp": {
116
                            "type": "string",
117
                            "pattern": isotime.ISO8601_UTC_REGEX
118
                        },
119
                        "status": {
120
                            "type": "string",
121
                            "enum": LIVEACTION_STATUSES
122
                        }
123
                    }
124
                }
125
            }
126
        },
127
        "additionalProperties": False
128
    }
129
130
    @classmethod
131
    def from_model(cls, model, mask_secrets=False):
132
        doc = cls._from_model(model, mask_secrets=mask_secrets)
133
        start_timestamp = isotime.format(model.start_timestamp, offset=False)
134
        doc['start_timestamp'] = start_timestamp
135
136
        end_timestamp = model.end_timestamp
137
        if end_timestamp:
138
            end_timestamp = isotime.format(end_timestamp, offset=False)
139
            doc['end_timestamp'] = end_timestamp
140
141
        for entry in doc.get('log', []):
142
            entry['timestamp'] = isotime.format(entry['timestamp'], offset=False)
143
144
        attrs = {attr: value for attr, value in six.iteritems(doc) if value}
145
        return cls(**attrs)
146
147
    @classmethod
148
    def to_model(cls, instance):
149
        values = {}
150
        for attr, meta in six.iteritems(cls.schema.get('properties', dict())):
151
            default = copy.deepcopy(meta.get('default', None))
152
            value = getattr(instance, attr, default)
153
154
            # pylint: disable=no-member
155
            # TODO: Add plugin which lets pylint know each MongoEngine document has _fields
156
            # attribute
157
            if not value and not cls.model._fields[attr].required:
158
                continue
159
            if attr not in ActionExecutionAPI.SKIP:
160
                values[attr] = value
161
162
        values['start_timestamp'] = isotime.parse(instance.start_timestamp)
163
        values['end_timestamp'] = isotime.parse(instance.end_timestamp)
164
165
        model = cls.model(**values)
166
        return model
167