VOL-1477 Migrate OpenOltAlarmMgr

Added alarm related functions to the core_proxy to send and create alarm
Some of the onu alarm classes modified to include serial_number in the alarm context
AdapterAlarms has modified to include the device's serial_number

Change-Id: Idda9ba90071029f57bb0b7e394fdd5bb6385ee3f
diff --git a/pyvoltha/adapters/extensions/alarms/adapter_alarms.py b/pyvoltha/adapters/extensions/alarms/adapter_alarms.py
index 56d47a1..0e8f94a 100644
--- a/pyvoltha/adapters/extensions/alarms/adapter_alarms.py
+++ b/pyvoltha/adapters/extensions/alarms/adapter_alarms.py
@@ -37,18 +37,20 @@
     """
     Class for managing Alarms within a given Device Handler instance
     """
-    def __init__(self, adapter_agent, device_id, logical_device_id):
+    def __init__(self, adapter_agent, device_id, logical_device_id, serial_number):
         """
         Adapter alarm manager initializer
 
         :param adapter_agent: (AdapterAgent) Adapter agent reference
         :param device_id: (str) Device handler's unique device id
         :param logical_device_id: (str) Logical Device that the device is a member of
+        :param serial_number: (str) Serial number of the device(OLT) that created this instance
         """
         self.log = structlog.get_logger(device_id=device_id)
         self.adapter_agent = adapter_agent
         self.device_id = device_id
         self.logical_device_id = logical_device_id
+        self.serial_number = serial_number
         self.adapter_name = adapter_agent.listening_topic
         self.lc = None
 
@@ -91,17 +93,11 @@
             if isinstance(context_data, dict):
                 for key, value in context_data.iteritems():
                     current_context[key] = str(value)
-            ser_num = None
-            device = self.adapter_agent.get_device(device_id=self.device_id)
-            ser_num = device.serial_number
+            #Always insert serial number of the OLT, ONU serial number comes in the context
+            current_context["serial-number"] = self.serial_number
 
-
-            """
-            Only put in the onu serial numbers since the OLT does not currently have a serial number and the
-            value is the ip:port address.
-            """
-            if isinstance(context_data, dict) and '_onu' in device.type.lower():
-                current_context["onu_serial_number"] = ser_num
+            self.log.debug('send_alarm', alarm_data=alarm_data)
+            
             alarm_event = self.adapter_agent.create_alarm(
                 id=alarm_data.get('id', 'voltha.{}.{}.olt'.format(self.adapter_name,
                                                                   self.device_id)),
diff --git a/pyvoltha/adapters/extensions/alarms/onu/onu_activation_fail_alarm.py b/pyvoltha/adapters/extensions/alarms/onu/onu_activation_fail_alarm.py
index 11662c6..58dbf9c 100644
--- a/pyvoltha/adapters/extensions/alarms/onu/onu_activation_fail_alarm.py
+++ b/pyvoltha/adapters/extensions/alarms/onu/onu_activation_fail_alarm.py
@@ -16,7 +16,7 @@
 
 
 class OnuActivationFailAlarm(AlarmBase):
-    def __init__(self, alarm_mgr, onu_id, intf_id):
+    def __init__(self, alarm_mgr, onu_id, intf_id, serial_number):
         super(OnuActivationFailAlarm, self).__init__(alarm_mgr, object_type='onu ACTIVATION FAIL',
                                           alarm='ONU_ACTIVATION_FAIL',
                                           alarm_category=AlarmEventCategory.ONU,
@@ -24,7 +24,9 @@
                                           alarm_severity=AlarmEventSeverity.MAJOR)
         self._onu_id = onu_id
         self._intf_id = intf_id
+        self._serial_number = serial_number
 
     def get_context_data(self):
         return {'onu-id': self._onu_id,
-                'onu-intf-id': self._intf_id}
+                'onu-intf-id': self._intf_id,
+                'onu-serial-number': self._serial_number}
diff --git a/pyvoltha/adapters/extensions/alarms/onu/onu_discovery_alarm.py b/pyvoltha/adapters/extensions/alarms/onu/onu_discovery_alarm.py
index d242a9f..a9f90ee 100644
--- a/pyvoltha/adapters/extensions/alarms/onu/onu_discovery_alarm.py
+++ b/pyvoltha/adapters/extensions/alarms/onu/onu_discovery_alarm.py
@@ -29,7 +29,8 @@
     def get_context_data(self):
         return {
             'pon-id': self._pon_id,
-            'serial-number': self._serial_number
+            'serial-number': self._serial_number,
+            'device-type': 'onu'
         }
 
     def clear_alarm(self):
diff --git a/pyvoltha/adapters/extensions/alarms/onu/onu_dying_gasp_alarm.py b/pyvoltha/adapters/extensions/alarms/onu/onu_dying_gasp_alarm.py
index 4e659d2..6e702a5 100644
--- a/pyvoltha/adapters/extensions/alarms/onu/onu_dying_gasp_alarm.py
+++ b/pyvoltha/adapters/extensions/alarms/onu/onu_dying_gasp_alarm.py
@@ -17,7 +17,7 @@
 
 
 class OnuDyingGaspAlarm(AlarmBase):
-    def __init__(self, alarm_mgr, onu_id, intf_id):
+    def __init__(self, alarm_mgr, onu_id, intf_id, serial_number):
         super(OnuDyingGaspAlarm, self).__init__(alarm_mgr, object_type='onu DYING_GASP',
                                                 alarm='ONU_DYING_GASP',
                                                 alarm_category=AlarmEventCategory.ONU,
@@ -25,9 +25,11 @@
                                                 alarm_severity=AlarmEventSeverity.MAJOR)
         self._onu_id = onu_id
         self._intf_id = intf_id
+        self._serial_number = serial_number
 
     def get_context_data(self):
         return {
             'onu-id': self._onu_id,
-            'onu-intf-id': self._intf_id
+            'onu-intf-id': self._intf_id,
+            'onu-serial-number': self._serial_number
         }
diff --git a/pyvoltha/adapters/extensions/alarms/onu/onu_lob_alarm.py b/pyvoltha/adapters/extensions/alarms/onu/onu_lob_alarm.py
index cbf24cb..4b898a1 100644
--- a/pyvoltha/adapters/extensions/alarms/onu/onu_lob_alarm.py
+++ b/pyvoltha/adapters/extensions/alarms/onu/onu_lob_alarm.py
@@ -16,7 +16,7 @@
 
 
 class OnuLobAlarm(AlarmBase):
-    def __init__(self, alarm_mgr, onu_id, intf_id):
+    def __init__(self, alarm_mgr, onu_id, intf_id, serial_number):
         super(OnuLobAlarm, self).__init__(alarm_mgr, object_type='onu LOB',
                                           alarm='ONU_LOB',
                                           alarm_category=AlarmEventCategory.ONU,
@@ -24,7 +24,10 @@
                                           alarm_severity=AlarmEventSeverity.MAJOR)
         self._onu_id = onu_id
         self._intf_id = intf_id
+        self._serial_number = serial_number
 
     def get_context_data(self):
         return {'onu-id': self._onu_id,
-                'onu-intf-id': self._intf_id}
+                'onu-intf-id': self._intf_id,
+                'onu-serial-number': self._serial_number
+        }
diff --git a/pyvoltha/adapters/extensions/alarms/onu/onu_lopc_mic_error_alarm.py b/pyvoltha/adapters/extensions/alarms/onu/onu_lopc_mic_error_alarm.py
index 8498d91..01871ca 100644
--- a/pyvoltha/adapters/extensions/alarms/onu/onu_lopc_mic_error_alarm.py
+++ b/pyvoltha/adapters/extensions/alarms/onu/onu_lopc_mic_error_alarm.py
@@ -17,7 +17,7 @@
 
 
 class OnuLopcMicErrorAlarm(AlarmBase):
-    def __init__(self, alarm_mgr, onu_id, intf_id):
+    def __init__(self, alarm_mgr, onu_id, intf_id, serial_number):
         super(OnuLopcMicErrorAlarm, self).__init__(alarm_mgr,  object_type='onu LOPC_MIC_ERROR',
                                                    alarm='ONU_LOPC_MIC_ERROR',
                                                    alarm_category=AlarmEventCategory.ONU,
@@ -25,9 +25,11 @@
                                                    alarm_severity=AlarmEventSeverity.MAJOR)
         self._onu_id = onu_id
         self._intf_id = intf_id
+        self._serial_number = serial_number
 
     def get_context_data(self):
         return {
             'onu-id': self._onu_id,
-            'onu-intf-id': self._intf_id
+            'onu-intf-id': self._intf_id,
+            'onu-serial-number': self._serial_number
         }
diff --git a/pyvoltha/adapters/extensions/alarms/onu/onu_lopc_miss_alarm.py b/pyvoltha/adapters/extensions/alarms/onu/onu_lopc_miss_alarm.py
index 8c7a632..550f616 100644
--- a/pyvoltha/adapters/extensions/alarms/onu/onu_lopc_miss_alarm.py
+++ b/pyvoltha/adapters/extensions/alarms/onu/onu_lopc_miss_alarm.py
@@ -17,7 +17,7 @@
 
 
 class OnuLopcMissAlarm(AlarmBase):
-    def __init__(self, alarm_mgr, onu_id, intf_id):
+    def __init__(self, alarm_mgr, onu_id, intf_id, serial_number):
         super(OnuLopcMissAlarm, self).__init__(alarm_mgr, object_type='onu LOPC_MISS',
                                                alarm='ONU_LOPC_MISS',
                                                alarm_category=AlarmEventCategory.ONU,
@@ -25,9 +25,11 @@
                                                alarm_severity=AlarmEventSeverity.MAJOR)
         self._onu_id = onu_id
         self._intf_id = intf_id
+        self._serial_number = serial_number
 
     def get_context_data(self):
         return {
             'onu-id': self._onu_id,
-            'onu-intf-id': self._intf_id
+            'onu-intf-id': self._intf_id,
+            'onu-serial-number': self._serial_number
         }
diff --git a/pyvoltha/adapters/extensions/alarms/onu/onu_los_alarm.py b/pyvoltha/adapters/extensions/alarms/onu/onu_los_alarm.py
index 9511f28..8c86372 100644
--- a/pyvoltha/adapters/extensions/alarms/onu/onu_los_alarm.py
+++ b/pyvoltha/adapters/extensions/alarms/onu/onu_los_alarm.py
@@ -16,7 +16,7 @@
 
 
 class OnuLosAlarm(AlarmBase):
-    def __init__(self, alarm_mgr, onu_id, intf_id):
+    def __init__(self, alarm_mgr, onu_id, intf_id, serial_number):
         super(OnuLosAlarm, self).__init__(alarm_mgr, object_type='onu LOS',
                                           alarm='ONU_LOS',
                                           alarm_category=AlarmEventCategory.ONU,
@@ -24,7 +24,10 @@
                                           alarm_severity=AlarmEventSeverity.MAJOR)
         self._onu_id = onu_id
         self._intf_id = intf_id
+        self._serial_number = serial_number
 
     def get_context_data(self):
         return {'onu-id': self._onu_id,
-                'onu-intf-id': self._intf_id}
+                'onu-intf-id': self._intf_id,
+                'onu-serial-number': self._serial_number
+        }
diff --git a/pyvoltha/adapters/extensions/alarms/onu/onu_signal_degrade_alarm.py b/pyvoltha/adapters/extensions/alarms/onu/onu_signal_degrade_alarm.py
index 552fc0b..8c74eac 100644
--- a/pyvoltha/adapters/extensions/alarms/onu/onu_signal_degrade_alarm.py
+++ b/pyvoltha/adapters/extensions/alarms/onu/onu_signal_degrade_alarm.py
@@ -17,7 +17,7 @@
 
 class OnuSignalDegradeAlarm(AlarmBase):
     def __init__(self, alarm_mgr, onu_id, intf_id,
-                 inverse_bit_error_rate):
+                 inverse_bit_error_rate, serial_number):
         super(OnuSignalDegradeAlarm, self).__init__(alarm_mgr, object_type='onu SIGNAL DEGRADE',
                                           alarm='ONU_SIGNAL_DEGRADE',
                                           alarm_category=AlarmEventCategory.ONU,
@@ -26,8 +26,10 @@
         self._onu_id = onu_id
         self._intf_id = intf_id
         self._inverse_bit_error_rate=inverse_bit_error_rate
+        self._serial_number = serial_number
 
     def get_context_data(self):
         return {'onu-id': self._onu_id,
                 'onu-intf-id': self._intf_id,
+                'onu-serial-number': self._serial_number,
                 'inverse-bit-error-rate': self._inverse_bit_error_rate}
diff --git a/pyvoltha/adapters/extensions/alarms/onu/onu_signal_fail_alarm.py b/pyvoltha/adapters/extensions/alarms/onu/onu_signal_fail_alarm.py
index c2dd827..d24c688 100644
--- a/pyvoltha/adapters/extensions/alarms/onu/onu_signal_fail_alarm.py
+++ b/pyvoltha/adapters/extensions/alarms/onu/onu_signal_fail_alarm.py
@@ -23,7 +23,7 @@
 """
 
 class OnuSignalFailAlarm(AlarmBase):
-    def __init__(self, alarm_mgr, onu_id, intf_id, inverse_bit_error_rate):
+    def __init__(self, alarm_mgr, onu_id, intf_id, inverse_bit_error_rate, serial_number):
         super(OnuSignalFailAlarm, self).__init__(alarm_mgr, object_type='onu SIGNAL FAIL',
                                           alarm='ONU_SIGNAL_FAIL',
                                           alarm_category=AlarmEventCategory.ONU,
@@ -32,8 +32,10 @@
         self._onu_id = onu_id
         self._intf_id = intf_id
         self._inverse_bit_error_rate = inverse_bit_error_rate
+        self._serial_number = serial_number
 
     def get_context_data(self):
         return {'onu-id': self._onu_id,
                 'onu-intf-id': self._intf_id,
-                'inverse-bit-error-rate': self._inverse_bit_error_rate}
+                'inverse-bit-error-rate': self._inverse_bit_error_rate,
+                 'onu-serial-number': self._serial_number}
diff --git a/pyvoltha/adapters/extensions/alarms/onu/onu_startup_alarm.py b/pyvoltha/adapters/extensions/alarms/onu/onu_startup_alarm.py
index 8a787de..d81d947 100644
--- a/pyvoltha/adapters/extensions/alarms/onu/onu_startup_alarm.py
+++ b/pyvoltha/adapters/extensions/alarms/onu/onu_startup_alarm.py
@@ -25,7 +25,7 @@
 
 class OnuStartupAlarm(AlarmBase):
 
-    def __init__(self, alarm_mgr, onu_id, intf_id):
+    def __init__(self, alarm_mgr, onu_id, intf_id, serial_number):
         super(OnuStartupAlarm, self).__init__(alarm_mgr, object_type='onu STARTUP FAIL',
                                           alarm='ONU_STARTUP_FAIL',
                                           alarm_category=AlarmEventCategory.ONU,
@@ -33,7 +33,10 @@
                                           alarm_severity=AlarmEventSeverity.MAJOR)
         self._onu_id = onu_id
         self._intf_id = intf_id
+        self._serial_number = serial_number
 
     def get_context_data(self):
         return {'onu-id': self._onu_id,
-                'onu-intf-id': self._intf_id}
+                'onu-intf-id': self._intf_id,
+                'onu-serial-number': self._serial_number
+        }
diff --git a/pyvoltha/adapters/extensions/alarms/onu/onu_window_drift_alarm.py b/pyvoltha/adapters/extensions/alarms/onu/onu_window_drift_alarm.py
index 4bed348..c00195b 100644
--- a/pyvoltha/adapters/extensions/alarms/onu/onu_window_drift_alarm.py
+++ b/pyvoltha/adapters/extensions/alarms/onu/onu_window_drift_alarm.py
@@ -25,7 +25,7 @@
             fixed32 new_eqd = 5;
         }
     """
-    def __init__(self, alarm_mgr, onu_id, intf_id, drift, new_eqd):
+    def __init__(self, alarm_mgr, onu_id, intf_id, drift, new_eqd, serial_number):
         super(OnuWindowDriftAlarm, self).__init__(alarm_mgr, object_type='onu WINDOW DRIFT',
                                           alarm='ONU_WINDOW_DRIFT',
                                           alarm_category=AlarmEventCategory.ONU,
@@ -35,9 +35,12 @@
         self._intf_id = intf_id
         self._drift = drift
         self._new_eqd = new_eqd
+        self._serial_number = serial_number
+        
 
     def get_context_data(self):
         return {'onu-id': self._onu_id,
                 'onu-intf-id': self._intf_id,
                 'drift': self._drift,
-                'new-eqd': self._new_eqd}
+                'new-eqd': self._new_eqd,
+                'onu-serial-number': self._serial_number}
diff --git a/pyvoltha/adapters/kafka/core_proxy.py b/pyvoltha/adapters/kafka/core_proxy.py
index 43229c8..2176778 100644
--- a/pyvoltha/adapters/kafka/core_proxy.py
+++ b/pyvoltha/adapters/kafka/core_proxy.py
@@ -18,6 +18,7 @@
 Agent to play gateway between CORE and an adapter.
 """
 import structlog
+import arrow
 from google.protobuf.message import Message
 from twisted.internet.defer import inlineCallbacks, returnValue
 
@@ -26,8 +27,10 @@
 from voltha_protos.common_pb2 import ID, ConnectStatus, OperStatus
 from voltha_protos.inter_container_pb2 import StrType, BoolType, IntType, Packet
 from voltha_protos.device_pb2 import Device, Ports, Devices
-from voltha_protos.voltha_pb2 import CoreInstance
-
+from voltha_protos.voltha_pb2 import CoreInstance, AlarmFilterRuleKey
+from voltha_protos.events_pb2 import AlarmEvent, AlarmEventType, \
+    AlarmEventState, AlarmEventCategory, AlarmEventSeverity
+    
 log = structlog.get_logger()
 
 
@@ -426,3 +429,102 @@
                                 port=p,
                                 packet=pac)
         returnValue(res)
+        
+    # ~~~~~~~~~~~~~~~~~~~ Handle alarm submissions ~~~~~~~~~~~~~~~~~~~~~
+
+    def create_alarm(self, id=None, resource_id=None, description=None,
+                     raised_ts=0, changed_ts=0,
+                     type=AlarmEventType.EQUIPMENT,
+                     category=AlarmEventCategory.PON,
+                     severity=AlarmEventSeverity.MINOR,
+                     state=AlarmEventState.RAISED,
+                     context=None,
+                     logical_device_id=None,
+                     alarm_type_name=None):
+        # Construct the ID if it is not provided
+        if id is None:
+            id = 'voltha.{}.{}'.format(self.adapter_name, resource_id)
+        log.debug('create alarmevent', id=id,
+            resource_id=resource_id,
+            type=type,
+            category=category,
+            severity=severity,
+            state=state,
+            description=description,
+            reported_ts=arrow.utcnow().timestamp,
+            raised_ts=raised_ts,
+            changed_ts=changed_ts,
+            context=context,
+            logical_device_id=logical_device_id,
+            alarm_type_name=alarm_type_name)
+        return AlarmEvent(
+            id=id,
+            resource_id=resource_id,
+            type=type,
+            category=category,
+            severity=severity,
+            state=state,
+            description=description,
+            reported_ts=arrow.utcnow().timestamp,
+            raised_ts=raised_ts,
+            changed_ts=changed_ts,
+            context=context,
+            logical_device_id=logical_device_id,
+            alarm_type_name=alarm_type_name
+        )
+
+    def filter_alarm(self, device_id, alarm_event):
+        '''
+        TODO
+        alarm filtering functionality is not implemented
+        in Voltha 1.x 
+        '''
+        log.warn('filter_alarm is not implemented')
+        return 
+        #alarm_filters = self.root_proxy.get('/alarm_filters')
+        
+        rule_values = {
+            'id': alarm_event.id,
+            'type': AlarmEventType.AlarmEventType.Name(alarm_event.type),
+            'category': AlarmEventCategory.AlarmEventCategory.Name(
+                alarm_event.category),
+            'severity': AlarmEventSeverity.AlarmEventSeverity.Name(
+                alarm_event.severity),
+            'resource_id': alarm_event.resource_id,
+            'device_id': device_id
+        }
+
+        for alarm_filter in alarm_filters:
+            if alarm_filter.rules:
+                exclude = True
+                for rule in alarm_filter.rules:
+                    log.debug("compare-alarm-event",
+                                   key=AlarmFilterRuleKey.AlarmFilterRuleKey.Name(
+                                       rule.key),
+                                   actual=rule_values[
+                                       AlarmFilterRuleKey.AlarmFilterRuleKey.Name(
+                                           rule.key)].lower(),
+                                   expected=rule.value.lower())
+                    exclude = exclude and \
+                              (rule_values[
+                                   AlarmFilterRuleKey.AlarmFilterRuleKey.Name(
+                                       rule.key)].lower() == rule.value.lower())
+                    if not exclude:
+                        break
+
+                if exclude:
+                    log.info("filtered-alarm-event", alarm=alarm_event)
+                    return True
+
+        return False
+
+    @inlineCallbacks
+    def submit_alarm(self, device_id, alarm_event_msg):
+        try:
+            assert isinstance(alarm_event_msg, AlarmEvent)
+            if not self.filter_alarm(device_id, alarm_event_msg):
+                res = yield self.kafka_proxy._send_kafka_message('alarms', alarm_event_msg)
+                returnValue(res)
+        except Exception as e:
+            log.exception('failed-alarm-submission',
+                        type=type(alarm_event_msg), e=e)
\ No newline at end of file