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