blob: 56d47a16b2e4010efb5f242ec018fdcabeedb2b3 [file] [log] [blame]
#
# Copyright 2017 the original author or authors.
#
# 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.
import structlog
import arrow
from voltha_protos.events_pb2 import AlarmEventType, AlarmEventSeverity,\
AlarmEventState, AlarmEventCategory
log = structlog.get_logger()
# TODO: In the device adapter, the following alarms are still TBD
# (Taken from openolt_alarms)
# onu_alarm_ind
# onu_startup_failure_indication
# onu_signal_degrade_indication
# onu_drift_of_window_ind
# onu_loss_omci_ind
# onu_signals_fail_ind
# onu_tiwi_ind
# onu_activation_fail_ind
# onu_processing_error_ind
class AdapterAlarms:
"""
Class for managing Alarms within a given Device Handler instance
"""
def __init__(self, adapter_agent, device_id, logical_device_id):
"""
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
"""
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.adapter_name = adapter_agent.listening_topic
self.lc = None
def format_id(self, alarm):
"""
Format the Unique Alarm ID for this alarm. This is provided in the alarms
'id' field
:param alarm: (str) The name of the alarm such as 'Discover' or 'LOS'
:return: (str) Alarm ID
"""
return 'voltha.{}.{}.{}'.format(self.adapter_name,
self.device_id,
alarm)
def format_description(self, _object, alarm, status):
"""
Format the textual description field of this alarm
:param _object: ()
:param alarm: (str) The name of the alarm such as 'Discover' or 'LOS'
:param status: (bool) If True, the alarm is active (it is being raised)
:return: (str) Alarm description
"""
return '{} Alarm - {} - {}'.format(_object.upper(),
alarm.upper(),
'Raised' if status else 'Cleared')
def send_alarm(self, context_data, alarm_data):
"""
Send the alarm to the event bus
:param context_data: (dict) Alarm specific context data
:param alarm_data: (dict) Common Alarm information dictionary
"""
try:
current_context = {}
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
"""
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
alarm_event = self.adapter_agent.create_alarm(
id=alarm_data.get('id', 'voltha.{}.{}.olt'.format(self.adapter_name,
self.device_id)),
resource_id=str(alarm_data.get('resource_id', self.device_id)),
description="{}.{} - {}".format(self.adapter_name, self.device_id,
alarm_data.get('description')),
type=alarm_data.get('type'),
category=alarm_data.get('category'),
severity=alarm_data.get('severity'),
state=alarm_data.get('state'),
raised_ts=alarm_data.get('ts', 0),
context=current_context,
logical_device_id=self.logical_device_id,
alarm_type_name=alarm_data.get('alarm_type_name')
)
self.adapter_agent.submit_alarm(self.device_id, alarm_event)
except Exception as e:
self.log.exception('failed-to-send-alarm', e=e)
raise
class AlarmBase(object):
"""Base class for alarms"""
def __init__(self, alarm_mgr, object_type, alarm,
alarm_category,
resource_id=None,
alarm_type=AlarmEventType.EQUIPMENT,
alarm_severity=AlarmEventSeverity.CRITICAL):
"""
Initializer for the Alarm base class
:param alarm_mgr: (AdapterAlarms) Reference to the device handler's Adapter
Alarm manager
:param object_type: (str) Type of device generating the alarm such as 'olt' or 'onu'
:param alarm: (str) A textual name for the alarm such as 'HeartBeat' or 'Discovery'
:param alarm_category: (AlarmEventCategory) Refers to functional category of
the alarm
:param resource_id: (str) Identifier of the originating resource of the alarm
:param alarm_type: (AlarmEventType) Refers to the area of the system impacted
by the alarm
:param alarm_severity: (AlarmEventSeverity) Overall impact of the alarm on the
system
"""
self._alarm_mgr = alarm_mgr
self._object_type = object_type
self._alarm = alarm
self._alarm_category = alarm_category
self._alarm_type = alarm_type
self._alarm_severity = alarm_severity
self._resource_id = resource_id
def get_alarm_data(self, status):
"""
Get the alarm specific data and format it into a dictionary. When the alarm
is being sent to the event bus, this dictionary provides a majority of the
fields for the alarms.
:param status: (bool) True if the alarm is active/raised
:return: (dict) Alarm data
"""
data = {
'ts': arrow.utcnow().timestamp,
'description': self._alarm_mgr.format_description(self._object_type,
self._alarm,
status),
'id': self._alarm_mgr.format_id(self._alarm),
'type': self._alarm_type,
'category': self._alarm_category,
'severity': self._alarm_severity,
'state': AlarmEventState.RAISED if status else AlarmEventState.CLEARED,
'alarm_type_name': self._alarm
}
if self._resource_id is not None:
data['resource_id'] = self._resource_id
return data
def get_context_data(self):
"""
Get alarm specific context data. If an alarm has specific data to specify, it is
included in the context field in the published event
:return: (dict) Dictionary with alarm specific context data
"""
return {} # NOTE: You should override this if needed
def raise_alarm(self):
"""
Called to set the state of an alarm to active and to send it to the event bus
"""
alarm_data = self.get_alarm_data(True)
context_data = self.get_context_data()
self._alarm_mgr.send_alarm(context_data, alarm_data)
def clear_alarm(self):
"""
Called to set the state of an alarm to inactive and to send it to the event bus
"""
alarm_data = self.get_alarm_data(False)
context_data = self.get_context_data()
self._alarm_mgr.send_alarm(context_data, alarm_data)