Completed
Pull Request — master (#2842)
by Edward
05:40
created

PackInstallController   A

Complexity

Total Complexity 1

Size/Duplication

Total Lines 16
Duplicated Lines 0 %

Importance

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

1 Method

Rating   Name   Duplication   Size   Complexity  
A post() 0 14 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 pecan
17
from pecan.rest import RestController
18
import six
19
20
import st2common
21
from st2common import log as logging
22
from st2common.bootstrap.triggersregistrar import TriggersRegistrar
23
from st2common.bootstrap.sensorsregistrar import SensorsRegistrar
24
from st2common.bootstrap.actionsregistrar import ActionsRegistrar
25
from st2common.bootstrap.aliasesregistrar import AliasesRegistrar
26
from st2common.bootstrap.policiesregistrar import PolicyRegistrar
27
import st2common.bootstrap.policiesregistrar as policies_registrar
28
import st2common.bootstrap.runnersregistrar as runners_registrar
29
from st2common.bootstrap.rulesregistrar import RulesRegistrar
30
import st2common.bootstrap.ruletypesregistrar as rule_types_registrar
31
from st2common.bootstrap.configsregistrar import ConfigsRegistrar
32
import st2common.content.utils as content_utils
33
from st2common.models.api.base import jsexpose
34
from st2api.controllers.resource import ResourceController
35
from st2api.controllers.v1.actionexecutions import ActionExecutionsControllerMixin
36
from st2common.models.api.action import LiveActionCreateAPI
37
from st2common.models.api.pack import PackAPI
38
from st2common.models.api.pack import PackInstallRequestAPI
39
from st2common.models.api.pack import PackRegisterRequestAPI
40
from st2common.models.api.pack import PackSearchRequestAPI
41
from st2common.models.api.pack import PackAsyncAPI
42
from st2common.persistence.pack import Pack
43
from st2common.rbac.types import PermissionType
44
from st2common.rbac.decorators import request_user_has_permission
45
from st2common.rbac.decorators import request_user_has_resource_db_permission
46
from st2common.services import packs as packs_service
47
48
http_client = six.moves.http_client
49
50
__all__ = [
51
    'PacksController',
52
    'BasePacksController'
53
]
54
55
LOG = logging.getLogger(__name__)
56
57
ENTITIES = {
58
    'action': (ActionsRegistrar, 'actions'),
59
    'trigger': (TriggersRegistrar, 'triggers'),
60
    'sensor': (SensorsRegistrar, 'sensors'),
61
    'rule': (RulesRegistrar, 'rules'),
62
    'alias': (AliasesRegistrar, 'aliases'),
63
    'policy': (PolicyRegistrar, 'policy'),
64
    'config': (ConfigsRegistrar, 'config')
65
}
66
67
68
class PackInstallController(ActionExecutionsControllerMixin, RestController):
69
70
    @request_user_has_permission(permission_type=PermissionType.PACK_INSTALL)
71
    @jsexpose(body_cls=PackInstallRequestAPI, status_code=http_client.ACCEPTED)
72
    def post(self, pack_install_request):
73
        parameters = {
74
            'packs': pack_install_request.packs
75
        }
76
77
        new_liveaction_api = LiveActionCreateAPI(action='packs.install',
78
                                                 parameters=parameters,
79
                                                 user=None)
80
81
        execution = self._handle_schedule_execution(liveaction_api=new_liveaction_api)
82
83
        return PackAsyncAPI(execution_id=execution.id)
84
85
86
class PackUninstallController(ActionExecutionsControllerMixin, RestController):
87
88
    @request_user_has_permission(permission_type=PermissionType.PACK_UNINSTALL)
89
    @jsexpose(body_cls=PackInstallRequestAPI, arg_types=[str], status_code=http_client.ACCEPTED)
90
    def post(self, pack_uninstall_request, ref_or_id=None):
91
        if ref_or_id:
92
            parameters = {
93
                'packs': [ref_or_id]
94
            }
95
        else:
96
            parameters = {
97
                'packs': pack_uninstall_request.packs
98
            }
99
100
        new_liveaction_api = LiveActionCreateAPI(action='packs.uninstall',
101
                                                 parameters=parameters,
102
                                                 user=None)
103
104
        execution = self._handle_schedule_execution(liveaction_api=new_liveaction_api)
105
106
        return PackAsyncAPI(execution_id=execution.id)
107
108
109
class PackRegisterController(RestController):
110
111
    @request_user_has_permission(permission_type=PermissionType.PACK_REGISTER)
112
    @jsexpose(body_cls=PackRegisterRequestAPI)
113
    def post(self, pack_register_request):
114
        if pack_register_request and hasattr(pack_register_request, 'types'):
115
            types = pack_register_request.types
116
        else:
117
            types = ['runner', 'action', 'trigger', 'sensor', 'rule', 'rule_type', 'alias',
118
                     'policy_type', 'policy', 'config']
119
120
        if pack_register_request and hasattr(pack_register_request, 'packs'):
121
            packs = pack_register_request.packs
122
        else:
123
            packs = None
124
125
        result = {}
126
127
        if 'runner' in types or 'action' in types:
128
            result['runners'] = runners_registrar.register_runners(experimental=True)
129
        if 'rule_type' in types or 'rule' in types:
130
            result['rule_types'] = rule_types_registrar.register_rule_types()
131
        if 'policy_type' in types or 'policy' in types:
132
            result['policy_types'] = policies_registrar.register_policy_types(st2common)
133
134
        use_pack_cache = True
135
136
        for type, (Registrar, name) in six.iteritems(ENTITIES):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in type.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
137
            if type in types:
138
                registrar = Registrar(use_pack_cache=use_pack_cache,
139
                                      fail_on_failure=False)
140
                if packs:
141
                    for pack in packs:
142
                        pack_path = content_utils.get_pack_base_path(pack)
143
                        result[name] = registrar.register_from_pack(pack_dir=pack_path)
144
                else:
145
                    packs_base_paths = content_utils.get_packs_base_paths()
146
                    result[name] = registrar.register_from_packs(base_dirs=packs_base_paths)
147
148
        return result
149
150
151
class PackSearchController(RestController):
152
153
    @request_user_has_permission(permission_type=PermissionType.PACK_SEARCH)
154
    @jsexpose(body_cls=PackSearchRequestAPI)
155
    def post(self, pack_search_request):
156
        if hasattr(pack_search_request, 'query'):
157
            packs = packs_service.search_pack_index(pack_search_request.query)
158
            return [PackAPI(**pack) for pack in packs]
159
        else:
160
            pack = packs_service.get_pack_from_index(pack_search_request.pack)
161
            return PackAPI(**pack) if pack else None
162
163
164
class IndexHealthController(RestController):
165
166
    @request_user_has_permission(permission_type=PermissionType.PACK_VIEW_INDEX_HEALTH)
167
    @jsexpose()
168
    def get(self):
169
        """
170
        Check if all listed indexes are healthy: they should be reachable,
171
        return valid JSON objects, and yield more than one result.
172
        """
173
        _, status = packs_service.fetch_pack_index(allow_empty=True)
174
175
        health = {
176
            "indexes": {
177
                "count": len(status),
178
                "valid": 0,
179
                "invalid": 0,
180
                "errors": {},
181
                "status": status,
182
            },
183
            "packs": {
184
                "count": 0,
185
            },
186
        }
187
188
        for index in status:
189
            if index['error']:
190
                error_count = health['indexes']['errors'].get(index['error'], 0) + 1
191
                health['indexes']['invalid'] += 1
192
                health['indexes']['errors'][index['error']] = error_count
193
            else:
194
                health['indexes']['valid'] += 1
195
            health['packs']['count'] += index['packs']
196
197
        return health
198
199
200
class BasePacksController(ResourceController):
201
    model = PackAPI
202
    access = Pack
203
204
    def _get_one_by_ref_or_id(self, ref_or_id, exclude_fields=None):
205
        LOG.info('GET %s with ref_or_id=%s', pecan.request.path, ref_or_id)
206
207
        instance = self._get_by_ref_or_id(ref_or_id=ref_or_id, exclude_fields=exclude_fields)
208
209
        if not instance:
210
            msg = 'Unable to identify resource with ref_or_id "%s".' % (ref_or_id)
211
            pecan.abort(http_client.NOT_FOUND, msg)
212
            return
213
214
        from_model_kwargs = self._get_from_model_kwargs_for_request(request=pecan.request)
215
        result = self.model.from_model(instance, **from_model_kwargs)
216
        LOG.debug('GET %s with ref_or_id=%s, client_result=%s', pecan.request.path, ref_or_id,
217
                  result)
218
219
        return result
220
221
    def _get_by_ref_or_id(self, ref_or_id, exclude_fields=None):
222
        resource_db = self._get_by_id(resource_id=ref_or_id, exclude_fields=exclude_fields)
223
224
        if not resource_db:
225
            # Try ref
226
            resource_db = self._get_by_ref(ref=ref_or_id, exclude_fields=exclude_fields)
227
228
        return resource_db
229
230
    def _get_by_ref(self, ref, exclude_fields=None):
231
        """
232
        Note: In this case "ref" is pack name and not StackStorm's ResourceReference.
233
        """
234
        resource_db = self.access.query(ref=ref, exclude_fields=exclude_fields).first()
235
        return resource_db
236
237
238
class PacksIndexController(RestController):
239
    search = PackSearchController()
240
    health = IndexHealthController()
241
242
243
class PacksController(BasePacksController):
244
    from st2api.controllers.v1.packviews import PackViewsController
245
246
    model = PackAPI
247
    access = Pack
248
    supported_filters = {
249
        'name': 'name',
250
        'ref': 'ref'
251
    }
252
253
    query_options = {
254
        'sort': ['ref']
255
    }
256
257
    # Nested controllers
258
    install = PackInstallController()
259
    uninstall = PackUninstallController()
260
    register = PackRegisterController()
261
    views = PackViewsController()
262
    index = PacksIndexController()
263
264
    @request_user_has_permission(permission_type=PermissionType.PACK_LIST)
265
    @jsexpose()
266
    def get_all(self, **kwargs):
267
        return super(PacksController, self)._get_all(**kwargs)
268
269
    @request_user_has_resource_db_permission(permission_type=PermissionType.PACK_VIEW)
270
    @jsexpose(arg_types=[str])
271
    def get_one(self, ref_or_id):
272
        return self._get_one_by_ref_or_id(ref_or_id=ref_or_id)
273