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