diff --git a/src/zino/tasks/juniperalarmtask.py b/src/zino/tasks/juniperalarmtask.py index 755839a92..0150510b0 100644 --- a/src/zino/tasks/juniperalarmtask.py +++ b/src/zino/tasks/juniperalarmtask.py @@ -21,13 +21,19 @@ async def run(self): except TypeError: return - device_state.alarms = { - "yellow": yellow_alarm_count, - "red": red_alarm_count, - } + if not device_state.alarms: + device_state.alarms = { + "yellow": 0, + "red": 0, + } - self.create_alarm_event(color="yellow", alarm_count=yellow_alarm_count) - self.create_alarm_event(color="red", alarm_count=red_alarm_count) + if device_state.alarms["yellow"] != yellow_alarm_count: + device_state.alarms["yellow"] = yellow_alarm_count + self.create_alarm_event(color="yellow", alarm_count=yellow_alarm_count) + + if device_state.alarms["red"] != red_alarm_count: + device_state.alarms["red"] = red_alarm_count + self.create_alarm_event(color="red", alarm_count=red_alarm_count) async def _get_juniper_alarms(self): snmp = SNMP(self.device) @@ -38,13 +44,19 @@ async def _get_juniper_alarms(self): if red_alarm_count: red_alarm_count = red_alarm_count.value - if type(yellow_alarm_count) is not int or type(red_alarm_count) is not int: + if not isinstance(yellow_alarm_count, int) or not isinstance(red_alarm_count, int): _logger.error( - "Device %s returns alarm count not of type int, type yellow alarm count: %s, type red alarm count: %s", + "Device %s returns alarm count not of type int. " + "Yellow alarm count: type %s. Red alarm count: type %s.", self.device.name, type(yellow_alarm_count), type(red_alarm_count), ) + _logger.debug( + "Yellow alarm count: value %r. Red alarm count: value %r.", + yellow_alarm_count, + red_alarm_count, + ) raise TypeError return yellow_alarm_count, red_alarm_count @@ -58,7 +70,7 @@ def create_alarm_event(self, color: Literal["yellow", "red"], alarm_count: int): if created: alarm_event.state = EventState.OPEN alarm_event.add_history("Change state to Open") - if alarm_event.alarm_count != alarm_count: - old_alarm_count = alarm_event.alarm_count - alarm_event.alarm_count = alarm_count - alarm_event.add_log(f"{self.device.name} {color} alarms went from {old_alarm_count} to {alarm_count}") + + old_alarm_count = alarm_event.alarm_count + alarm_event.alarm_count = alarm_count + alarm_event.add_log(f"{self.device.name} {color} alarms went from {old_alarm_count} to {alarm_count}") diff --git a/tests/snmp_fixtures/juniper-alarm-zero.snmprec b/tests/snmp_fixtures/juniper-alarm-zero.snmprec new file mode 100644 index 000000000..12c4f24fa --- /dev/null +++ b/tests/snmp_fixtures/juniper-alarm-zero.snmprec @@ -0,0 +1,2 @@ +1.3.6.1.4.1.2636.3.4.2.2.2.0|66|0 +1.3.6.1.4.1.2636.3.4.2.3.2.0|66|0 diff --git a/tests/snmp_fixtures/juniper-alarm.snmprec b/tests/snmp_fixtures/juniper-alarm.snmprec index 830c1b00e..79fbcd9e2 100644 --- a/tests/snmp_fixtures/juniper-alarm.snmprec +++ b/tests/snmp_fixtures/juniper-alarm.snmprec @@ -1,2 +1,2 @@ -1.3.6.1.4.1.2636.3.4.2.2.2.0|66|0 +1.3.6.1.4.1.2636.3.4.2.2.2.0|66|1 1.3.6.1.4.1.2636.3.4.2.3.2.0|66|2 diff --git a/tests/tasks/test_juniperalarmtask.py b/tests/tasks/test_juniperalarmtask.py index b4a61850a..a6d030b42 100644 --- a/tests/tasks/test_juniperalarmtask.py +++ b/tests/tasks/test_juniperalarmtask.py @@ -8,11 +8,11 @@ class TestJuniperalarmTask: @pytest.mark.asyncio - async def test_task_runs_without_errors(self, snmpsim, juniper_alarm_task): + async def test_task_runs_without_errors(self, juniper_alarm_task): assert (await juniper_alarm_task.run()) is None @pytest.mark.asyncio - async def test_task_does_nothing_for_non_juniper_device(self, snmpsim, juniper_alarm_task): + async def test_task_does_nothing_for_non_juniper_device(self, juniper_alarm_task): task = juniper_alarm_task device_state = task.state.devices.get(device_name=task.device.name) device_state.enterprise_id = 11 @@ -22,7 +22,7 @@ async def test_task_does_nothing_for_non_juniper_device(self, snmpsim, juniper_a assert device_state.alarms is None @pytest.mark.asyncio - async def test_task_does_nothing_for_non_int_result(self, snmpsim, snmp_test_port): + async def test_task_does_nothing_for_non_int_result(self, snmp_test_port): device = PollDevice( name="buick.lab.example.org", address="127.0.0.1", @@ -38,7 +38,7 @@ async def test_task_does_nothing_for_non_int_result(self, snmpsim, snmp_test_por assert device_state.alarms is None @pytest.mark.asyncio - async def test_task_saves_alarm_count_in_device_state(self, snmpsim, juniper_alarm_task): + async def test_task_saves_alarm_count_in_device_state(self, juniper_alarm_task): task = juniper_alarm_task device_state = task.state.devices.get(device_name=task.device.name) device_state.enterprise_id = 2636 @@ -46,26 +46,26 @@ async def test_task_saves_alarm_count_in_device_state(self, snmpsim, juniper_ala await task.run() assert device_state.alarms - assert device_state.alarms["yellow"] == 0 + assert device_state.alarms["yellow"] == 1 assert device_state.alarms["red"] == 2 @pytest.mark.asyncio - async def test_task_overrides_alarm_count_in_device_state(self, snmpsim, juniper_alarm_task): + async def test_task_overrides_alarm_count_in_device_state(self, juniper_alarm_task): task = juniper_alarm_task device_state = task.state.devices.get(device_name=task.device.name) device_state.enterprise_id = 2636 device_state.alarms = { - "yellow": "1", - "red": "3", + "yellow": 2, + "red": 3, } await task.run() - assert device_state.alarms["yellow"] == 0 + assert device_state.alarms["yellow"] == 1 assert device_state.alarms["red"] == 2 @pytest.mark.asyncio - async def test_task_creates_alarm_events(self, snmpsim, juniper_alarm_task): + async def test_task_creates_both_alarm_events_on_both_counts_changed(self, juniper_alarm_task): task = juniper_alarm_task device_state = task.state.devices.get(device_name=task.device.name) device_state.enterprise_id = 2636 @@ -77,18 +77,37 @@ async def test_task_creates_alarm_events(self, snmpsim, juniper_alarm_task): assert yellow_event assert red_event - assert yellow_event.alarm_count == 0 + assert yellow_event.alarm_count == 1 assert red_event.alarm_count == 2 @pytest.mark.asyncio - async def test_task_updates_alarm_events(self, snmpsim, juniper_alarm_task): + async def test_task_creates_one_alarm_event_on_one_count_changed(self, juniper_alarm_task): + task = juniper_alarm_task + device_state = task.state.devices.get(device_name=task.device.name) + device_state.enterprise_id = 2636 + device_state.alarms = { + "yellow": 1, + "red": 0, + } + + await task.run() + + yellow_event = task.state.events.get(device_name=task.device.name, port="yellow", event_class=AlarmEvent) + red_event = task.state.events.get(device_name=task.device.name, port="red", event_class=AlarmEvent) + + assert not yellow_event + assert red_event + assert red_event.alarm_count == 2 + + @pytest.mark.asyncio + async def test_task_updates_alarm_events(self, juniper_alarm_task): task = juniper_alarm_task device_state = task.state.devices.get(device_name=task.device.name) device_state.enterprise_id = 2636 yellow_event, _ = task.state.events.get_or_create_event( device_name=task.device.name, port="yellow", event_class=AlarmEvent ) - yellow_event.alarm_count = 1 + yellow_event.alarm_count = 2 red_event, _ = task.state.events.get_or_create_event( device_name=task.device.name, port="red", event_class=AlarmEvent ) @@ -96,9 +115,47 @@ async def test_task_updates_alarm_events(self, snmpsim, juniper_alarm_task): await task.run() - assert yellow_event.alarm_count == 0 + assert yellow_event.alarm_count == 1 assert red_event.alarm_count == 2 + @pytest.mark.asyncio + async def test_task_does_not_create_alarm_events_on_unchanged_alarm_count(self, juniper_alarm_task): + task = juniper_alarm_task + device_state = task.state.devices.get(device_name=task.device.name) + device_state.enterprise_id = 2636 + device_state.alarms = { + "yellow": 1, + "red": 2, + } + + await task.run() + + yellow_event = task.state.events.get(device_name=task.device.name, port="yellow", event_class=AlarmEvent) + red_event = task.state.events.get(device_name=task.device.name, port="red", event_class=AlarmEvent) + + assert not yellow_event + assert not red_event + + @pytest.mark.asyncio + async def test_task_does_not_create_alarm_events_on_alarm_count_zero_on_first_run(self, snmp_test_port): + device = PollDevice( + name="buick.lab.example.org", + address="127.0.0.1", + community="juniper-alarm-zero", + port=snmp_test_port, + ) + state = ZinoState() + task = JuniperAlarmTask(device, state) + device_state = task.state.devices.get(device_name=task.device.name) + device_state.enterprise_id = 2636 + await task.run() + + yellow_event = task.state.events.get(device_name=task.device.name, port="yellow", event_class=AlarmEvent) + red_event = task.state.events.get(device_name=task.device.name, port="red", event_class=AlarmEvent) + + assert not yellow_event + assert not red_event + @pytest.fixture() def juniper_alarm_task(snmpsim, snmp_test_port):