PONSIM: Generate alarms as FrameIO egress packets
- Option to enable generation of alarms
- Alarms are received by PONSIM OLT and submitted to kafka
- Option to configure alarm frequency
Change-Id: I93a05eaaae7eb2a6f25937ec76470c1b24c2842b
diff --git a/ponsim/main.py b/ponsim/main.py
index b6e305e..2100879 100755
--- a/ponsim/main.py
+++ b/ponsim/main.py
@@ -113,6 +113,23 @@
action='count',
help=_help)
+ _help = 'enable generation of simulated alarms'
+ parser.add_argument('-a', '--alarm-simulation',
+ dest='alarm_simulation',
+ action='store_true',
+ default=False,
+ help=_help)
+
+ _help = 'frequency of simulated alarms (in seconds)'
+ parser.add_argument('-f', '--alarm-frequency',
+ dest='alarm_frequency',
+ action='store',
+ type=int,
+ metavar="[30-300]",
+ choices=range(30,301),
+ default=60,
+ help=_help)
+
_help = 'omit startup banner log lines'
parser.add_argument('-n', '--no-banner',
dest='no_banner',
@@ -142,6 +159,10 @@
self.ponsim = None
self.grpc_server = None
+ self.alarm_config = dict()
+ self.alarm_config['simulation'] = self.args.alarm_simulation
+ self.alarm_config['frequency'] = self.args.alarm_frequency
+
if not args.no_banner:
print_banner(self.log)
@@ -158,7 +179,7 @@
iface_map = self.setup_networking_assets(self.args.name,
self.args.onus)
self.io = yield RealIo(iface_map).start()
- self.ponsim = PonSim(self.args.onus, self.io.egress)
+ self.ponsim = PonSim(self.args.onus, self.io.egress, self.alarm_config)
self.io.register_ponsim(self.ponsim)
self.grpc_server = GrpcServer(self.args.grpc_port, self.ponsim)
diff --git a/ponsim/ponsim.py b/ponsim/ponsim.py
index 437290e..b060a10 100644
--- a/ponsim/ponsim.py
+++ b/ponsim/ponsim.py
@@ -20,15 +20,21 @@
handle 0-tagged packets (no comment).
"""
import structlog
-from scapy.layers.inet import IP, UDP
+import random
+import arrow
+import json
+from scapy.layers.inet import IP, UDP, TCP, Raw
from scapy.layers.l2 import Ether, Dot1Q
from scapy.packet import Packet
from voltha.protos import third_party
from voltha.protos.ponsim_pb2 import PonSimMetrics, PonSimPortMetrics, \
PonSimPacketCounter
+from voltha.protos.events_pb2 import AlarmEventType, AlarmEventSeverity, \
+ AlarmEventState, AlarmEventCategory
from voltha.core.flow_decomposer import *
from twisted.internet.task import LoopingCall
+from twisted.internet import reactor
_ = third_party
@@ -147,6 +153,79 @@
return sim_metrics
+class SimAlarms:
+ def __init__(self):
+ self.lc = None
+
+ @staticmethod
+ def _prepare_alarm():
+ alarm_event = dict()
+
+ try:
+ # Randomly choose values for each enum types
+ alm_severity = random.choice(list(
+ v for k, v in
+ AlarmEventSeverity.DESCRIPTOR.enum_values_by_name.items()))
+
+ alm_type = random.choice(list(
+ v for k, v in
+ AlarmEventType.DESCRIPTOR.enum_values_by_name.items()))
+
+ alm_category = random.choice(list(
+ v for k, v in
+ AlarmEventCategory.DESCRIPTOR.enum_values_by_name.items()))
+
+ alarm_event['severity'] = alm_severity.number
+ alarm_event['type'] = alm_type.number
+ alarm_event['category'] = alm_category.number
+ alarm_event['state'] = AlarmEventState.RAISED
+ alarm_event['ts'] = arrow.utcnow().timestamp
+ alarm_event['description'] = "{}.{} alarm".format(alm_type.name, alm_category.name)
+
+ return alarm_event
+
+ except Exception as e:
+ log.exception('failed-to-prepare-alarm', e=e)
+
+ @staticmethod
+ def _raise_alarm(alarm_event, olt, egress):
+ try:
+ frame = Ether() / Dot1Q(vlan=4000) / IP() / TCP() / Raw(load=json.dumps(alarm_event))
+ egress(0, frame)
+
+ except Exception as e:
+ log.exception('failed-to-raise-alarm', e=e)
+
+ @staticmethod
+ def _clear_alarm(alarm_event, olt, egress):
+ try:
+ alarm_event['state'] = AlarmEventState.CLEARED
+ frame = Ether() / Dot1Q(vlan=4000) / IP() / TCP() / Raw(load=json.dumps(alarm_event))
+ egress(0, frame)
+
+ except Exception as e:
+ log.exception('failed-to-clear-alarm', e=e)
+
+ def _generate_alarm(self, olt, egress):
+ try:
+ alarm = self._prepare_alarm()
+ self._raise_alarm(alarm, olt, egress)
+ reactor.callLater(random.randint(20, 60), self._clear_alarm, alarm, olt, egress)
+ except Exception as e:
+ log.exception(e=e)
+
+ def start_simulation(self, olt, egress, config):
+ log.info("starting-alarm-simulation")
+
+ """Simulate periodic device alarms"""
+ self.lc = LoopingCall(self._generate_alarm, olt, egress)
+ self.lc.start(config['frequency'])
+
+ def stop_simulation(self):
+ log.info("stopping-alarm-simulation")
+ self.lc.stop()
+
+
class SimDevice(object):
def __init__(self, name, logical_port_no):
self.name = name
@@ -338,7 +417,7 @@
class PonSim(object):
- def __init__(self, onus, egress_fun):
+ def __init__(self, onus, egress_fun, alarm_config):
self.egress_fun = egress_fun
self.log = structlog.get_logger()
@@ -372,6 +451,10 @@
self.log.info("pon-sim-init", port=d, name=self.devices[d].name,
links=self.devices[d].links)
+ if alarm_config['simulation']:
+ self.alarms = SimAlarms()
+ self.alarms.start_simulation(self.olt, self.egress_fun, alarm_config)
+
def get_ports(self):
return sorted(self.devices.keys())