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

PackInstallController.post()   A

Complexity

Conditions 1

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
c 2
b 0
f 0
dl 0
loc 13
rs 9.4285
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
    @jsexpose(body_cls=PackInstallRequestAPI, status_code=http_client.ACCEPTED)
71
    def post(self, pack_install_request):
72
        parameters = {
73
            'packs': pack_install_request.packs
74
        }
75
76
        new_liveaction_api = LiveActionCreateAPI(action='packs.install',
77
                                                 parameters=parameters,
78
                                                 user=None)
79
80
        execution = self._handle_schedule_execution(liveaction_api=new_liveaction_api)
81
82
        return PackAsyncAPI(execution_id=execution.id)
83
84
85
class PackUninstallController(ActionExecutionsControllerMixin, RestController):
86
87
    @jsexpose(body_cls=PackInstallRequestAPI, arg_types=[str], status_code=http_client.ACCEPTED)
88
    def post(self, pack_uninstall_request, ref_or_id=None):
89
        if ref_or_id:
90
            parameters = {
91
                'packs': [ref_or_id]
92
            }
93
        else:
94
            parameters = {
95
                'packs': pack_uninstall_request.packs
96
            }
97
98
        new_liveaction_api = LiveActionCreateAPI(action='packs.uninstall',
99
                                                 parameters=parameters,
100
                                                 user=None)
101
102
        execution = self._handle_schedule_execution(liveaction_api=new_liveaction_api)
103
104
        return PackAsyncAPI(execution_id=execution.id)
105
106
107
class PackRegisterController(RestController):
108
109
    @jsexpose(body_cls=PackRegisterRequestAPI)
110
    def post(self, pack_register_request):
111
        if pack_register_request and hasattr(pack_register_request, 'types'):
112
            types = pack_register_request.types
113
        else:
114
            types = ['runner', 'action', 'trigger', 'sensor', 'rule', 'rule_type', 'alias',
115
                     'policy_type', 'policy', 'config']
116
117
        if pack_register_request and hasattr(pack_register_request, 'packs'):
118
            packs = pack_register_request.packs
119
        else:
120
            packs = None
121
122
        result = {}
123
124
        if 'runner' in types or 'action' in types:
125
            result['runners'] = runners_registrar.register_runners(experimental=True)
126
        if 'rule_type' in types or 'rule' in types:
127
            result['rule_types'] = rule_types_registrar.register_rule_types()
128
        if 'policy_type' in types or 'policy' in types:
129
            result['policy_types'] = policies_registrar.register_policy_types(st2common)
130
131
        use_pack_cache = True
132
133
        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...
134
            if type in types:
135
                registrar = Registrar(use_pack_cache=use_pack_cache,
136
                                      fail_on_failure=False)
137
                if packs:
138
                    for pack in packs:
139
                        pack_path = content_utils.get_pack_base_path(pack)
140
                        result[name] = registrar.register_from_pack(pack_dir=pack_path)
141
                else:
142
                    packs_base_paths = content_utils.get_packs_base_paths()
143
                    result[name] = registrar.register_from_packs(base_dirs=packs_base_paths)
144
145
        return result
146
147
148
class PackSearchController(RestController):
149
150
    @jsexpose(body_cls=PackSearchRequestAPI)
151
    def post(self, pack_search_request):
152
        if hasattr(pack_search_request, 'query'):
153
            packs = packs_service.search_pack_index(pack_search_request.query)
154
            return [PackAPI(**pack) for pack in packs]
155
        else:
156
            pack = packs_service.get_pack_from_index(pack_search_request.pack)
157
            return PackAPI(**pack) if pack else None
158
159
160
class IndexHealthController(RestController):
161
162
    @jsexpose()
163
    def get(self):
164
        """
165
        Check if all listed indexes are healthy: they should be reachable,
166
        return valid JSON objects, and yield more than one result.
167
        """
168
        _, status = packs_service.fetch_pack_index(allow_empty=True)
169
170
        health = {
171
            "indexes": {
172
                "count": len(status),
173
                "valid": 0,
174
                "invalid": 0,
175
                "errors": {},
176
                "status": status,
177
            },
178
            "packs": {
179
                "count": 0,
180
            },
181
        }
182
183
        for index in status:
184
            if index['error']:
185
                error_count = health['indexes']['errors'].get(index['error'], 0) + 1
186
                health['indexes']['invalid'] += 1
187
                health['indexes']['errors'][index['error']] = error_count
188
            else:
189
                health['indexes']['valid'] += 1
190
            health['packs']['count'] += index['packs']
191
192
        return health
193
194
195
class BasePacksController(ResourceController):
196
    model = PackAPI
197
    access = Pack
198
199
    def _get_one_by_ref_or_id(self, ref_or_id, exclude_fields=None):
200
        LOG.info('GET %s with ref_or_id=%s', pecan.request.path, ref_or_id)
201
202
        instance = self._get_by_ref_or_id(ref_or_id=ref_or_id, exclude_fields=exclude_fields)
203
204
        if not instance:
205
            msg = 'Unable to identify resource with ref_or_id "%s".' % (ref_or_id)
206
            pecan.abort(http_client.NOT_FOUND, msg)
207
            return
208
209
        from_model_kwargs = self._get_from_model_kwargs_for_request(request=pecan.request)
210
        result = self.model.from_model(instance, **from_model_kwargs)
211
        LOG.debug('GET %s with ref_or_id=%s, client_result=%s', pecan.request.path, ref_or_id,
212
                  result)
213
214
        return result
215
216
    def _get_by_ref_or_id(self, ref_or_id, exclude_fields=None):
217
        resource_db = self._get_by_id(resource_id=ref_or_id, exclude_fields=exclude_fields)
218
219
        if not resource_db:
220
            # Try ref
221
            resource_db = self._get_by_ref(ref=ref_or_id, exclude_fields=exclude_fields)
222
223
        return resource_db
224
225
    def _get_by_ref(self, ref, exclude_fields=None):
226
        """
227
        Note: In this case "ref" is pack name and not StackStorm's ResourceReference.
228
        """
229
        resource_db = self.access.query(ref=ref, exclude_fields=exclude_fields).first()
230
        return resource_db
231
232
233
class PacksController(BasePacksController):
234
    from st2api.controllers.v1.packviews import PackViewsController
235
236
    model = PackAPI
237
    access = Pack
238
    supported_filters = {
239
        'name': 'name',
240
        'ref': 'ref'
241
    }
242
243
    query_options = {
244
        'sort': ['ref']
245
    }
246
247
    # Nested controllers
248
    install = PackInstallController()
249
    uninstall = PackUninstallController()
250
    register = PackRegisterController()
251
    search = PackSearchController()
252
    views = PackViewsController()
253
    health = IndexHealthController()
254
255
    @request_user_has_permission(permission_type=PermissionType.PACK_LIST)
256
    @jsexpose()
257
    def get_all(self, **kwargs):
258
        return super(PacksController, self)._get_all(**kwargs)
259
260
    @request_user_has_resource_db_permission(permission_type=PermissionType.PACK_VIEW)
261
    @jsexpose(arg_types=[str])
262
    def get_one(self, ref_or_id):
263
        return self._get_one_by_ref_or_id(ref_or_id=ref_or_id)
264