|
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 six |
|
17
|
|
|
import string |
|
18
|
|
|
|
|
19
|
|
|
from st2common.util import schema as util_schema |
|
20
|
|
|
from st2common.models.api.notification import NotificationSubSchemaAPI |
|
21
|
|
|
|
|
22
|
|
|
|
|
23
|
|
|
class Node(object): |
|
24
|
|
|
|
|
25
|
|
|
schema = { |
|
26
|
|
|
"title": "Node", |
|
27
|
|
|
"description": "Node of an ActionChain.", |
|
28
|
|
|
"type": "object", |
|
29
|
|
|
"properties": { |
|
30
|
|
|
"name": { |
|
31
|
|
|
"description": "The name of this node.", |
|
32
|
|
|
"type": "string", |
|
33
|
|
|
"required": True |
|
34
|
|
|
}, |
|
35
|
|
|
"ref": { |
|
36
|
|
|
"type": "string", |
|
37
|
|
|
"description": "Ref of the action to be executed.", |
|
38
|
|
|
"required": True |
|
39
|
|
|
}, |
|
40
|
|
|
"params": { |
|
41
|
|
|
"type": "object", |
|
42
|
|
|
"description": ("Parameter for the execution (old name, here for backward " |
|
43
|
|
|
"compatibility reasons)."), |
|
44
|
|
|
"default": {} |
|
45
|
|
|
}, |
|
46
|
|
|
"parameters": { |
|
47
|
|
|
"type": "object", |
|
48
|
|
|
"description": "Parameter for the execution.", |
|
49
|
|
|
"default": {} |
|
50
|
|
|
}, |
|
51
|
|
|
"on-success": { |
|
52
|
|
|
"type": "string", |
|
53
|
|
|
"description": "Name of the node to invoke on successful completion of action" |
|
54
|
|
|
" executed for this node.", |
|
55
|
|
|
"default": "" |
|
56
|
|
|
}, |
|
57
|
|
|
"on-failure": { |
|
58
|
|
|
"type": "string", |
|
59
|
|
|
"description": "Name of the node to invoke on failure of action executed for this" |
|
60
|
|
|
" node.", |
|
61
|
|
|
"default": "" |
|
62
|
|
|
}, |
|
63
|
|
|
"publish": { |
|
64
|
|
|
"description": "The variables to publish from the result. Should be of the form" |
|
65
|
|
|
" name.foo. o1: {{node_name.foo}} will result in creation of a" |
|
66
|
|
|
" variable o1 which is now available for reference through" |
|
67
|
|
|
" remainder of the chain as a global variable.", |
|
68
|
|
|
"type": "object", |
|
69
|
|
|
"patternProperties": { |
|
70
|
|
|
"^\w+$": {} |
|
|
|
|
|
|
71
|
|
|
} |
|
72
|
|
|
}, |
|
73
|
|
|
"notify": { |
|
74
|
|
|
"description": "Notification settings for action.", |
|
75
|
|
|
"type": "object", |
|
76
|
|
|
"properties": { |
|
77
|
|
|
"on-complete": NotificationSubSchemaAPI, |
|
78
|
|
|
"on-failure": NotificationSubSchemaAPI, |
|
79
|
|
|
"on-success": NotificationSubSchemaAPI |
|
80
|
|
|
}, |
|
81
|
|
|
"additionalProperties": False |
|
82
|
|
|
} |
|
83
|
|
|
}, |
|
84
|
|
|
"additionalProperties": False |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
def __init__(self, **kw): |
|
88
|
|
|
for prop in six.iterkeys(self.schema.get('properties', [])): |
|
89
|
|
|
value = kw.get(prop, None) |
|
90
|
|
|
# having '-' in the property name lead to challenges in referencing the property. |
|
91
|
|
|
# At hindsight the schema property should've been on_success rather than on-success. |
|
92
|
|
|
prop = string.replace(prop, '-', '_') |
|
93
|
|
|
setattr(self, prop, value) |
|
94
|
|
|
|
|
95
|
|
|
def validate(self): |
|
96
|
|
|
params = getattr(self, 'params', {}) |
|
97
|
|
|
parameters = getattr(self, 'parameters', {}) |
|
98
|
|
|
|
|
99
|
|
|
if params and parameters: |
|
100
|
|
|
msg = ('Either "params" or "parameters" attribute needs to be provided, but not ' |
|
101
|
|
|
'both') |
|
102
|
|
|
raise ValueError(msg) |
|
103
|
|
|
|
|
104
|
|
|
return self |
|
105
|
|
|
|
|
106
|
|
|
def get_parameters(self): |
|
107
|
|
|
# Note: "params" is old deprecated attribute which will be removed in a future release |
|
108
|
|
|
params = getattr(self, 'params', {}) |
|
109
|
|
|
parameters = getattr(self, 'parameters', {}) |
|
110
|
|
|
|
|
111
|
|
|
return parameters or params |
|
112
|
|
|
|
|
113
|
|
|
def __repr__(self): |
|
114
|
|
|
return ('<Node name=%s, ref=%s, on-success=%s, on-failure=%s>' % |
|
115
|
|
|
(self.name, self.ref, self.on_success, self.on_failure)) |
|
116
|
|
|
|
|
117
|
|
|
|
|
118
|
|
|
class ActionChain(object): |
|
119
|
|
|
|
|
120
|
|
|
schema = { |
|
121
|
|
|
"title": "ActionChain", |
|
122
|
|
|
"description": "A chain of sequentially executed actions.", |
|
123
|
|
|
"type": "object", |
|
124
|
|
|
"properties": { |
|
125
|
|
|
"chain": { |
|
126
|
|
|
"description": "The chain.", |
|
127
|
|
|
"type": "array", |
|
128
|
|
|
"items": [Node.schema], |
|
129
|
|
|
"required": True |
|
130
|
|
|
}, |
|
131
|
|
|
"default": { |
|
132
|
|
|
"type": "string", |
|
133
|
|
|
"description": "name of the action to be executed." |
|
134
|
|
|
}, |
|
135
|
|
|
"vars": { |
|
136
|
|
|
"description": "", |
|
137
|
|
|
"type": "object", |
|
138
|
|
|
"patternProperties": { |
|
139
|
|
|
"^\w+$": {} |
|
|
|
|
|
|
140
|
|
|
} |
|
141
|
|
|
} |
|
142
|
|
|
}, |
|
143
|
|
|
"additionalProperties": False |
|
144
|
|
|
} |
|
145
|
|
|
|
|
146
|
|
|
def __init__(self, **kw): |
|
147
|
|
|
util_schema.validate(instance=kw, schema=self.schema, cls=util_schema.CustomValidator, |
|
148
|
|
|
use_default=False, allow_default_none=True) |
|
149
|
|
|
|
|
150
|
|
|
for prop in six.iterkeys(self.schema.get('properties', [])): |
|
151
|
|
|
value = kw.get(prop, None) |
|
152
|
|
|
# special handling for chain property to create the Node object |
|
153
|
|
|
if prop == 'chain': |
|
154
|
|
|
nodes = [] |
|
155
|
|
|
for node in value: |
|
156
|
|
|
ac_node = Node(**node) |
|
157
|
|
|
ac_node.validate() |
|
158
|
|
|
nodes.append(ac_node) |
|
159
|
|
|
value = nodes |
|
160
|
|
|
setattr(self, prop, value) |
|
161
|
|
|
|
Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with
rorRare 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.