Fix the new base image to support helm cli ssh login
[pti/o2.git] / o2ims / views / ocloud_view.py
1 # Copyright (C) 2021 Wind River Systems, Inc.
2 #
3 #  Licensed under the Apache License, Version 2.0 (the "License");
4 #  you may not use this file except in compliance with the License.
5 #  You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 #  Unless required by applicable law or agreed to in writing, software
10 #  distributed under the License is distributed on an "AS IS" BASIS,
11 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 #  See the License for the specific language governing permissions and
13 #  limitations under the License.
14
15 import filecmp
16 import os.path
17 import uuid
18 import yaml
19 from datetime import datetime
20 import shutil
21
22 from o2common.service import unit_of_work
23 from o2common.config import config
24 from o2common.views.view import gen_filter, check_filter
25 from o2common.views.pagination_view import Pagination
26 from o2common.views.route_exception import BadRequestException, \
27     NotFoundException
28
29 from o2ims.domain import ocloud
30 from o2ims.views.ocloud_dto import SubscriptionDTO
31 from o2ims.domain.subscription_obj import Subscription
32
33 from o2common.helper import o2logging
34 logger = o2logging.get_logger(__name__)
35
36
37 def oclouds(uow: unit_of_work.AbstractUnitOfWork):
38     with uow:
39         li = uow.oclouds.list()
40     return [r.serialize() for r in li]
41
42
43 def ocloud_one(ocloudid: str, uow: unit_of_work.AbstractUnitOfWork):
44     with uow:
45         first = uow.oclouds.get(ocloudid)
46         return first.serialize() if first is not None else None
47
48
49 def resource_types(uow: unit_of_work.AbstractUnitOfWork, **kwargs):
50     pagination = Pagination(**kwargs)
51     query_kwargs = pagination.get_pagination()
52     args = gen_filter(ocloud.ResourceType,
53                       kwargs['filter']) if 'filter' in kwargs else []
54     with uow:
55         li = uow.resource_types.list_with_count(*args, **query_kwargs)
56     return pagination.get_result(li)
57
58
59 def resource_type_one(resourceTypeId: str,
60                       uow: unit_of_work.AbstractUnitOfWork):
61     with uow:
62         first = uow.resource_types.get(resourceTypeId)
63         return first.serialize() if first is not None else None
64
65
66 def resource_pools(uow: unit_of_work.AbstractUnitOfWork, **kwargs):
67     pagination = Pagination(**kwargs)
68     query_kwargs = pagination.get_pagination()
69     args = gen_filter(ocloud.ResourcePool,
70                       kwargs['filter']) if 'filter' in kwargs else []
71     with uow:
72         li = uow.resource_pools.list_with_count(*args, **query_kwargs)
73     return pagination.get_result(li)
74
75
76 def resource_pool_one(resourcePoolId: str,
77                       uow: unit_of_work.AbstractUnitOfWork):
78     with uow:
79         first = uow.resource_pools.get(resourcePoolId)
80         return first.serialize() if first else None
81
82
83 def resources(resourcePoolId: str, uow: unit_of_work.AbstractUnitOfWork,
84               **kwargs):
85     with uow:
86         first = uow.resource_pools.get(resourcePoolId)
87     if first is None:
88         raise NotFoundException("ResourcePool {} doesn't exist".format(
89             resourcePoolId))
90     pagination = Pagination(**kwargs)
91     # filter key should be the same with database name
92     query_kwargs = pagination.get_pagination()
93     if 'resourceTypeName' in kwargs:
94         resource_type_name = kwargs['resourceTypeName']
95         with uow:
96             # res_types = uow.resource_types.list()
97             # restype_ids = [
98             #     restype.resourceTypeId for restype in res_types
99             #     if resourceTypeName == restype.name]
100             # restype_id = '' if len(restype_ids) == 0 else restype_ids[0]
101             res_type = uow.resource_types.get_by_name(resource_type_name)
102             restype_id = '' if res_type is None else res_type.resourceTypeId
103         query_kwargs['resourceTypeId'] = restype_id
104     args = gen_filter(
105         ocloud.Resource, kwargs['filter']) if 'filter' in kwargs else []
106
107     if 'parentId' in kwargs:
108         query_kwargs['parentId'] = kwargs['parentId']
109     if 'sort' in kwargs:
110         query_kwargs['sort'] = kwargs['sort']
111
112     with uow:
113         ret = uow.resources.list_with_count(
114             resourcePoolId, *args, **query_kwargs)
115
116     return pagination.get_result(ret)
117
118
119 def resource_one(resourceId: str,
120                  uow: unit_of_work.AbstractUnitOfWork, resourcePoolId: str):
121     with uow:
122         resoucePool = uow.resource_pools.get(resourcePoolId)
123     if resoucePool is None:
124         raise NotFoundException("ResourcePool {} doesn't exist".format(
125             resourcePoolId))
126
127     first = uow.resources.get(resourceId)
128     if first is None:
129         raise NotFoundException("Resource {} doesn't exist".format(
130             resourceId))
131     return first.serialize()
132
133
134 def deployment_managers(uow: unit_of_work.AbstractUnitOfWork, **kwargs):
135     pagination = Pagination(**kwargs)
136     query_kwargs = pagination.get_pagination()
137     args = gen_filter(ocloud.DeploymentManager,
138                       kwargs['filter']) if 'filter' in kwargs else []
139     with uow:
140         li = uow.deployment_managers.list_with_count(*args, **query_kwargs)
141     return pagination.get_result(li)
142
143
144 def deployment_manager_one(deploymentManagerId: str,
145                            uow: unit_of_work.AbstractUnitOfWork,
146                            profile: str =
147                            ocloud.DeploymentManagerProfileDefault):
148     profile = profile.lower()
149     with uow:
150         first = uow.deployment_managers.get(deploymentManagerId)
151         if first is None:
152             return first
153         result = first.serialize()
154         if result is None:
155             return None
156
157     profile_data = result.pop("profile", None)
158     profiles = config.get_dms_support_profiles()
159     if profile not in profiles:
160         return ""
161
162     extensions = {
163         'profileName': profile
164     }
165     if ocloud.DeploymentManagerProfileDefault == profile \
166             or ocloud.DeploymentManagerProfileSOL018 == profile:
167         result['serviceUri'] = \
168             profile_data['cluster_api_endpoint']
169         extensions['profileData'] = profile_data
170     elif ocloud.DeploymentManagerProfileSOL018HelmCLI == profile:
171         result['serviceUri'] = \
172             profile_data['cluster_api_endpoint']
173
174         helmcli_profile = dict()
175         helmcli_profile["helmcli_host_with_port"], helmcli_profile[
176             "helmcli_username"], helmcli_profile["helmcli_password"] = \
177             config.get_helmcli_access()
178         helmcli_profile["helmcli_kubeconfig"] = _gen_kube_config(
179             deploymentManagerId, profile_data)
180         extensions['profileData'] = helmcli_profile
181     else:
182         return ""
183
184     result['extensions'] = extensions
185     return result
186
187
188 def _gen_kube_config(dmId: str, kubeconfig: dict) -> dict:
189     shared_folder = config.get_containers_shared_folder()
190
191     data = config.gen_k8s_config_dict(
192         kubeconfig.pop('cluster_api_endpoint', None),
193         kubeconfig.pop('cluster_ca_cert', None),
194         kubeconfig.pop('admin_user', None),
195         kubeconfig.pop('admin_client_cert', None),
196         kubeconfig.pop('admin_client_key', None),
197     )
198
199     # Generate a random key for tmp kube config file
200     # letters = string.ascii_uppercase
201     # random_key = ''.join(random.choice(letters) for i in range(10))
202     name_key = dmId[:8]
203
204     # Get datetime of now as tag of the tmp file
205     current_time = datetime.now().strftime("%Y%m%d%H%M%S")
206     tmp_file_name = 'kubeconfig_' + name_key + "_" + current_time
207     kube_config_name = 'kubeconfig_' + name_key + '.config'
208     kube_config_path = f'{shared_folder}/{kube_config_name}'
209
210     # write down the yaml file of kubectl into tmp folder
211     with open('/tmp/' + tmp_file_name, 'w') as file:
212         yaml.dump(data, file)
213
214     # generate the kube config file if not exist or update the file if it
215     # changes
216     if not os.path.exists(kube_config_path) or not \
217             filecmp.cmp('/tmp/'+tmp_file_name, kube_config_path):
218         shutil.move(os.path.join('/tmp', tmp_file_name),
219                     os.path.join(shared_folder, kube_config_name))
220
221     return kube_config_path
222
223
224 def subscriptions(uow: unit_of_work.AbstractUnitOfWork, **kwargs):
225     pagination = Pagination(**kwargs)
226     query_kwargs = pagination.get_pagination()
227     args = gen_filter(Subscription,
228                       kwargs['filter']) if 'filter' in kwargs else []
229     with uow:
230         li = uow.subscriptions.list_with_count(*args, **query_kwargs)
231     return pagination.get_result(li)
232
233
234 def subscription_one(subscriptionId: str,
235                      uow: unit_of_work.AbstractUnitOfWork):
236     with uow:
237         first = uow.subscriptions.get(subscriptionId)
238         return first.serialize() if first is not None else None
239
240
241 def subscription_create(subscriptionDto: SubscriptionDTO.subscription_create,
242                         uow: unit_of_work.AbstractUnitOfWork):
243     filter = subscriptionDto.get('filter', '')
244     consumer_subs_id = subscriptionDto.get('consumerSubscriptionId', '')
245
246     _check_subscription_filter(filter)
247
248     sub_uuid = str(uuid.uuid4())
249     subscription = Subscription(
250         sub_uuid, subscriptionDto['callback'],
251         consumer_subs_id, filter)
252     with uow:
253         args = list()
254         args.append(getattr(Subscription, 'callback')
255                     == subscriptionDto['callback'])
256         args.append(getattr(Subscription, 'filter') == filter)
257         args.append(getattr(Subscription,
258                     'consumerSubscriptionId') == consumer_subs_id)
259         count, _ = uow.subscriptions.list_with_count(*args)
260         if count > 0:
261             raise BadRequestException("The value of parameters is duplicated")
262         uow.subscriptions.add(subscription)
263         uow.commit()
264         first = uow.subscriptions.get(sub_uuid)
265         return first.serialize()
266
267
268 def _check_subscription_filter(filter: str):
269     if not filter:
270         return
271
272     def _sub_filter_checking(sub_filter: str):
273         exprs = sub_filter.split(';')
274         objectType = False
275         objectTypeValue = ''
276         for expr in exprs:
277             expr_strip = expr.strip(' ()')
278             items = expr_strip.split(',')
279             if len(items) < 3:
280                 raise BadRequestException("invalid filter {}".format(expr))
281             item_key = items[1].strip()
282             if item_key != 'objectType':
283                 continue
284             item_op = items[0].strip()
285             if item_op != 'eq':
286                 raise BadRequestException(
287                     "Filter objectType only support 'eq' operation")
288             objectType = True
289             objectTypeValue = items[2].strip()
290         if not objectType:
291             # if there has no objectType specific, by default is ResourceInfo
292             check_filter(ocloud.Resource, sub_filter)
293             # return 'ResourceInfo'
294             return
295         if objectTypeValue == 'ResourceTypeInfo':
296             check_filter(ocloud.ResourceType, sub_filter)
297         elif objectTypeValue == 'ResourcePoolInfo':
298             check_filter(ocloud.ResourcePool, sub_filter)
299         elif objectTypeValue == 'DeploymentManagerInfo':
300             check_filter(ocloud.DeploymentManager, sub_filter)
301         elif objectTypeValue == 'CloudInfo':
302             check_filter(ocloud.Ocloud, sub_filter)
303         elif objectTypeValue == 'ResourceInfo':
304             check_filter(ocloud.Resource, sub_filter)
305         else:
306             raise BadRequestException(
307                 "Filter ObjectType {} not support.".format(items[2]))
308         # return objectTypeValue
309     filter_strip = filter.strip(' []')
310     filter_list = filter_strip.split('|')
311     # check_duplication = dict()
312     for sub_filter in filter_list:
313         _sub_filter_checking(sub_filter)
314         # obj_type = _sub_filter_checking(sub_filter)
315         # if obj_type not in check_duplication:
316         #     check_duplication[obj_type] = 0
317         # check_duplication[obj_type] += 1
318         # if check_duplication[obj_type] > 1:
319         #     raise BadRequestException(
320         #         "Filter objectType {} only support one in each."
321         #         .format(obj_type))
322
323
324 def subscription_delete(subscriptionId: str,
325                         uow: unit_of_work.AbstractUnitOfWork):
326     with uow:
327         first = uow.subscriptions.get(subscriptionId)
328         if not first:
329             raise NotFoundException(
330                 "Subscription {} not found.".format(subscriptionId))
331         uow.subscriptions.delete(subscriptionId)
332         uow.commit()
333     return True