Passed
Push — master ( 1b4105...c96172 )
by
unknown
04:10
created

PackSearchController._get_proxy_config()   A

Complexity

Conditions 1

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 17
rs 9.4285
c 0
b 0
f 0
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 os
17
import re
18
19
from collections import defaultdict
20
from collections import OrderedDict
21
22
import six
23
24
import st2common
25
from st2common import log as logging
26
from st2common.bootstrap.triggersregistrar import TriggersRegistrar
27
from st2common.bootstrap.sensorsregistrar import SensorsRegistrar
28
from st2common.bootstrap.actionsregistrar import ActionsRegistrar
29
from st2common.bootstrap.aliasesregistrar import AliasesRegistrar
30
from st2common.bootstrap.policiesregistrar import PolicyRegistrar
31
import st2common.bootstrap.policiesregistrar as policies_registrar
32
import st2common.bootstrap.runnersregistrar as runners_registrar
33
from st2common.bootstrap.rulesregistrar import RulesRegistrar
34
import st2common.bootstrap.ruletypesregistrar as rule_types_registrar
35
from st2common.bootstrap.configsregistrar import ConfigsRegistrar
36
import st2common.content.utils as content_utils
37
from st2common.models.api.action import LiveActionCreateAPI
38
from st2common.models.api.pack import PackAPI
39
from st2common.models.api.pack import PackAsyncAPI
40
from st2common.exceptions.db import StackStormDBObjectNotFoundError
41
from st2common.persistence.pack import Pack
42
from st2common.rbac.types import PermissionType
43
from st2common.rbac import utils as rbac_utils
44
from st2common.services import packs as packs_service
45
from st2common.router import abort
46
from st2common.router import Response
47
48
from st2api.controllers.resource import ResourceController
49
from st2api.controllers.v1.actionexecutions import ActionExecutionsControllerMixin
50
51
http_client = six.moves.http_client
52
53
__all__ = [
54
    'PacksController',
55
    'BasePacksController',
56
    'ENTITIES'
57
]
58
59
LOG = logging.getLogger(__name__)
60
61
# Note: The order those are defined it's important so they are registered in
62
# the same order as they are in st2-register-content.
63
# We also need to use list of tuples to preserve the order.
64
ENTITIES = OrderedDict([
65
    ('trigger', (TriggersRegistrar, 'triggers')),
66
    ('sensor', (SensorsRegistrar, 'sensors')),
67
    ('action', (ActionsRegistrar, 'actions')),
68
    ('rule', (RulesRegistrar, 'rules')),
69
    ('alias', (AliasesRegistrar, 'aliases')),
70
    ('policy', (PolicyRegistrar, 'policies')),
71
    ('config', (ConfigsRegistrar, 'configs'))
72
])
73
74
75
def _get_proxy_config():
76
    LOG.debug('Loading proxy configuration from env variables %s.', os.environ)
77
    http_proxy = os.environ.get('http_proxy', None)
78
    https_proxy = os.environ.get('https_proxy', None)
79
    no_proxy = os.environ.get('no_proxy', None)
80
    proxy_ca_bundle_path = os.environ.get('proxy_ca_bundle_path', None)
81
82
    proxy_config = {
83
        'http_proxy': http_proxy,
84
        'https_proxy': https_proxy,
85
        'proxy_ca_bundle_path': proxy_ca_bundle_path,
86
        'no_proxy': no_proxy
87
    }
88
89
    LOG.debug('Proxy configuration: %s', proxy_config)
90
91
    return proxy_config
92
93
94
class PackInstallController(ActionExecutionsControllerMixin):
95
96
    def post(self, pack_install_request):
97
        parameters = {
98
            'packs': pack_install_request.packs,
99
        }
100
101
        if pack_install_request.force:
102
            parameters['force'] = True
103
104
        new_liveaction_api = LiveActionCreateAPI(action='packs.install',
105
                                                 parameters=parameters,
106
                                                 user=None)
107
108
        execution_resp = self._handle_schedule_execution(liveaction_api=new_liveaction_api,
109
                                                         requester_user=None)
110
111
        exec_id = PackAsyncAPI(execution_id=execution_resp.json['id'])
112
113
        return Response(json=exec_id, status=http_client.ACCEPTED)
114
115
116
class PackUninstallController(ActionExecutionsControllerMixin):
117
118
    def post(self, pack_uninstall_request, ref_or_id=None):
119
        if ref_or_id:
120
            parameters = {
121
                'packs': [ref_or_id]
122
            }
123
        else:
124
            parameters = {
125
                'packs': pack_uninstall_request.packs
126
            }
127
128
        new_liveaction_api = LiveActionCreateAPI(action='packs.uninstall',
129
                                                 parameters=parameters,
130
                                                 user=None)
131
132
        execution_resp = self._handle_schedule_execution(liveaction_api=new_liveaction_api,
133
                                                         requester_user=None)
134
135
        exec_id = PackAsyncAPI(execution_id=execution_resp.json['id'])
136
137
        return Response(json=exec_id, status=http_client.ACCEPTED)
138
139
140
class PackRegisterController(object):
141
    CONTENT_TYPES = ['runner', 'action', 'trigger', 'sensor', 'rule',
142
                     'rule_type', 'alias', 'policy_type', 'policy', 'config']
143
144
    def post(self, pack_register_request):
145
        if pack_register_request and hasattr(pack_register_request, 'types'):
146
            types = pack_register_request.types
147
            if 'all' in types:
148
                types = PackRegisterController.CONTENT_TYPES
149
        else:
150
            types = PackRegisterController.CONTENT_TYPES
151
152
        if pack_register_request and hasattr(pack_register_request, 'packs'):
153
            packs = list(set(pack_register_request.packs))
154
        else:
155
            packs = None
156
157
        result = defaultdict(int)
158
159
        # Register depended resources (actions depend on runners, rules depend on rule types, etc)
160
        if ('runner' in types or 'runners' in types) or ('action' in types or 'actions' in types):
161
            result['runners'] = runners_registrar.register_runners(experimental=True)
162
        if ('rule_type' in types or 'rule_types' in types) or \
163
           ('rule' in types or 'rules' in types):
164
            result['rule_types'] = rule_types_registrar.register_rule_types()
165
        if ('policy_type' in types or 'policy_types' in types) or \
166
           ('policy' in types or 'policies' in types):
167
            result['policy_types'] = policies_registrar.register_policy_types(st2common)
168
169
        use_pack_cache = False
170
171
        fail_on_failure = getattr(pack_register_request, 'fail_on_failure', True)
172
        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...
173
            if type in types or name in types:
174
                registrar = Registrar(use_pack_cache=use_pack_cache,
175
                                      fail_on_failure=fail_on_failure)
176
                if packs:
177
                    for pack in packs:
178
                        pack_path = content_utils.get_pack_base_path(pack)
179
180
                        try:
181
                            registered_count = registrar.register_from_pack(pack_dir=pack_path)
182
                            result[name] += registered_count
183
                        except ValueError as e:
184
                            # Throw more user-friendly exception if requsted pack doesn't exist
185
                            if re.match('Directory ".*?" doesn\'t exist', str(e)):
186
                                msg = 'Pack "%s" not found on disk: %s' % (pack, str(e))
187
                                raise ValueError(msg)
188
189
                            raise e
190
                else:
191
                    packs_base_paths = content_utils.get_packs_base_paths()
192
                    registered_count = registrar.register_from_packs(base_dirs=packs_base_paths)
193
                    result[name] += registered_count
194
195
        return result
196
197
198
class PackSearchController(object):
199
200
    def post(self, pack_search_request):
201
202
        proxy_config = _get_proxy_config()
203
204
        if hasattr(pack_search_request, 'query'):
205
            packs = packs_service.search_pack_index(pack_search_request.query,
206
                                                    case_sensitive=False,
207
                                                    proxy_config=proxy_config)
208
            return [PackAPI(**pack) for pack in packs]
209
        else:
210
            pack = packs_service.get_pack_from_index(pack_search_request.pack,
211
                                                     proxy_config=proxy_config)
212
            return PackAPI(**pack) if pack else []
213
214
215
class IndexHealthController(object):
216
217
    def get(self):
218
        """
219
        Check if all listed indexes are healthy: they should be reachable,
220
        return valid JSON objects, and yield more than one result.
221
        """
222
        proxy_config = _get_proxy_config()
223
224
        _, status = packs_service.fetch_pack_index(allow_empty=True, proxy_config=proxy_config)
225
226
        health = {
227
            "indexes": {
228
                "count": len(status),
229
                "valid": 0,
230
                "invalid": 0,
231
                "errors": {},
232
                "status": status,
233
            },
234
            "packs": {
235
                "count": 0,
236
            },
237
        }
238
239
        for index in status:
240
            if index['error']:
241
                error_count = health['indexes']['errors'].get(index['error'], 0) + 1
242
                health['indexes']['invalid'] += 1
243
                health['indexes']['errors'][index['error']] = error_count
244
            else:
245
                health['indexes']['valid'] += 1
246
            health['packs']['count'] += index['packs']
247
248
        return health
249
250
251
class BasePacksController(ResourceController):
252
    model = PackAPI
253
    access = Pack
254
255
    def _get_one_by_ref_or_id(self, ref_or_id, requester_user, exclude_fields=None):
256
        instance = self._get_by_ref_or_id(ref_or_id=ref_or_id, exclude_fields=exclude_fields)
257
258
        rbac_utils.assert_user_has_resource_db_permission(user_db=requester_user,
259
                                                          resource_db=instance,
260
                                                          permission_type=PermissionType.PACK_VIEW)
261
262
        if not instance:
263
            msg = 'Unable to identify resource with ref_or_id "%s".' % (ref_or_id)
264
            abort(http_client.NOT_FOUND, msg)
265
            return
266
267
        result = self.model.from_model(instance, **self.from_model_kwargs)
268
269
        return result
270
271
    def _get_by_ref_or_id(self, ref_or_id, exclude_fields=None):
272
        resource_db = self._get_by_id(resource_id=ref_or_id, exclude_fields=exclude_fields)
273
274
        if not resource_db:
275
            # Try ref
276
            resource_db = self._get_by_ref(ref=ref_or_id, exclude_fields=exclude_fields)
277
278
        if not resource_db:
279
            msg = 'Resource with a ref or id "%s" not found' % (ref_or_id)
280
            raise StackStormDBObjectNotFoundError(msg)
281
282
        return resource_db
283
284
    def _get_by_ref(self, ref, exclude_fields=None):
285
        """
286
        Note: In this case "ref" is pack name and not StackStorm's ResourceReference.
287
        """
288
        resource_db = self.access.query(ref=ref, exclude_fields=exclude_fields).first()
289
        return resource_db
290
291
292
class PacksIndexController():
293
    search = PackSearchController()
294
    health = IndexHealthController()
295
296
    def get_all(self):
297
        proxy_config = _get_proxy_config()
298
299
        index, status = packs_service.fetch_pack_index(proxy_config=proxy_config)
300
301
        return {
302
            'status': status,
303
            'index': index
304
        }
305
306
307
class PacksController(BasePacksController):
308
    from st2api.controllers.v1.packviews import PackViewsController
309
310
    model = PackAPI
311
    access = Pack
312
    supported_filters = {
313
        'name': 'name',
314
        'ref': 'ref'
315
    }
316
317
    query_options = {
318
        'sort': ['ref']
319
    }
320
321
    # Nested controllers
322
    install = PackInstallController()
323
    uninstall = PackUninstallController()
324
    register = PackRegisterController()
325
    views = PackViewsController()
326
    index = PacksIndexController()
327
328
    def __init__(self):
329
        super(PacksController, self).__init__()
330
        self.get_one_db_method = self._get_by_ref_or_id
331
332
    def get_all(self, sort=None, offset=0, limit=None, **raw_filters):
333
        return super(PacksController, self)._get_all(sort=sort,
334
                                                     offset=offset,
335
                                                     limit=limit,
336
                                                     raw_filters=raw_filters)
337
338
    def get_one(self, ref_or_id, requester_user):
339
        return self._get_one_by_ref_or_id(ref_or_id=ref_or_id, requester_user=requester_user)
340
341
342
packs_controller = PacksController()
343