Updated distcloud for subcloud region_name changes
[pti/o2.git] / o2ims / adapter / clients / ocloud_client.py
index 35188aa..4e8430f 100644 (file)
 # client talking to Stx standalone
 
 import uuid
-from o2common.service.client.base_client import BaseClient
+import json
 from typing import List
 # Optional,  Set
-from o2ims.domain import stx_object as ocloudModel
-from o2common.config import config
-from o2ims.domain.resource_type import ResourceTypeEnum
 
-# from dcmanagerclient.api import client
 from cgtsclient.client import get_client as get_stx_client
 from cgtsclient.exc import EndpointException
 from dcmanagerclient.api.client import client as get_dc_client
 
+from o2common.config import config
+from o2common.service.client.base_client import BaseClient
+from o2ims.domain import stx_object as ocloudModel
+from o2ims.domain.resource_type import ResourceTypeEnum
+
 from o2common.helper import o2logging
 logger = o2logging.get_logger(__name__)
 
@@ -43,7 +44,7 @@ class StxOcloudClient(BaseClient):
     def _get(self, id) -> ocloudModel.StxGenericModel:
         return self.driver.getInstanceInfo()
 
-    def _list(self, **filters):
+    def _list(self, **filters) -> List[ocloudModel.StxGenericModel]:
         return [self.driver.getInstanceInfo()]
 
     def _set_stx_client(self):
@@ -58,7 +59,7 @@ class StxResourcePoolClient(BaseClient):
     def _get(self, id) -> ocloudModel.StxGenericModel:
         return self.driver.getResourcePoolDetail(id)
 
-    def _list(self, **filters):
+    def _list(self, **filters) -> List[ocloudModel.StxGenericModel]:
         return self.driver.getResourcePoolList(**filters)
 
     def _set_stx_client(self):
@@ -73,7 +74,7 @@ class StxDmsClient(BaseClient):
     def _get(self, name) -> ocloudModel.StxGenericModel:
         return self.driver.getK8sDetail(name)
 
-    def _list(self, **filters):
+    def _list(self, **filters) -> List[ocloudModel.StxGenericModel]:
         return self.driver.getK8sList(**filters)
 
     def _set_stx_client(self):
@@ -89,7 +90,6 @@ class StxPserverClient(BaseClient):
         return self.driver.getPserver(id)
 
     def _list(self, **filters) -> List[ocloudModel.StxGenericModel]:
-        filters['resourcepoolid']
         return self.driver.getPserverList(**filters)
 
     def _set_stx_client(self):
@@ -226,19 +226,21 @@ class StxClientImp(object):
             subcloud_additional_details(subcloud_id)
         logger.debug('subcloud name: %s, oam_floating_ip: %s' %
                      (subcloud[0].name, subcloud[0].oam_floating_ip))
+        if subcloud[0].oam_floating_ip == 'unavailable':
+            raise EnvironmentError(f"{subcloud[0].name} was unavailable")
         try:
             os_client_args = config.get_stx_access_info(
-                region_name=subcloud[0].name,
+                region_name=subcloud[0].region_name,
                 subcloud_hostname=subcloud[0].oam_floating_ip)
-            logger.info(os_client_args)
+            logger.info(os_client_args)
             config_client = get_stx_client(**os_client_args)
         except EndpointException as e:
             msg = e.format_message()
             if CGTSCLIENT_ENDPOINT_ERROR_MSG in msg:
                 os_client_args = config.get_stx_access_info(
-                    region_name=subcloud[0].name, sub_is_https=True,
+                    region_name=subcloud[0].region_name, sub_is_https=True,
                     subcloud_hostname=subcloud[0].oam_floating_ip)
-                logger.info(os_client_args)
+                logger.info(os_client_args)
                 config_client = get_stx_client(**os_client_args)
             else:
                 raise ValueError('Stx endpoint exception: %s' % msg)
@@ -271,6 +273,7 @@ class StxClientImp(object):
             ResourceTypeEnum.OCLOUD, systems[0]) if systems else None
 
     def getSubcloudList(self):
+        self.dcclient = self.getDcmanagerClient()
         subs = self.dcclient.subcloud_manager.list_subclouds()
         known_subs = [sub for sub in subs if sub.sync_status != 'unknown']
         return known_subs
@@ -284,7 +287,8 @@ class StxClientImp(object):
         if systems[0].distributed_cloud_role is None or \
                 systems[0].distributed_cloud_role != 'systemcontroller':
             return [ocloudModel.StxGenericModel(
-                ResourceTypeEnum.RESOURCE_POOL, systems[0])]
+                ResourceTypeEnum.RESOURCE_POOL,
+                self._respoolconverter(systems[0]))]
 
         pools = []
         if config.get_system_controller_as_respool():
@@ -306,14 +310,16 @@ class StxClientImp(object):
 
         return [ocloudModel.StxGenericModel(
             ResourceTypeEnum.RESOURCE_POOL,
-            respool) for respool in pools if respool]
+                self._respoolconverter(
+                    respool)) for respool in pools if respool]
 
     def getResourcePoolDetail(self, id):
         self.setStxClient(id)
         systems = self.stxclient.isystem.list()
         logger.debug('systems:' + str(systems[0].to_dict()))
         return ocloudModel.StxGenericModel(
-            ResourceTypeEnum.RESOURCE_POOL, systems[0]) if systems else None
+            ResourceTypeEnum.RESOURCE_POOL,
+            self._respoolconverter(systems[0])) if systems else None
 
     def getPserverList(self, **filters) -> List[ocloudModel.StxGenericModel]:
         hosts = self.stxclient.ihost.list()
@@ -321,6 +327,7 @@ class StxClientImp(object):
         return [ocloudModel.StxGenericModel(
             ResourceTypeEnum.PSERVER, self._hostconverter(host))
             for host in hosts if host and (host.availability == 'available'
+                                           or host.availability == 'online'
                                            or host.availability == 'degraded')]
 
     def getPserver(self, id) -> ocloudModel.StxGenericModel:
@@ -329,88 +336,147 @@ class StxClientImp(object):
         return ocloudModel.StxGenericModel(
             ResourceTypeEnum.PSERVER, self._hostconverter(host))
 
+    def _checkLabelExistOnHost(self, client, label_to_check, host_id,
+                               check_value=False) -> bool:
+        labels = client.label.list(host_id)
+        if check_value:
+            return any(label_to_check['key'] == label.label_key and
+                       label_to_check['value'] == label.label_value
+                       for label in labels)
+        else:
+            return any(label_to_check['key'] == label.label_key
+                       for label in labels)
+
+    def _checkLabelExistOnCluster(self, client, label_to_check,
+                                  check_value=False) -> bool:
+        hosts = client.ihost.list()
+        for host in hosts:
+            if self._checkLabelExistOnHost(client, label_to_check,
+                                           host.uuid, check_value):
+                if check_value:
+                    logger.info(
+                        f"host {host.hostname} has the label "
+                        f"{label_to_check['key']} with value "
+                        f"{label_to_check['value']}")
+                else:
+                    logger.info(
+                        f"host {host.hostname} has the label "
+                        f"{label_to_check['key']}")
+                return True
+        return False
+
+    def _setK8sCapabilities(self, client, k8scluster):
+        capabilities = {}
+        label_OS_2chk = {'key': 'OS', 'value': 'low_latency'}
+        if self._checkLabelExistOnCluster(client, label_OS_2chk, True):
+            logger.debug("low latency host inside of the k8s cluster")
+            capabilities[label_OS_2chk['key']] = label_OS_2chk['value']
+        setattr(k8scluster, 'capabilities', json.dumps(capabilities))
+        return k8scluster
+
+    def getLabelList(self, **filters) -> List[ocloudModel.StxGenericModel]:
+        hostid = filters.get('hostid', None)
+        assert (hostid is not None), 'missing hostid to query label list'
+        labels = self.stxclient.label.list(hostid)
+        return [ocloudModel.StxGenericModel(
+            ResourceTypeEnum.PSERVER_LABEL,
+            self._labelconverter(label)) for label in labels if label]
+
     def getK8sList(self, **filters) -> List[ocloudModel.StxGenericModel]:
-        systems = self.stxclient.isystem.list()
-        logger.debug('system controller distributed_cloud_role:' +
-                     str(systems[0].distributed_cloud_role))
+        def process_cluster(client, cluster):
+            setattr(cluster, 'cloud_name', systems[0].name)
+            setattr(cluster, 'cloud_uuid', systems[0].uuid)
+            cluster = self._setK8sCapabilities(client, cluster)
+            logger.debug('k8sresources cluster_api_endpoint: ' +
+                         str(cluster.cluster_api_endpoint))
+            return ocloudModel.StxGenericModel(ResourceTypeEnum.DMS,
+                                               self._k8sconverter(cluster),
+                                               self._k8shasher(cluster))
 
-        if systems[0].distributed_cloud_role is None or \
-                systems[0].distributed_cloud_role != 'systemcontroller':
-            k8sclusters = self.stxclient.kube_cluster.list()
-            setattr(k8sclusters[0], 'cloud_name', systems[0].name)
-            logger.debug('k8sresources[0]:' + str(k8sclusters[0].to_dict()))
-            # logger.debug('k8sresources[0] cluster_api_endpoint: ' +
-            #  str(k8sclusters[0].cluster_api_endpoint))
-            return [ocloudModel.StxGenericModel(
-                ResourceTypeEnum.DMS,
-                self._k8sconverter(k8sres), self._k8shasher(k8sres))
-                for k8sres in k8sclusters if k8sres]
+        systems = self.stxclient.isystem.list()
+        distributed_cloud_role = systems[0].distributed_cloud_role
+        logger.debug((
+            f'system controller distributed_cloud_role: '
+            f'{distributed_cloud_role}'))
 
         k8s_list = []
+
+        if distributed_cloud_role is None or distributed_cloud_role != \
+                'systemcontroller':
+            k8s_list.extend(
+                [process_cluster(self.stxclient, k8s)
+                 for k8s in self.stxclient.kube_cluster.list() if k8s])
+            return k8s_list
+
         if config.get_system_controller_as_respool():
-            k8sclusters = self.stxclient.kube_cluster.list()
-            setattr(k8sclusters[0], 'cloud_name', systems[0].name)
-            logger.debug('k8sresources[0]:' + str(k8sclusters[0].to_dict()))
-            # logger.debug('k8sresources[0] cluster_api_endpoint: ' +
-            #  str(k8sclusters[0].cluster_api_endpoint))
-            k8s_list.append(k8sclusters[0])
+            k8s_list.extend(
+                [process_cluster(self.stxclient, k8s)
+                 for k8s in self.stxclient.kube_cluster.list() if k8s])
 
         subclouds = self.getSubcloudList()
-        logger.debug('subclouds numbers: %s' % len(subclouds))
+        logger.debug(f'subclouds numbers: {len(subclouds)}')
+
         for subcloud in subclouds:
             try:
                 subcloud_stxclient = self.getSubcloudClient(
                     subcloud.subcloud_id)
                 systems = subcloud_stxclient.isystem.list()
                 k8sclusters = subcloud_stxclient.kube_cluster.list()
-                setattr(k8sclusters[0], 'cloud_name', systems[0].name)
-                logger.debug('k8sresources[0]:' +
-                             str(k8sclusters[0].to_dict()))
-                # logger.debug('k8sresources[0] cluster_api_endpoint: ' +
-                #  str(k8sclusters[0].cluster_api_endpoint))
-                k8s_list.append(k8sclusters[0])
+                k8s_list.extend([process_cluster(subcloud_stxclient, k8s)
+                                for k8s in k8sclusters if k8s])
             except Exception as ex:
-                logger.warning('Failed get cgstclient of subcloud %s: %s' %
-                               (subcloud.name, ex))
+                logger.warning((
+                    f'Failed to get cgstclient of subcloud '
+                    f'{subcloud.name}: {ex}'))
                 continue
 
-        return [ocloudModel.StxGenericModel(ResourceTypeEnum.DMS,
-                self._k8sconverter(k8sres), self._k8shasher(k8sres))
-                for k8sres in k8s_list if k8sres]
+        return k8s_list
 
     def getK8sDetail(self, name) -> ocloudModel.StxGenericModel:
+        def process_k8s_cluster(client, k8s_cluster, cloud_name, cloud_uuid):
+            setattr(k8s_cluster, 'cloud_name', cloud_name)
+            setattr(k8s_cluster, 'cloud_uuid', cloud_uuid)
+            k8s_cluster = self._setK8sCapabilities(client, k8s_cluster)
+            return k8s_cluster
+
         systems = self.stxclient.isystem.list()
+        system_name = systems[0].name
+        system_uuid = systems[0].uuid
+
         if not name:
-            k8sclusters = self.stxclient.kube_cluster.list()
-            # logger.debug("k8sresources[0]:" + str(k8sclusters[0].to_dict()))
-            setattr(k8sclusters[0], 'cloud_name', systems[0].name)
-            k8scluster = k8sclusters.pop()
+            k8s_clusters = self.stxclient.kube_cluster.list()
+            k8s_cluster = process_k8s_cluster(
+                self.stxclient, k8s_clusters.pop(), system_name)
         else:
             sname = name.split('.')
             cloud_name = '.'.join(sname[:-1])
             k8s_name = sname[-1]
-            if cloud_name == systems[0].name:
-                k8scluster = self.stxclient.kube_cluster.get(k8s_name)
-                setattr(k8scluster, 'cloud_name', cloud_name)
+
+            if cloud_name == system_name:
+                k8s_cluster = process_k8s_cluster(
+                    self.stxclient,
+                    self.stxclient.kube_cluster.get(k8s_name), cloud_name,
+                    system_uuid)
             else:
                 subclouds = self.getSubcloudList()
-                subcloud_id = [
+                subcloud_id = next(
                     sub.subcloud_id for sub in subclouds
-                    if sub.name == cloud_name][0]
+                    if sub.name == cloud_name)
                 subcloud_stxclient = self.getSubcloudClient(subcloud_id)
-                k8scluster = subcloud_stxclient.kube_cluster.get(k8s_name)
-                setattr(k8scluster, 'cloud_name', cloud_name)
-                # logger.debug('k8sresources[0]:' +
-                #  str(k8sclusters[0].to_dict()))
-                # logger.debug('k8sresources[0] cluster_api_endpoint: ' +
-                #  str(k8sclusters[0].cluster_api_endpoint))
-
-        if not k8scluster:
+                systems = subcloud_stxclient.isystem.list()
+                system_uuid = systems[0].uuid
+                k8s_cluster = process_k8s_cluster(
+                    subcloud_stxclient,
+                    subcloud_stxclient.kube_cluster.get(k8s_name), cloud_name,
+                    system_uuid)
+
+        if not k8s_cluster:
             return None
-        logger.debug('k8sresource:' + str(k8scluster.to_dict()))
+
+        logger.debug(f'k8sresource: {k8s_cluster.to_dict()}')
         return ocloudModel.StxGenericModel(
-            ResourceTypeEnum.DMS,
-            self._k8sconverter(k8scluster), self._k8shasher(k8scluster))
+            ResourceTypeEnum.DMS, self._k8sconverter(k8s_cluster),
+            self._k8shasher(k8s_cluster))
 
     def getCpuList(self, **filters) -> List[ocloudModel.StxGenericModel]:
         hostid = filters.get('hostid', None)
@@ -525,25 +591,88 @@ class StxClientImp(object):
                                 'more than one system exists in the account.')
             return isystems[0]
 
+    @ staticmethod
+    def _respoolconverter(res_pool):
+        setattr(res_pool, 'name', res_pool.region_name)
+        return res_pool
+
     @ staticmethod
     def _hostconverter(host):
+        selected_keys = [
+            "hostname", "personality", "id", "mgmt_ip", "mgmt_mac",
+            "software_load", "capabilities",
+            "operational", "availability", "administrative",
+            "boot_device", "rootfs_device", "install_state", "subfunctions",
+            "clock_synchronization", "max_cpu_mhz_allowed"
+        ]
+        content = host.to_dict()
+        filtered = dict(
+            filter(lambda item: item[0] in selected_keys, content.items()))
+        setattr(host, 'filtered', filtered)
         setattr(host, 'name', host.hostname)
         return host
 
+    @ staticmethod
+    def _labelconverter(label):
+        selected_keys = [
+            "uuid", "label_key", "label_value", "host_uuid"
+        ]
+        content = label.to_dict()
+        print(content)
+        filtered = dict(
+            filter(lambda item: item[0] in selected_keys, content.items()))
+        setattr(label, 'filtered', filtered)
+        setattr(label, 'name', label.uuid.split(
+            '-', 1)[0] + '-label-' + label.label_key)
+        setattr(label, 'updated_at', None)
+        setattr(label, 'created_at', None)
+        return label
+
     @ staticmethod
     def _cpuconverter(cpu):
+        selected_keys = [
+            "cpu", "core", "thread", "allocated_function", "numa_node",
+            "cpu_model", "cpu_family"
+        ]
+        content = cpu.to_dict()
+        filtered = dict(
+            filter(lambda item: item[0] in selected_keys, content.items()))
+        setattr(cpu, 'filtered', filtered)
         setattr(cpu, 'name', cpu.ihost_uuid.split(
             '-', 1)[0] + '-cpu-'+str(cpu.cpu))
         return cpu
 
     @ staticmethod
     def _memconverter(mem):
+        selected_keys = [
+            "memtotal_mib", "memavail_mib", "vm_hugepages_use_1G",
+            "vm_hugepages_possible_1G", "hugepages_configured",
+            "vm_hugepages_avail_1G", "vm_hugepages_nr_1G",
+            "vm_hugepages_nr_4K", "vm_hugepages_nr_2M",
+            "vm_hugepages_possible_2M", "vm_hugepages_avail_2M",
+            "platform_reserved_mib", "numa_node"
+        ]
+        content = mem.to_dict()
+        filtered = dict(
+            filter(lambda item: item[0] in selected_keys, content.items()))
+        setattr(mem, 'filtered', filtered)
         setattr(mem, 'name', mem.ihost_uuid.split('-', 1)[0] +
                 '-mem-node-'+str(mem.numa_node))
         return mem
 
     @ staticmethod
     def _ethconverter(eth):
+        selected_keys = [
+            "name", "namedisplay", "dev_id", "pdevice", "capabilities",
+            "type", "driver", "mac", "numa_node",
+            "pciaddr", "pclass", "psvendor", "psdevice",
+            "sriov_totalvfs", "sriov_numvfs", "dpdksupport",
+            "sriov_vf_driver", "sriov_vf_pdevice_id", "interface_uuid"
+        ]
+        content = eth.to_dict()
+        filtered = dict(
+            filter(lambda item: item[0] in selected_keys, content.items()))
+        setattr(eth, 'filtered', filtered)
         setattr(eth, 'name', eth.host_uuid.split('-', 1)[0] + '-'+eth.name)
         setattr(eth, 'updated_at', None)
         setattr(eth, 'created_at', None)
@@ -551,6 +680,15 @@ class StxClientImp(object):
 
     @ staticmethod
     def _ifconverter(ifs):
+        selected_keys = [
+            "ifname", "iftype", "imac", "vlan_id", "imtu",
+            "ifclass", "uses", "max_tx_rate",
+            "sriov_vf_driver", "sriov_numvfs", "ptp_role"
+        ]
+        content = ifs.to_dict()
+        filtered = dict(
+            filter(lambda item: item[0] in selected_keys, content.items()))
+        setattr(ifs, 'filtered', filtered)
         setattr(ifs, 'name', ifs.ihost_uuid.split('-', 1)[0] + '-'+ifs.ifname)
         setattr(ifs, 'updated_at', None)
         setattr(ifs, 'created_at', None)
@@ -558,6 +696,15 @@ class StxClientImp(object):
 
     @ staticmethod
     def _devconverter(dev):
+        selected_keys = [
+            "name", "pdevice", "pciaddr", "pvendor_id", "pvendor",
+            "pclass_id", "pclass", "psvendor", "psdevice",
+            "sriov_totalvfs", "sriov_numvfs", "numa_node"
+        ]
+        content = dev.to_dict()
+        filtered = dict(
+            filter(lambda item: item[0] in selected_keys, content.items()))
+        setattr(dev, 'filtered', filtered)
         setattr(dev, 'name', dev.host_uuid.split('-', 1)[0] + '-'+dev.name)
         return dev
 
@@ -566,7 +713,7 @@ class StxClientImp(object):
         setattr(cluster, 'name', cluster.cloud_name +
                 '.' + cluster.cluster_name)
         setattr(cluster, 'uuid',
-                uuid.uuid3(uuid.NAMESPACE_URL, cluster.name))
+                uuid.uuid3(uuid.NAMESPACE_URL, cluster.cloud_uuid))
         setattr(cluster, 'updated_at', None)
         setattr(cluster, 'created_at', None)
         setattr(cluster, 'events', [])
@@ -577,4 +724,5 @@ class StxClientImp(object):
     @ staticmethod
     def _k8shasher(cluster):
         return str(hash((cluster.cluster_name, cluster.cloud_name,
-                         cluster.cluster_api_endpoint, cluster.admin_user)))
+                         cluster.cluster_api_endpoint, cluster.admin_user,
+                         cluster.capabilities)))