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 | |||
18 | from mongoengine.queryset import Q |
||
19 | |||
20 | from st2common import log as logging |
||
21 | from st2api.controllers.resource import BaseResourceIsolationControllerMixin |
||
22 | from st2api.controllers.resource import ContentPackResourceController |
||
23 | from st2common.models.api.rule import RuleViewAPI |
||
24 | from st2common.models.system.common import ResourceReference |
||
25 | from st2common.persistence.action import Action |
||
26 | from st2common.persistence.rule import Rule |
||
27 | from st2common.persistence.trigger import TriggerType, Trigger |
||
28 | from st2common.rbac.types import PermissionType |
||
29 | |||
30 | http_client = six.moves.http_client |
||
31 | |||
32 | LOG = logging.getLogger(__name__) |
||
33 | |||
34 | |||
35 | __all__ = ['RuleViewController'] |
||
36 | |||
37 | |||
38 | class RuleViewController(BaseResourceIsolationControllerMixin, ContentPackResourceController): |
||
39 | """ |
||
40 | Add some extras to a Rule object to make it easier for UI to render a rule. The additions |
||
41 | do not necessarily belong in the Rule itself but are still valuable augmentations. |
||
42 | |||
43 | :Example: |
||
44 | { |
||
45 | "action": { |
||
46 | "description": "Action that executes an arbitrary Linux command on the localhost.", |
||
47 | "parameters": { |
||
48 | "cmd": "echo \"{{trigger.executed_at}}\"" |
||
49 | }, |
||
50 | "ref": "core.local" |
||
51 | }, |
||
52 | "criteria": {}, |
||
53 | "description": "Sample rule using an Interval Timer.", |
||
54 | "enabled": false, |
||
55 | "id": "55ea221832ed35759cf3b312", |
||
56 | "name": "sample.with_timer", |
||
57 | "pack": "examples", |
||
58 | "ref": "examples.sample.with_timer", |
||
59 | "tags": [], |
||
60 | "trigger": { |
||
61 | "description": "Triggers on specified intervals. e.g. every 30s, 1week etc.", |
||
62 | "parameters": { |
||
63 | "delta": 5, |
||
64 | "unit": "seconds" |
||
65 | }, |
||
66 | "ref": "core.4ad65602-6fb4-4c89-b0f2-b990d7b68bad", |
||
67 | "type": "core.st2.IntervalTimer" |
||
68 | }, |
||
69 | "uid": "rule:examples:sample.with_timer" |
||
70 | } |
||
71 | |||
72 | The `description` fields in action and trigger are augmented properties. |
||
73 | """ |
||
74 | |||
75 | model = RuleViewAPI |
||
76 | access = Rule |
||
77 | supported_filters = { |
||
78 | 'name': 'name', |
||
79 | 'pack': 'pack', |
||
80 | 'user': 'context.user' |
||
81 | } |
||
82 | |||
83 | query_options = { |
||
84 | 'sort': ['pack', 'name'] |
||
85 | } |
||
86 | |||
87 | include_reference = True |
||
88 | |||
89 | def get_all(self, sort=None, offset=0, limit=None, requester_user=None, **raw_filters): |
||
90 | rules = super(RuleViewController, self)._get_all(sort=sort, |
||
91 | offset=offset, |
||
92 | limit=limit, |
||
93 | raw_filters=raw_filters, |
||
94 | requester_user=requester_user) |
||
95 | result = self._append_view_properties(rules.json) |
||
96 | rules.json = result |
||
97 | return rules |
||
98 | |||
99 | def get_one(self, ref_or_id, requester_user): |
||
100 | rule = self._get_one(ref_or_id, permission_type=PermissionType.RULE_VIEW, |
||
101 | requester_user=requester_user) |
||
102 | result = self._append_view_properties([rule.json])[0] |
||
103 | rule.json = result |
||
104 | return rule |
||
105 | |||
106 | def _append_view_properties(self, rules): |
||
107 | action_by_refs, trigger_by_refs, trigger_type_by_refs = self._get_referenced_models(rules) |
||
108 | |||
109 | for rule in rules: |
||
110 | action_db = action_by_refs.get(rule['action']['ref'], None) |
||
111 | rule['action']['description'] = action_db.description if action_db else '' |
||
112 | |||
113 | rule['trigger']['description'] = '' |
||
114 | |||
115 | trigger_db = trigger_by_refs.get(rule['trigger']['ref'], None) |
||
116 | if trigger_db: |
||
117 | rule['trigger']['description'] = trigger_db.description |
||
118 | |||
119 | # If description is not found in trigger get description from triggertype |
||
120 | if not rule['trigger']['description']: |
||
121 | trigger_type_db = trigger_type_by_refs.get(rule['trigger']['type'], None) |
||
122 | if trigger_type_db: |
||
123 | rule['trigger']['description'] = trigger_type_db.description |
||
124 | |||
125 | return rules |
||
126 | |||
127 | def _get_referenced_models(self, rules): |
||
128 | """ |
||
129 | Reduces the number of queries to be made to the DB by creating sets of Actions, Triggers |
||
130 | and TriggerTypes. |
||
131 | """ |
||
132 | action_refs = set() |
||
133 | trigger_refs = set() |
||
134 | trigger_type_refs = set() |
||
135 | |||
136 | for rule in rules: |
||
137 | action_refs.add(rule['action']['ref']) |
||
138 | trigger_refs.add(rule['trigger']['ref']) |
||
139 | trigger_type_refs.add(rule['trigger']['type']) |
||
140 | |||
141 | action_by_refs = {} |
||
142 | trigger_by_refs = {} |
||
143 | trigger_type_by_refs = {} |
||
144 | |||
145 | # The functions that will return args that can used to query. |
||
146 | def ref_query_args(ref): |
||
147 | return {'ref': ref} |
||
148 | |||
149 | def name_pack_query_args(ref): |
||
150 | resource_ref = ResourceReference.from_string_reference(ref=ref) |
||
151 | return {'name': resource_ref.name, 'pack': resource_ref.pack} |
||
152 | |||
153 | action_dbs = self._get_entities(model_persistence=Action, |
||
154 | refs=action_refs, |
||
155 | query_args=ref_query_args) |
||
156 | for action_db in action_dbs: |
||
157 | action_by_refs[action_db.ref] = action_db |
||
158 | |||
159 | trigger_dbs = self._get_entities(model_persistence=Trigger, |
||
160 | refs=trigger_refs, |
||
161 | query_args=name_pack_query_args) |
||
162 | for trigger_db in trigger_dbs: |
||
163 | trigger_by_refs[trigger_db.get_reference().ref] = trigger_db |
||
164 | |||
165 | trigger_type_dbs = self._get_entities(model_persistence=TriggerType, |
||
166 | refs=trigger_type_refs, |
||
167 | query_args=name_pack_query_args) |
||
168 | for trigger_type_db in trigger_type_dbs: |
||
169 | trigger_type_by_refs[trigger_type_db.get_reference().ref] = trigger_type_db |
||
170 | |||
171 | return (action_by_refs, trigger_by_refs, trigger_type_by_refs) |
||
172 | |||
173 | def _get_entities(self, model_persistence, refs, query_args): |
||
174 | """ |
||
175 | Returns all the entities for the supplied refs. model_persistence is the persistence |
||
176 | object that will be used to get to the correct query method and the query_args function |
||
177 | to return the ref specific query argument. |
||
178 | |||
179 | This is such a weirdly specific method that it is likely better only in this context. |
||
180 | """ |
||
181 | q = None |
||
182 | for ref in refs: |
||
183 | if not q: |
||
184 | q = Q(**query_args(ref)) |
||
185 | else: |
||
186 | q |= Q(**query_args(ref)) |
||
187 | if q: |
||
188 | return model_persistence._get_impl().model.objects(q) |
||
0 ignored issues
–
show
|
|||
189 | return [] |
||
190 | |||
191 | |||
192 | rule_view_controller = RuleViewController() |
||
193 |
Prefixing a member variable
_
is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class: