INF-303 Add Infrastructure Monitoring Fault Service; INF-305 update inventory api...
[pti/o2.git] / o2ims / adapter / clients / fault_client.py
diff --git a/o2ims/adapter/clients/fault_client.py b/o2ims/adapter/clients/fault_client.py
new file mode 100644 (file)
index 0000000..b37a4d2
--- /dev/null
@@ -0,0 +1,191 @@
+# Copyright (C) 2022 Wind River Systems, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+# client talking to Stx standalone
+
+from typing import List  # Optional,  Set
+import uuid as uuid
+
+# 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 fmclient.client import get_client as get_fm_client
+from fmclient.common.exceptions import HTTPNotFound
+
+from o2common.service.client.base_client import BaseClient
+from o2common.config import config
+from o2ims.domain import alarm_obj as alarmModel
+from o2ims.domain.resource_type import ResourceTypeEnum
+from o2app.adapter import unit_of_work
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+CGTSCLIENT_ENDPOINT_ERROR_MSG = \
+    'Must provide Keystone credentials or user-defined endpoint and token'
+
+
+class StxAlarmClient(BaseClient):
+    def __init__(self, uow: unit_of_work.AbstractUnitOfWork, driver=None):
+        super().__init__()
+        self.driver = driver if driver else StxFaultClientImp()
+        self.uow = uow
+
+    def _get(self, id) -> alarmModel.FaultGenericModel:
+        return self.driver.getAlarmInfo(id)
+
+    def _list(self, **filters) -> List[alarmModel.FaultGenericModel]:
+        # filters['resourcetypeid']
+        newmodels = self.driver.getAlarmList(**filters)
+        uow = self.uow
+        exist_alarms = {}
+        with uow:
+            rs = uow.session.execute(
+                '''
+                SELECT "alarmEventRecordId"
+                FROM "alarmEventRecord"
+                WHERE "perceivedSeverity" != :perceived_severity_enum
+                ''',
+                dict(perceived_severity_enum=alarmModel.PerceivedSeverityEnum.
+                     CLEARED)
+            )
+            for row in rs:
+                id = row[0]
+                # logger.debug('Exist alarm: ' + id)
+                exist_alarms[id] = False
+
+        ret = []
+        for m in newmodels:
+            try:
+                if exist_alarms[m.id]:
+                    ret.append(m)
+                    exist_alarms[m.id] = True
+            except KeyError:
+                logger.debug('alarm new: ' + m.id)
+                ret.append(m)
+
+        for alarm in exist_alarms:
+            logger.debug('exist alarm: ' + alarm)
+            if exist_alarms[alarm]:
+                # exist alarm is active
+                continue
+            event = self._get(alarm)
+            ret.append(event)
+
+        return ret
+
+    def _set_stx_client(self):
+        pass
+
+
+class StxEventClient(BaseClient):
+    def __init__(self, driver=None):
+        super().__init__()
+        self.driver = driver if driver else StxFaultClientImp()
+
+    def _get(self, id) -> alarmModel.FaultGenericModel:
+        return self.driver.getEventInfo(id)
+
+    def _list(self, **filters) -> List[alarmModel.FaultGenericModel]:
+        return self.driver.getEventList(**filters)
+
+    def _set_stx_client(self):
+        pass
+
+
+# internal driver which implement client call to Stx Fault Management instance
+class StxFaultClientImp(object):
+    def __init__(self, fm_client=None):
+        super().__init__()
+        self.fmclient = fm_client if fm_client else self.getFmClient()
+        # if subcloud_id is not None:
+        # self.stxclient = self.getSubcloudClient(subcloud_id)
+
+    def getFmClient(self):
+        os_client_args = config.get_fm_access_info()
+        config_client = get_fm_client(1, **os_client_args)
+        return config_client
+
+    def getAlarmList(self, **filters) -> List[alarmModel.FaultGenericModel]:
+        alarms = self.fmclient.alarm.list(expand=True)
+        if len(alarms) == 0:
+            return []
+        logger.debug('alarm 1:' + str(alarms[0].to_dict()))
+        # [print('alarm:' + str(alarm.to_dict())) for alarm in alarms if alarm]
+        return [alarmModel.FaultGenericModel(
+            ResourceTypeEnum.PSERVER, self._alarmconverter(alarm))
+            for alarm in alarms if alarm]
+
+    def getAlarmInfo(self, id) -> alarmModel.FaultGenericModel:
+        try:
+            alarm = self.fmclient.alarm.get(id)
+            logger.debug('get alarm id ' + id + ':' + str(alarm.to_dict()))
+            # print(alarm.to_dict())
+        except HTTPNotFound:
+            event = self.fmclient.event_log.get(id)
+            return alarmModel.FaultGenericModel(
+                ResourceTypeEnum.PSERVER, self._eventconverter(event, True))
+        return alarmModel.FaultGenericModel(
+            ResourceTypeEnum.PSERVER, self._alarmconverter(alarm))
+
+    def getEventList(self, **filters) -> List[alarmModel.FaultGenericModel]:
+        events = self.fmclient.event_log.list(alarms=True, expand=True)
+        logger.debug('event 1:' + str(events[0].to_dict()))
+        # [print('alarm:' + str(event.to_dict())) for event in events if event]
+        return [alarmModel.FaultGenericModel(
+            ResourceTypeEnum.PSERVER, self._eventconverter(event))
+            for event in events if event]
+
+    def getEventInfo(self, id) -> alarmModel.FaultGenericModel:
+        event = self.fmclient.event_log.get(id)
+        logger.debug('get event id ' + id + ':' + str(event.to_dict()))
+        # print(event.to_dict())
+        return alarmModel.FaultGenericModel(
+            ResourceTypeEnum.PSERVER, self._eventconverter(event))
+
+    @ staticmethod
+    def _alarmconverter(alarm):
+        # setattr(alarm, 'alarm_def_id', uuid.uuid3(
+        #         uuid.NAMESPACE_URL, alarm.alarm_id))
+        setattr(alarm, 'state', alarm.alarm_state)
+        setattr(alarm, 'event_log_type', alarm.alarm_type)
+        setattr(alarm, 'event_log_id', alarm.alarm_id)
+
+        setattr(alarm, 'alarm_def_id', uuid.uuid3(
+                uuid.NAMESPACE_URL, alarm.alarm_id))
+        setattr(alarm, 'probable_cause_id', uuid.uuid3(
+                uuid.NAMESPACE_URL, alarm.probale_cause))
+        return alarm
+
+    @ staticmethod
+    def _eventconverter(event, clear=False):
+        setattr(event, 'alarm_id', event.event_log_id)
+        setattr(event, 'alarm_type', event.event_log_type)
+        if clear:
+            logger.debug('alarm is clear')
+            event.state = 'clear'
+        setattr(event, 'alarm_def_id', uuid.uuid3(
+                uuid.NAMESPACE_URL, event.alarm_id))
+        setattr(event, 'probable_cause_id', uuid.uuid3(
+                uuid.NAMESPACE_URL, event.probale_cause))
+        return event
+
+    @ staticmethod
+    def _alarmeventhasher(event, state=''):
+        # The event model and the alarm model have different parameter name
+        # of the state. alarm model is alarm_state, event model is state.
+        status = event.alarm_state if state == '' else state
+        return str(hash((event.uuid, event.timestamp, status)))