From 3f5ccdb0fbd89f465b8b2fb77bea6a90553062b4 Mon Sep 17 00:00:00 2001
From: "Th.L" <thl-cmk@outlook.com>
Date: Mon, 22 Mar 2021 18:15:03 +0100
Subject: [PATCH] update project

---
 agent_based/cisco_asa_sensors.py |  99 ++++++++++++++++++-------------
 cisco_asa_sensors.mkp            | Bin 3560 -> 3683 bytes
 2 files changed, 58 insertions(+), 41 deletions(-)

diff --git a/agent_based/cisco_asa_sensors.py b/agent_based/cisco_asa_sensors.py
index fb528a4..53cec87 100644
--- a/agent_based/cisco_asa_sensors.py
+++ b/agent_based/cisco_asa_sensors.py
@@ -90,6 +90,8 @@
 #   ['Chassis Ambient Temperature Sensor 1', '8', '32', '1', 'celsius'],
 #   ['Chassis Ambient Temperature Sensor 2', '8', '30', '1', 'celsius'],
 #   ['Chassis Ambient Temperature Sensor 3', '8', '33', '1', 'celsius'],
+#   ['Power supply 1', '12', '', '3', ''],
+#   ['Power supply 2', '12', '', '1', ''],
 #   ['Gi0/0', '', '', '', ''],
 #   ['Gi0/1', '', '', '', ''],
 #   ['Gi0/2', '', '', '', ''],
@@ -104,30 +106,36 @@
 # ]
 #
 # sample section
-# {'fan': {
-#    'Chassis Sensor 1': CiscoAsaSensor(value=7680, status=<State.OK: 0>, state_readable='Ok', unit='rpm'),
-#    'Chassis Sensor 2': CiscoAsaSensor(value=7936, status=<State.OK: 0>, state_readable='Ok', unit='rpm'),
-#    'Chassis Sensor 3': CiscoAsaSensor(value=7680, status=<State.OK: 0>, state_readable='Ok', unit='rpm')
-#   },
-#  'temp': {
-#    'CPU Sensor 0/0': CiscoAsaSensor(value=34.0, status=<State.OK: 0>, state_readable='Ok', unit='celsius'),
-#    'Chassis Ambient Sensor 1': CiscoAsaSensor(value=32.0, status=<State.OK: 0>, state_readable='Ok', unit='celsius'),
-#    'Chassis Ambient Sensor 2': CiscoAsaSensor(value=30.0, status=<State.OK: 0>, state_readable='Ok', unit='celsius'),
-#    'Chassis Ambient Sensor 3': CiscoAsaSensor(value=33.0, status=<State.OK: 0>, state_readable='Ok', unit='celsius')
-#   },
-#  'power': {}}
+# CiscoAsaSensors(
+#     temp={
+#         'CPU Sensor 0/0': CiscoAsaTempSensor(value=34.0, state=State.OK, status=0, status_readable='Ok',
+#                                              unit='celsius'),
+#         'Chassis Ambient Sensor 1': CiscoAsaTempSensor(value=32.0, state=State.OK, status=0,
+#                                                        status_readable='Ok', unit='celsius'),
+#         'Chassis Ambient Sensor 2': CiscoAsaTempSensor(value=30.0, state=State.OK, status=0,
+#                                                        status_readable='Ok', unit='celsius'),
+#         'Chassis Ambient Sensor 3': CiscoAsaTempSensor(value=33.0, state=State.OK, status=0,
+#                                                        status_readable='Ok', unit='celsius')},
+#     fan={
+#         'Chassis Sensor 1': CiscoAsaFanSensor(value=7680, state=State.OK, status_readable='Ok', unit='rpm'),
+#         'Chassis Sensor 2': CiscoAsaFanSensor(value=7936, state=State.OK, status_readable='Ok', unit='rpm'),
+#         'Chassis Sensor 3': CiscoAsaFanSensor(value=7680, state=State.OK, status_readable='Ok',
+#                                               unit='rpm')},
+#     power={'supply 1': CiscoAsaPowerSensor(state=State.CRIT, status_readable='nonoperational'),
+#            'supply 2': CiscoAsaPowerSensor(state=State.OK, status_readable='Ok')
+#            })
 #
 
 
-from typing import Dict, List, NamedTuple, Mapping
+from typing import List, NamedTuple, Mapping
 
-from .agent_based_api.v1.type_defs import (
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
     DiscoveryResult,
     CheckResult,
     StringTable,
 )
 
-from .agent_based_api.v1 import (
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
     register,
     Service,
     Result,
@@ -137,7 +145,7 @@ from .agent_based_api.v1 import (
     startswith,
 )
 
-from .utils.temperature import (
+from cmk.base.plugins.agent_based.utils.temperature import (
     check_temperature,
     TempParamType,
     to_celsius,
@@ -151,25 +159,33 @@ from .utils.temperature import (
 # ##################################################################################################
 
 
-class CiscoAsaSensor(NamedTuple):
+class CiscoAsaTempSensor(NamedTuple):
     value: float
     state: State
-    state_readable: str
+    status: int
+    status_readable: str
+    unit: str
+
+
+class CiscoAsaFanSensor(NamedTuple):
+    value: int
+    state: State
+    status_readable: str
     unit: str
 
 
 class CiscoAsaPowerSensor(NamedTuple):
     state: State
-    state_readable: str
+    status_readable: str
 
 
-class CiscoasaSensors(NamedTuple):
-    fan: Mapping[str, CiscoAsaSensor]
-    temp: Mapping[str, CiscoAsaSensor]
+class CiscoAsaSensors(NamedTuple):
+    fan: Mapping[str, CiscoAsaFanSensor]
+    temp: Mapping[str, CiscoAsaTempSensor]
     power: Mapping[str, CiscoAsaPowerSensor]
 
 
-def get_state_readable(st: str) -> str:
+def get_status_readable(st: str) -> str:
     states = {
         '1': 'Ok',
         '2': 'unavailable',
@@ -187,7 +203,7 @@ def get_sensor_state(st: str) -> State:
     return states.get(st, State.CRIT)
 
 
-def parse_cisco_asa_sensors(string_table: List[StringTable]) -> CiscoasaSensors:
+def parse_cisco_asa_sensors(string_table: List[StringTable]) -> CiscoAsaSensors:
     temp = {}
     fan = {}
     power = {}
@@ -195,28 +211,29 @@ def parse_cisco_asa_sensors(string_table: List[StringTable]) -> CiscoasaSensors:
     for sensorname, sensortype, sensorvalue, sensorstatus, sensorunits in string_table[0]:
         if sensorname != '':  # for asa context, there are no real sensors.
             if sensortype == '8':  # Temperature
-                temp.update({sensorname.replace('Temperature ', ''): CiscoAsaSensor(
+                temp.update({sensorname.replace('Temperature ', ''): CiscoAsaTempSensor(
                     value=to_celsius(float(sensorvalue), sensorunits),
                     unit=sensorunits,
                     state=get_sensor_state(sensorstatus),
-                    state_readable=get_state_readable(sensorstatus),
+                    status=int(sensorstatus) - 1,
+                    status_readable=get_status_readable(sensorstatus),
                 )})
 
             if sensortype == '10':  # Fan
-                fan.update({sensorname.replace('Fan ', ''): CiscoAsaSensor(
+                fan.update({sensorname.replace('Fan ', ''): CiscoAsaFanSensor(
                     value=int(sensorvalue),
                     unit=sensorunits,
                     state=get_sensor_state(sensorstatus),
-                    state_readable=get_state_readable(sensorstatus),
+                    status_readable=get_status_readable(sensorstatus),
                 )})
 
             if sensortype == '12':  # Power supply
                 power.update({sensorname.replace('Power ', ''): CiscoAsaPowerSensor(
                     state=get_sensor_state(sensorstatus),
-                    state_readable=get_state_readable(sensorstatus),
+                    status_readable=get_status_readable(sensorstatus),
                 )})
 
-    return CiscoasaSensors(temp=temp, fan=fan, power=power)
+    return CiscoAsaSensors(temp=temp, fan=fan, power=power)
 
 
 register.snmp_section(
@@ -245,23 +262,23 @@ register.snmp_section(
 # ##################################################################################################
 
 
-def discovery_cisco_asa_temp(section: CiscoasaSensors) -> DiscoveryResult:
+def discovery_cisco_asa_temp(section: CiscoAsaSensors) -> DiscoveryResult:
     yield from (Service(item=item) for item in section.temp.keys())
 
 
-def check_cisco_asa_temp(item, params: TempParamType, section: CiscoasaSensors) -> CheckResult:
+def check_cisco_asa_temp(item, params: TempParamType, section: CiscoAsaSensors) -> CheckResult:
     try:
         sensor = section.temp[item]
     except KeyError:
         return
 
-    yield Result(state=sensor.state, summary='Status: %s' % sensor.state_readable)
+    yield Result(state=sensor.state, summary='Status: %s' % sensor.status_readable)
 
     yield from check_temperature(
         sensor.value,
         dev_unit=sensor.unit,
-        dev_status=sensor.state,
-        dev_status_name=sensor.state_readable,
+        dev_status=sensor.status,
+        dev_status_name=sensor.status_readable,
         params=params,
         unique_name='check_cisco_asa_temp.%s' % item,
     )
@@ -285,17 +302,17 @@ register.check_plugin(
 # ##################################################################################################
 
 
-def discovery_cisco_asa_fan(section: CiscoasaSensors) -> DiscoveryResult:
+def discovery_cisco_asa_fan(section: CiscoAsaSensors) -> DiscoveryResult:
     yield from (Service(item=item) for item in section.fan.keys())
 
 
-def check_cisco_asa_fan(item, params, section: CiscoasaSensors) -> CheckResult:
+def check_cisco_asa_fan(item, params, section: CiscoAsaSensors) -> CheckResult:
     try:
         sensor = section.fan[item]
     except KeyError:
         return
 
-    yield Result(state=sensor.state, summary='Status: %s' % sensor.state_readable)
+    yield Result(state=sensor.state, summary='Status: %s' % sensor.status_readable)
 
     yield from check_levels(
         sensor.value,
@@ -324,17 +341,17 @@ register.check_plugin(
 #
 # ##################################################################################################
 
-def discovery_cisco_asa_power(section: CiscoasaSensors) -> DiscoveryResult:
+def discovery_cisco_asa_power(section: CiscoAsaSensors) -> DiscoveryResult:
     yield from (Service(item=item) for item in section.power.keys())
 
 
-def check_cisco_asa_power(item, section: CiscoasaSensors) -> CheckResult:
+def check_cisco_asa_power(item, section: CiscoAsaSensors) -> CheckResult:
     try:
         sensor = section.power[item]
     except KeyError:
         return
 
-    yield Result(state=sensor.state, summary='Status: %s' % sensor.state_readable)
+    yield Result(state=sensor.state, summary='Status: %s' % sensor.status_readable)
 
 
 register.check_plugin(
diff --git a/cisco_asa_sensors.mkp b/cisco_asa_sensors.mkp
index 58899b6953a29e18fb52a3e31257d12667aeab09..c1fdca6f88fcccbf81d9b509ec00c438193ad343 100644
GIT binary patch
literal 3683
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
Y`9D7Y|E9m&GbHj?2_ZdXMPy|E0hM+_UH||9

literal 3560
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
E03G%MdH?_b

-- 
GitLab