VOL-701: Added OMCI Alarm table support to CLI
Change-Id: Ia2250579c0cc274406837fc546e80dedfbeece93
diff --git a/cli/omci.py b/cli/omci.py
index 17e24ba..9b11d32 100644
--- a/cli/omci.py
+++ b/cli/omci.py
@@ -27,6 +27,8 @@
from voltha.protos import voltha_pb2
from voltha.protos.omci_mib_db_pb2 import MibDeviceData, MibClassData, \
MibInstanceData
+from voltha.protos.omci_alarm_db_pb2 import AlarmDeviceData, AlarmClassData, \
+ AlarmInstanceData
from os import linesep
_ = third_party
@@ -96,8 +98,8 @@
try:
res = stub.GetMibDeviceData(voltha_pb2.ID(id=device_id),
metadata=(('get-depth', str(depth)), ))
- except Exception as e:
- pass
+ except Exception as _e:
+ res = None
return res
@@ -145,6 +147,11 @@
.format(device_id), 'red'))
return
+ if mib_db is None:
+ self.poutput(self.colorize('MIB database for ONU {} is not currently available'
+ .format(device_id), 'red'))
+ return
+
mib = self._device_to_dict(mib_db)
self.poutput('OpenOMCI MIB Database for ONU {}'.format(device_id))
@@ -212,8 +219,8 @@
return ' '.join([v[0].upper() + v[1:] for v in attr.split('_')])
def _instance_to_dict(self, instance):
- if not isinstance(instance, MibInstanceData):
- raise TypeError('{} is not of type MibInstanceData'.format(type(instance)))
+ if not isinstance(instance, (MibInstanceData, AlarmInstanceData)):
+ raise TypeError('{} is not of type MIB/Alarm Instance Data'.format(type(instance)))
data = {
OmciCli.INSTANCE_ID_KEY: instance.instance_id,
@@ -227,8 +234,8 @@
return data
def _class_to_dict(self, val):
- if not isinstance(val, MibClassData):
- raise TypeError('{} is not of type MibClassData'.format(type(val)))
+ if not isinstance(val, (MibClassData, AlarmClassData)):
+ raise TypeError('{} is not of type MIB/Alarm Class Data'.format(type(val)))
data = {
OmciCli.CLASS_ID_KEY: val.class_id,
@@ -239,7 +246,7 @@
def _device_to_dict(self, val):
if not isinstance(val, MibDeviceData):
- raise TypeError('{} is not of type MibDeviceData'.format(type(val)))
+ raise TypeError('{} is not of type MIB Device Data'.format(type(val)))
data = {
OmciCli.DEVICE_ID_KEY: val.device_id,
@@ -279,6 +286,10 @@
try:
mib_db = self.get_device_mib(device_id, depth=1)
+ if mib_db is None:
+ self.poutput(self.colorize('Supported ME information for ONU {} is not currently available'
+ .format(device_id), 'red'))
+ return
mib = self._device_to_dict(mib_db)
except Exception: # UnboundLocalError if Device ID not found in DB
@@ -308,6 +319,11 @@
try:
mib_db = self.get_device_mib(device_id, depth=1)
+ if mib_db is None:
+ self.poutput(self.colorize('Message Types for ONU {} are not currently available'
+ .format(device_id), 'red'))
+ return
+
mib = self._device_to_dict(mib_db)
except Exception: # UnboundLocalError if Device ID not found in DB
@@ -347,7 +363,7 @@
print_pb_list_as_table('Devices:', devices, omit_fields, self.poutput)
def help_devices(self):
- self.poutput('TODO: Provide some help')
+ self.poutput('List devices registered in Voltha')
def poutput(self, msg):
"""Convenient shortcut for self.stdout.write(); adds newline if necessary."""
@@ -359,3 +375,106 @@
def do_show(self, _):
"""Show detailed omci information"""
self.poutput('Use show_mib, show_alarms, show_me, show_msg_types for detailed OMCI information')
+
+ def get_alarm_table(self, device_id, depth=-1):
+ stub = self.get_stub()
+
+ try:
+ res = stub.GetAlarmDeviceData(voltha_pb2.ID(id=device_id),
+ metadata=(('get-depth', str(depth)), ))
+ except Exception as _e:
+ res = None
+
+ return res
+
+ def _alarms_to_dict(self, val):
+ if not isinstance(val, AlarmDeviceData):
+ raise TypeError('{} is not of type Alarm Device Data'.format(type(val)))
+
+ data = {
+ OmciCli.DEVICE_ID_KEY: val.device_id,
+ OmciCli.CREATED_KEY: self._string_to_time(val.created),
+ OmciCli.VERSION_KEY: val.version
+ }
+ for class_data in val.classes:
+ data[class_data.class_id] = self._class_to_dict(class_data)
+
+ return data
+
+ def help_show_alarms(self):
+ self.poutput('show_alarms [-d <device-id>]' +
+ linesep + '-d: <device-id> ONU Device ID')
+
+ @options([
+ make_option('-d', '--device-id', action="store", dest='device_id', type='string',
+ help='ONU Device ID', default=None),
+ ])
+ def do_show_alarms(self, _line, opts):
+ """ Show contents of the alarm table"""
+ device_id = opts.device_id or self.device_id
+
+ try:
+ alarm_db = self.get_alarm_table(device_id, depth=-1)
+ if alarm_db is None:
+ self.poutput(self.colorize('Alarm Table for ONU {} is not currently available'
+ .format(device_id), 'red'))
+ return
+
+ except Exception: # UnboundLocalError if Device ID not found in DB
+ self.poutput(self.colorize('Failed to get Alarm Table for ONU {}'
+ .format(device_id), 'red'))
+ return
+
+ alarms = self._alarms_to_dict(alarm_db)
+ self.poutput('OpenOMCI Alarm Table for ONU {}'.format(device_id))
+ self.poutput('Version : {}'.format(alarms[OmciCli.VERSION_KEY]))
+ self.poutput('Created : {}'.format(alarms[OmciCli.CREATED_KEY]))
+
+ class_ids = [k for k in alarms.iterkeys() if isinstance(k, int)]
+ class_ids.sort()
+
+ if len(class_ids) == 0:
+ self.poutput('No active alarms')
+ return
+
+ for cls_id in class_ids:
+ from omci_alarm_info import _alarm_info
+ class_data = alarms[cls_id]
+ info = _alarm_info.get(cls_id)
+
+ self.poutput(' ----------------------------------------------')
+ self.poutput(' Class ID: {0} - ({0:#x}): {1}'.
+ format(cls_id,
+ info.get('name') if info is not None else 'Unknown Class ID'))
+
+ inst_ids = [k for k in class_data.iterkeys() if isinstance(k, int)]
+ inst_ids.sort()
+
+ for inst_id in inst_ids:
+ inst_data = class_data[inst_id]
+ self.poutput(' Instance ID : {0} - ({0:#x})'.format(inst_id))
+ self.poutput(' Created : {}'.format(inst_data[OmciCli.CREATED_KEY]))
+ self.poutput(' Modified : {}'.format(inst_data[OmciCli.MODIFIED_KEY]))
+
+ try:
+ alarm_value = int(inst_data[OmciCli.ATTRIBUTES_KEY]['alarm_bit_map'])
+ except ValueError:
+ alarm_value = 0
+
+ if alarm_value == 0:
+ self.poutput(' Active Alarms: No Active Alarms')
+
+ else:
+ padding = ' Active Alarms:'
+ for alarm_no in xrange(0, 224):
+ if (1 << (223 - alarm_no)) & alarm_value:
+ if info is None:
+ txt = 'Unknown alarm number'
+ else:
+ txt = info.get(alarm_no, 'Unknown alarm number')
+
+ self.poutput('{} {}: {}'.format(padding, alarm_no, txt))
+ padding = ' '
+
+ if inst_id is not inst_ids[-1]:
+ self.poutput(linesep)
diff --git a/cli/omci_alarm_info.py b/cli/omci_alarm_info.py
new file mode 100644
index 0000000..31e6c08
--- /dev/null
+++ b/cli/omci_alarm_info.py
@@ -0,0 +1,172 @@
+#
+# Copyright 2018 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.
+#
+
+_alarm_info = {
+ 5: {
+ 'name': 'CardHolder',
+ 0: 'Plug-in circuit pack missing',
+ 1: 'Plug-in type mismatch alarm',
+ 2: 'Improper card removal',
+ 3: 'Plug-in equipment ID mismatch alarm',
+ 4: 'Protection switch',
+ },
+ 6: {
+ 'name': 'CircuitPack',
+ 0: 'Equipment alarm',
+ 1: 'Powering alarm',
+ 2: 'Self-test failure',
+ 3: 'Laser end of life',
+ 4: 'Temperature yellow',
+ 5: 'Temperature red',
+
+ },
+ 11: {
+ 'name': 'PptpEthernetUni',
+ 0: 'LAN Loss Of Signal',
+ },
+ 47: {
+ 'name': 'MacBridgePortConfigurationData',
+ 0: 'Port blocking',
+ },
+ 256: {
+ 'name': 'OntG',
+ 0: 'Equipment alarm',
+ 1: 'Powering alarm',
+ 2: 'Battery missing',
+ 3: 'Battery failure',
+ 4: 'Battery low',
+ 5: 'Physical intrusion',
+ 6: 'Self-test failure',
+ 7: 'Dying gasp',
+ 8: 'Temperature yellow',
+ 9: 'Temperature red',
+ 10: 'Voltage yellow',
+ 11: 'Voltage red',
+ 12: 'ONU manual power off',
+ 13: 'Invalid image',
+ 14: 'PSE overload yellow',
+ 15: 'PSE overload red',
+ },
+ 263: {
+ 'name': 'AniG',
+ 0: 'Low received optical power',
+ 1: 'High received optical power',
+ 2: 'Signal fail',
+ 3: 'Signal degrade',
+ 4: 'Low transmit optical power',
+ 5: 'High transmit optical power',
+ 6: 'Laser bias current',
+ },
+ 266: {
+ 'name': 'GemInterworkingTp',
+ 6: 'Operational state change',
+ },
+ 268: {
+ 'name': 'GemPortNetworkCtp',
+ 5: 'End-to-end loss of continuity',
+ },
+ 277: {
+ 'name': 'PriorityQueueG',
+ 0: 'Block loss',
+ },
+ 281: {
+ 'name': 'MulticastGemInterworkingTp',
+ 0: 'Deprecated',
+ },
+ 309: {
+ 'name': 'MulticastOperationsProfile',
+ 0: 'Lost multicast group',
+ },
+ 329: {
+ 'name': 'VirtualEthernetInterfacePt',
+ 0: 'Connecting function fail',
+ },
+ 24: {
+ 'name': 'EthernetPMMonitoringHistoryData',
+ 0: 'FCS errors',
+ 1: 'Excessive collision counter',
+ 2: 'Late collision counter',
+ 3: 'Frames too long',
+ 4: 'Buffer overflows on receive',
+ 5: 'Buffer overflows on transmit',
+ 6: 'Single collision frame counter',
+ 7: 'Multiple collision frame counter',
+ 8: 'SQE counter',
+ 9: 'Deferred transmission counter',
+ 10: 'Internal MAC transmit error counter',
+ 11: 'Carrier sense error counter',
+ 12: 'Alignment error counter',
+ 13: 'Internal MAC receive error counter',
+ },
+ 312: {
+ 'name': 'FecPerformanceMonitoringHistoryData',
+ 0: 'Corrected bytes',
+ 1: 'Corrected code words',
+ 2: 'Uncorrectable code words',
+ 4: 'FEC seconds',
+ },
+ 321: {
+ 'name': 'EthernetFrameDownstreamPerformanceMonitoringHistoryData',
+ 0: 'Drop events',
+ 1: 'CRC errored packets',
+ 2: 'Undersize packets',
+ 3: 'Oversize packets',
+ },
+ 322: {
+ 'name': 'EthernetFrameUpstreamPerformanceMonitoringHistoryData',
+ 0: 'Drop events',
+ 1: 'CRC errored packets',
+ 2: 'Undersize packets',
+ 3: 'Oversize packets',
+ },
+ 329: {
+ 'name': 'VeipUni',
+ 0: 'Connecting function fail'
+ },
+ 334: {
+ 'name': 'EthernetFrameExtendedPerformanceMonitoring',
+ 0: 'Drop events',
+ 1: 'CRC errored packets',
+ 2: 'Undersize packets',
+ 3: 'Oversize packets',
+ },
+ 426: {
+ 'name': 'EthernetFrameExtendedPerformanceMonitoring64Bit',
+ 0: 'Drop events',
+ 1: 'CRC errored packets',
+ 2: 'Undersize packets',
+ 3: 'Oversize packets',
+ },
+ 341: {
+ 'name': 'GemPortNetworkCtpMonitoringHistoryData',
+ 1: 'Encryption key errors',
+ },
+ 344: {
+ 'name': 'XgPonTcPerformanceMonitoringHistoryData',
+ 1: 'PSBd HEC error count',
+ 2: 'XGTC HEC error count',
+ 3: 'Unknown profile count',
+ 4: 'XGEM HEC loss count',
+ 5: 'XGEM key errors',
+ 6: 'XGEM HEC error count',
+ },
+ 345: {
+ 'name': 'anceMonitoringHistoryData',
+ 1: 'PLOAM MIC error count',
+ 2: 'OMCI MIC error count',
+ },
+}
+