35188aa7f686b7a7a0b09e43282b7e6438b84a88
[pti/o2.git] / o2ims / adapter / clients / ocloud_client.py
1 # Copyright (C) 2022 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 # client talking to Stx standalone
16
17 import uuid
18 from o2common.service.client.base_client import BaseClient
19 from typing import List
20 # Optional,  Set
21 from o2ims.domain import stx_object as ocloudModel
22 from o2common.config import config
23 from o2ims.domain.resource_type import ResourceTypeEnum
24
25 # from dcmanagerclient.api import client
26 from cgtsclient.client import get_client as get_stx_client
27 from cgtsclient.exc import EndpointException
28 from dcmanagerclient.api.client import client as get_dc_client
29
30 from o2common.helper import o2logging
31 logger = o2logging.get_logger(__name__)
32
33
34 CGTSCLIENT_ENDPOINT_ERROR_MSG = \
35     'Must provide Keystone credentials or user-defined endpoint and token'
36
37
38 class StxOcloudClient(BaseClient):
39     def __init__(self, driver=None):
40         super().__init__()
41         self.driver = driver if driver else StxClientImp()
42
43     def _get(self, id) -> ocloudModel.StxGenericModel:
44         return self.driver.getInstanceInfo()
45
46     def _list(self, **filters):
47         return [self.driver.getInstanceInfo()]
48
49     def _set_stx_client(self):
50         pass
51
52
53 class StxResourcePoolClient(BaseClient):
54     def __init__(self):
55         super().__init__()
56         self.driver = StxClientImp()
57
58     def _get(self, id) -> ocloudModel.StxGenericModel:
59         return self.driver.getResourcePoolDetail(id)
60
61     def _list(self, **filters):
62         return self.driver.getResourcePoolList(**filters)
63
64     def _set_stx_client(self):
65         pass
66
67
68 class StxDmsClient(BaseClient):
69     def __init__(self):
70         super().__init__()
71         self.driver = StxClientImp()
72
73     def _get(self, name) -> ocloudModel.StxGenericModel:
74         return self.driver.getK8sDetail(name)
75
76     def _list(self, **filters):
77         return self.driver.getK8sList(**filters)
78
79     def _set_stx_client(self):
80         pass
81
82
83 class StxPserverClient(BaseClient):
84     def __init__(self):
85         super().__init__()
86         self.driver = StxClientImp()
87
88     def _get(self, id) -> ocloudModel.StxGenericModel:
89         return self.driver.getPserver(id)
90
91     def _list(self, **filters) -> List[ocloudModel.StxGenericModel]:
92         filters['resourcepoolid']
93         return self.driver.getPserverList(**filters)
94
95     def _set_stx_client(self):
96         self.driver.setStxClient(self._pool_id)
97
98
99 class StxCpuClient(BaseClient):
100     def __init__(self):
101         super().__init__()
102         # self._pserver_id = pserver_id
103         self.driver = StxClientImp()
104
105     def _get(self, id) -> ocloudModel.StxGenericModel:
106         return self.driver.getCpu(id)
107
108     def _list(self, **filters) -> List[ocloudModel.StxGenericModel]:
109         return self.driver.getCpuList(**filters)
110
111     def _set_stx_client(self):
112         self.driver.setStxClient(self._pool_id)
113
114
115 class StxMemClient(BaseClient):
116     def __init__(self):
117         super().__init__()
118         self.driver = StxClientImp()
119
120     def _get(self, id) -> ocloudModel.StxGenericModel:
121         return self.driver.getMem(id)
122
123     def _list(self, **filters) -> List[ocloudModel.StxGenericModel]:
124         return self.driver.getMemList(**filters)
125
126     def _set_stx_client(self):
127         self.driver.setStxClient(self._pool_id)
128
129
130 class StxEthClient(BaseClient):
131     def __init__(self):
132         super().__init__()
133         self.driver = StxClientImp()
134
135     def _get(self, id) -> ocloudModel.StxGenericModel:
136         return self.driver.getEthernet(id)
137
138     def _list(self, **filters) -> List[ocloudModel.StxGenericModel]:
139         return self.driver.getEthernetList(**filters)
140
141     def _set_stx_client(self):
142         self.driver.setStxClient(self._pool_id)
143
144
145 class StxIfClient(BaseClient):
146     def __init__(self):
147         super().__init__()
148         self.driver = StxClientImp()
149
150     def _get(self, id) -> ocloudModel.StxGenericModel:
151         return self.driver.getIf(id)
152
153     def _list(self, **filters) -> List[ocloudModel.StxGenericModel]:
154         return self.driver.getIfList(**filters)
155
156     def _set_stx_client(self):
157         self.driver.setStxClient(self._pool_id)
158
159
160 class StxIfPortClient(BaseClient):
161     def __init__(self):
162         super().__init__()
163         self.driver = StxClientImp()
164
165     def _get(self, id) -> ocloudModel.StxGenericModel:
166         return self.driver.getPort(id)
167
168     def _list(self, **filters) -> List[ocloudModel.StxGenericModel]:
169         return self.driver.getPortList(**filters)
170
171     def _set_stx_client(self):
172         self.driver.setStxClient(self._pool_id)
173
174
175 class StxDevClient(BaseClient):
176     def __init__(self):
177         super().__init__()
178         self.driver = StxClientImp()
179
180     def _get(self, id) -> ocloudModel.StxGenericModel:
181         return self.driver.getDevice(id)
182
183     def _list(self, **filters) -> List[ocloudModel.StxGenericModel]:
184         return self.driver.getDeviceList(**filters)
185
186     def _set_stx_client(self):
187         self.driver.setStxClient(self._pool_id)
188
189
190 class StxAccClient(BaseClient):
191     def __init__(self):
192         super().__init__()
193         self.driver = StxClientImp()
194
195     def _get(self, id) -> ocloudModel.StxGenericModel:
196         return self.driver.getAccelerator(id)
197
198     def _list(self, **filters) -> List[ocloudModel.StxGenericModel]:
199         return self.driver.getAcceleratorList(**filters)
200
201     def _set_stx_client(self):
202         self.driver.setStxClient(self._pool_id)
203
204
205 # internal driver which implement client call to Stx Standalone and DC instance
206 class StxClientImp(object):
207     def __init__(self, stx_client=None, dc_client=None):
208         super().__init__()
209         self.stxclient = stx_client if stx_client else self.getStxClient()
210         self.dcclient = dc_client if dc_client else self.getDcmanagerClient()
211         # if subcloud_id is not None:
212         # self.stxclient = self.getSubcloudClient(subcloud_id)
213
214     def getStxClient(self):
215         os_client_args = config.get_stx_access_info()
216         config_client = get_stx_client(**os_client_args)
217         return config_client
218
219     def getDcmanagerClient(self):
220         os_client_args = config.get_dc_access_info()
221         config_client = get_dc_client(**os_client_args)
222         return config_client
223
224     def getSubcloudClient(self, subcloud_id):
225         subcloud = self.dcclient.subcloud_manager.\
226             subcloud_additional_details(subcloud_id)
227         logger.debug('subcloud name: %s, oam_floating_ip: %s' %
228                      (subcloud[0].name, subcloud[0].oam_floating_ip))
229         try:
230             os_client_args = config.get_stx_access_info(
231                 region_name=subcloud[0].name,
232                 subcloud_hostname=subcloud[0].oam_floating_ip)
233             logger.info(os_client_args)
234             config_client = get_stx_client(**os_client_args)
235         except EndpointException as e:
236             msg = e.format_message()
237             if CGTSCLIENT_ENDPOINT_ERROR_MSG in msg:
238                 os_client_args = config.get_stx_access_info(
239                     region_name=subcloud[0].name, sub_is_https=True,
240                     subcloud_hostname=subcloud[0].oam_floating_ip)
241                 logger.info(os_client_args)
242                 config_client = get_stx_client(**os_client_args)
243             else:
244                 raise ValueError('Stx endpoint exception: %s' % msg)
245         except Exception:
246             raise ValueError('cgtsclient get subcloud client failed')
247
248         return config_client
249
250     def setStxClient(self, resource_pool_id):
251         systems = self.stxclient.isystem.list()
252         if resource_pool_id == systems[0].uuid:
253             logger.debug('Stx Client not change: %s' % resource_pool_id)
254             return
255
256         subclouds = self.getSubcloudList()
257         for subcloud in subclouds:
258             subcloud_stxclient = self.getSubcloudClient(subcloud.subcloud_id)
259             systems = subcloud_stxclient.isystem.list()
260             # logger.debug('subcloud %s id: %s' %
261             #  (systems[0].name, systems[0].uuid))
262             # logger.debug('subcloud: %s' % (systems[0].to_dict()))
263             if resource_pool_id == systems[0].uuid:
264                 self.stxclient = subcloud_stxclient
265
266     def getInstanceInfo(self) -> ocloudModel.StxGenericModel:
267         systems = self.stxclient.isystem.list()
268         logger.debug('systems:' + str(systems[0].to_dict()))
269         # logger.debug('systems[0] uuid: ' + str(systems[0].uuid))
270         return ocloudModel.StxGenericModel(
271             ResourceTypeEnum.OCLOUD, systems[0]) if systems else None
272
273     def getSubcloudList(self):
274         subs = self.dcclient.subcloud_manager.list_subclouds()
275         known_subs = [sub for sub in subs if sub.sync_status != 'unknown']
276         return known_subs
277
278     def getResourcePoolList(self, **filters) -> List[
279             ocloudModel.StxGenericModel]:
280         systems = self.stxclient.isystem.list()
281         logger.debug('system controller distributed_cloud_role:' +
282                      str(systems[0].distributed_cloud_role))
283
284         if systems[0].distributed_cloud_role is None or \
285                 systems[0].distributed_cloud_role != 'systemcontroller':
286             return [ocloudModel.StxGenericModel(
287                 ResourceTypeEnum.RESOURCE_POOL, systems[0])]
288
289         pools = []
290         if config.get_system_controller_as_respool():
291             pools.append(systems[0])
292
293         subclouds = self.getSubcloudList()
294         logger.debug('subclouds numbers: %s' % len(subclouds))
295         for subcloud in subclouds:
296             try:
297                 subcloud_stxclient = self.getSubcloudClient(
298                     subcloud.subcloud_id)
299                 systems = subcloud_stxclient.isystem.list()
300                 logger.debug('systems:' + str(systems[0].to_dict()))
301                 pools.append(systems[0])
302             except Exception as ex:
303                 logger.warning('Failed get cgstclient of subcloud %s: %s' %
304                                (subcloud.name, ex))
305                 continue
306
307         return [ocloudModel.StxGenericModel(
308             ResourceTypeEnum.RESOURCE_POOL,
309             respool) for respool in pools if respool]
310
311     def getResourcePoolDetail(self, id):
312         self.setStxClient(id)
313         systems = self.stxclient.isystem.list()
314         logger.debug('systems:' + str(systems[0].to_dict()))
315         return ocloudModel.StxGenericModel(
316             ResourceTypeEnum.RESOURCE_POOL, systems[0]) if systems else None
317
318     def getPserverList(self, **filters) -> List[ocloudModel.StxGenericModel]:
319         hosts = self.stxclient.ihost.list()
320         logger.debug('host 1:' + str(hosts[0].to_dict()))
321         return [ocloudModel.StxGenericModel(
322             ResourceTypeEnum.PSERVER, self._hostconverter(host))
323             for host in hosts if host and (host.availability == 'available'
324                                            or host.availability == 'degraded')]
325
326     def getPserver(self, id) -> ocloudModel.StxGenericModel:
327         host = self.stxclient.ihost.get(id)
328         logger.debug('host:' + str(host.to_dict()))
329         return ocloudModel.StxGenericModel(
330             ResourceTypeEnum.PSERVER, self._hostconverter(host))
331
332     def getK8sList(self, **filters) -> List[ocloudModel.StxGenericModel]:
333         systems = self.stxclient.isystem.list()
334         logger.debug('system controller distributed_cloud_role:' +
335                      str(systems[0].distributed_cloud_role))
336
337         if systems[0].distributed_cloud_role is None or \
338                 systems[0].distributed_cloud_role != 'systemcontroller':
339             k8sclusters = self.stxclient.kube_cluster.list()
340             setattr(k8sclusters[0], 'cloud_name', systems[0].name)
341             logger.debug('k8sresources[0]:' + str(k8sclusters[0].to_dict()))
342             # logger.debug('k8sresources[0] cluster_api_endpoint: ' +
343             #  str(k8sclusters[0].cluster_api_endpoint))
344             return [ocloudModel.StxGenericModel(
345                 ResourceTypeEnum.DMS,
346                 self._k8sconverter(k8sres), self._k8shasher(k8sres))
347                 for k8sres in k8sclusters if k8sres]
348
349         k8s_list = []
350         if config.get_system_controller_as_respool():
351             k8sclusters = self.stxclient.kube_cluster.list()
352             setattr(k8sclusters[0], 'cloud_name', systems[0].name)
353             logger.debug('k8sresources[0]:' + str(k8sclusters[0].to_dict()))
354             # logger.debug('k8sresources[0] cluster_api_endpoint: ' +
355             #  str(k8sclusters[0].cluster_api_endpoint))
356             k8s_list.append(k8sclusters[0])
357
358         subclouds = self.getSubcloudList()
359         logger.debug('subclouds numbers: %s' % len(subclouds))
360         for subcloud in subclouds:
361             try:
362                 subcloud_stxclient = self.getSubcloudClient(
363                     subcloud.subcloud_id)
364                 systems = subcloud_stxclient.isystem.list()
365                 k8sclusters = subcloud_stxclient.kube_cluster.list()
366                 setattr(k8sclusters[0], 'cloud_name', systems[0].name)
367                 logger.debug('k8sresources[0]:' +
368                              str(k8sclusters[0].to_dict()))
369                 # logger.debug('k8sresources[0] cluster_api_endpoint: ' +
370                 #  str(k8sclusters[0].cluster_api_endpoint))
371                 k8s_list.append(k8sclusters[0])
372             except Exception as ex:
373                 logger.warning('Failed get cgstclient of subcloud %s: %s' %
374                                (subcloud.name, ex))
375                 continue
376
377         return [ocloudModel.StxGenericModel(ResourceTypeEnum.DMS,
378                 self._k8sconverter(k8sres), self._k8shasher(k8sres))
379                 for k8sres in k8s_list if k8sres]
380
381     def getK8sDetail(self, name) -> ocloudModel.StxGenericModel:
382         systems = self.stxclient.isystem.list()
383         if not name:
384             k8sclusters = self.stxclient.kube_cluster.list()
385             # logger.debug("k8sresources[0]:" + str(k8sclusters[0].to_dict()))
386             setattr(k8sclusters[0], 'cloud_name', systems[0].name)
387             k8scluster = k8sclusters.pop()
388         else:
389             sname = name.split('.')
390             cloud_name = '.'.join(sname[:-1])
391             k8s_name = sname[-1]
392             if cloud_name == systems[0].name:
393                 k8scluster = self.stxclient.kube_cluster.get(k8s_name)
394                 setattr(k8scluster, 'cloud_name', cloud_name)
395             else:
396                 subclouds = self.getSubcloudList()
397                 subcloud_id = [
398                     sub.subcloud_id for sub in subclouds
399                     if sub.name == cloud_name][0]
400                 subcloud_stxclient = self.getSubcloudClient(subcloud_id)
401                 k8scluster = subcloud_stxclient.kube_cluster.get(k8s_name)
402                 setattr(k8scluster, 'cloud_name', cloud_name)
403                 # logger.debug('k8sresources[0]:' +
404                 #  str(k8sclusters[0].to_dict()))
405                 # logger.debug('k8sresources[0] cluster_api_endpoint: ' +
406                 #  str(k8sclusters[0].cluster_api_endpoint))
407
408         if not k8scluster:
409             return None
410         logger.debug('k8sresource:' + str(k8scluster.to_dict()))
411         return ocloudModel.StxGenericModel(
412             ResourceTypeEnum.DMS,
413             self._k8sconverter(k8scluster), self._k8shasher(k8scluster))
414
415     def getCpuList(self, **filters) -> List[ocloudModel.StxGenericModel]:
416         hostid = filters.get('hostid', None)
417         assert (hostid is not None), 'missing hostid to query icpu list'
418         cpulist = self.stxclient.icpu.list(hostid)
419         return [ocloudModel.StxGenericModel(
420             ResourceTypeEnum.PSERVER_CPU,
421             self._cpuconverter(cpures)) for cpures in cpulist if cpures]
422
423     def getCpu(self, id) -> ocloudModel.StxGenericModel:
424         cpuinfo = self.stxclient.icpu.get(id)
425         return ocloudModel.StxGenericModel(
426             ResourceTypeEnum.PSERVER_CPU, self._cpuconverter(cpuinfo))
427
428     def getMemList(self, **filters) -> List[ocloudModel.StxGenericModel]:
429         hostid = filters.get('hostid', None)
430         assert (hostid is not None), 'missing hostid to query imem list'
431         memlist = self.stxclient.imemory.list(hostid)
432         return [ocloudModel.StxGenericModel(
433             ResourceTypeEnum.PSERVER_RAM,
434             self._memconverter(memories)) for memories in memlist if memories]
435
436     def getMem(self, id) -> ocloudModel.StxGenericModel:
437         meminfo = self.stxclient.imemory.get(id)
438         return ocloudModel.StxGenericModel(
439             ResourceTypeEnum.PSERVER_RAM, self._memconverter(meminfo))
440
441     def getEthernetList(self, **filters) -> List[ocloudModel.StxGenericModel]:
442         hostid = filters.get('hostid', None)
443         assert (hostid is not None), 'missing hostid to query port list'
444         ethlist = self.stxclient.ethernet_port.list(hostid)
445         return [ocloudModel.StxGenericModel(
446             ResourceTypeEnum.PSERVER_ETH,
447             self._ethconverter(eth)) for eth in ethlist if eth]
448
449     def getEthernet(self, id) -> ocloudModel.StxGenericModel:
450         ethinfo = self.stxclient.ethernet_port.get(id)
451         return ocloudModel.StxGenericModel(
452             ResourceTypeEnum.PSERVER_ETH, self._ethconverter(ethinfo))
453
454     def getIfList(self, **filters) -> List[ocloudModel.StxGenericModel]:
455         hostid = filters.get('hostid', None)
456         assert (hostid is not None), 'missing hostid to query iinterface list'
457         iflist = self.stxclient.iinterface.list(hostid)
458         return [ocloudModel.StxGenericModel(
459             ResourceTypeEnum.PSERVER_IF,
460             self._ifconverter(ifs)) for ifs in iflist if ifs]
461
462     def getIf(self, id) -> ocloudModel.StxGenericModel:
463         ifinfo = self.stxclient.iinterface.get(id)
464         return ocloudModel.StxGenericModel(
465             ResourceTypeEnum.PSERVER_IF, self._ifconverter(ifinfo))
466
467     def getPortList(self, **filters) -> List[ocloudModel.StxGenericModel]:
468         ifid = filters.get('interfaceid', None)
469         assert (ifid is not None), 'missing interface id to query port list'
470         portlist = self.stxclient.iinterface.list_ports(ifid)
471         return [ocloudModel.StxGenericModel(
472             ResourceTypeEnum.PSERVER_IF_PORT,
473             port) for port in portlist if port]
474
475     def getPort(self, id) -> ocloudModel.StxGenericModel:
476         portinfo = self.stxclient.port.get(id)
477         return ocloudModel.StxGenericModel(
478             ResourceTypeEnum.PSERVER_IF_PORT, portinfo)
479
480     def getDeviceList(self, **filters) -> List[ocloudModel.StxGenericModel]:
481         hostid = filters.get('hostid', None)
482         assert (hostid is not None), 'missing hostid to query pci device list'
483         pci_dev_list = self.stxclient.pci_device.list(hostid)
484         return [ocloudModel.StxGenericModel(
485             ResourceTypeEnum.PSERVER_PCI_DEV,
486             self._devconverter(pci_dev))
487             for pci_dev in pci_dev_list if pci_dev]
488
489     def getDevice(self, id) -> ocloudModel.StxGenericModel:
490         pciinfo = self.stxclient.pci_device.get(id)
491         return ocloudModel.StxGenericModel(
492             ResourceTypeEnum.PSERVER_PCI_DEV, self._devconverter(pciinfo))
493
494     def getAcceleratorList(self, **filters) -> \
495             List[ocloudModel.StxGenericModel]:
496         hostid = filters.get('hostid', None)
497         assert (hostid is not None), 'missing hostid to query accelerator list'
498         pci_dev_list = self.stxclient.pci_device.list(hostid)
499         acc_list = []
500         for pci_dev in pci_dev_list:
501             if pci_dev.pvendor_id in ['8086']:
502                 if pci_dev.pdevice_id in ['0d5c', '0d5d']:
503                     logger.info('Accelerator vendor ID: {}, device ID: {}'.
504                                 format(pci_dev.pvendor_id, pci_dev.pdevice_id))
505                     acc_list.append(ocloudModel.StxGenericModel(
506                         ResourceTypeEnum.PSERVER_ACC,
507                         self._devconverter(pci_dev)))
508         return acc_list
509
510     def getAccelerator(self, id) -> ocloudModel.StxGenericModel:
511         pciinfo = self.stxclient.pci_device.get(id)
512         return ocloudModel.StxGenericModel(
513             ResourceTypeEnum.PSERVER_ACC, self._devconverter(pciinfo))
514
515     def _getIsystems(self):
516         return self.stxclient.isystem.list()
517
518     def _getIsystem(self, id=None):
519         if id:
520             return self.stxclient.isystem.get(id)
521         else:
522             isystems = self.stxclient.isystem.list()
523             if len(isystems) != 1 and not id:
524                 raise Exception('No system uuid was provided and '
525                                 'more than one system exists in the account.')
526             return isystems[0]
527
528     @ staticmethod
529     def _hostconverter(host):
530         setattr(host, 'name', host.hostname)
531         return host
532
533     @ staticmethod
534     def _cpuconverter(cpu):
535         setattr(cpu, 'name', cpu.ihost_uuid.split(
536             '-', 1)[0] + '-cpu-'+str(cpu.cpu))
537         return cpu
538
539     @ staticmethod
540     def _memconverter(mem):
541         setattr(mem, 'name', mem.ihost_uuid.split('-', 1)[0] +
542                 '-mem-node-'+str(mem.numa_node))
543         return mem
544
545     @ staticmethod
546     def _ethconverter(eth):
547         setattr(eth, 'name', eth.host_uuid.split('-', 1)[0] + '-'+eth.name)
548         setattr(eth, 'updated_at', None)
549         setattr(eth, 'created_at', None)
550         return eth
551
552     @ staticmethod
553     def _ifconverter(ifs):
554         setattr(ifs, 'name', ifs.ihost_uuid.split('-', 1)[0] + '-'+ifs.ifname)
555         setattr(ifs, 'updated_at', None)
556         setattr(ifs, 'created_at', None)
557         return ifs
558
559     @ staticmethod
560     def _devconverter(dev):
561         setattr(dev, 'name', dev.host_uuid.split('-', 1)[0] + '-'+dev.name)
562         return dev
563
564     @ staticmethod
565     def _k8sconverter(cluster):
566         setattr(cluster, 'name', cluster.cloud_name +
567                 '.' + cluster.cluster_name)
568         setattr(cluster, 'uuid',
569                 uuid.uuid3(uuid.NAMESPACE_URL, cluster.name))
570         setattr(cluster, 'updated_at', None)
571         setattr(cluster, 'created_at', None)
572         setattr(cluster, 'events', [])
573         logger.debug('k8s cluster name/uuid:' +
574                      cluster.name + '/' + str(cluster.uuid))
575         return cluster
576
577     @ staticmethod
578     def _k8shasher(cluster):
579         return str(hash((cluster.cluster_name, cluster.cloud_name,
580                          cluster.cluster_api_endpoint, cluster.admin_user)))