From 7bfebc8796d5d9cd7cd0f52bdb38a316e6f2fd47 Mon Sep 17 00:00:00 2001 From: Mridul Bajpai Date: Mon, 18 Sep 2023 22:00:30 -0700 Subject: [PATCH 1/4] Initial support for voltage/current sensors --- src/sonic_ax_impl/mibs/__init__.py | 14 +++ .../ietf/physical_entity_sub_oid_generator.py | 18 +++ src/sonic_ax_impl/mibs/ietf/rfc2737.py | 106 ++++++++++++++++++ 3 files changed, 138 insertions(+) diff --git a/src/sonic_ax_impl/mibs/__init__.py b/src/sonic_ax_impl/mibs/__init__.py index 612d580f9..156cf07d4 100644 --- a/src/sonic_ax_impl/mibs/__init__.py +++ b/src/sonic_ax_impl/mibs/__init__.py @@ -134,6 +134,20 @@ def thermal_info_table(thermal_name): return "TEMPERATURE_INFO" + TABLE_NAME_SEPARATOR_VBAR + thermal_name +def voltage_sensor_info_table(sensor_name): + """ + :param: sensor_name : Voltage Sensor name + :return: voltage sensor info key + """ + return "VOLTAGE_INFO" + TABLE_NAME_SEPARATOR_VBAR + sensor_name + +def current_sensor_info_table(sensor_name): + """ + :param: sensor_name : Current Sensor name + :return: current sensor info key + """ + return "CURRENT_INFO" + TABLE_NAME_SEPARATOR_VBAR + sensor_name + def lldp_entry_table(if_name): """ :param if_name: given interface to cast. diff --git a/src/sonic_ax_impl/mibs/ietf/physical_entity_sub_oid_generator.py b/src/sonic_ax_impl/mibs/ietf/physical_entity_sub_oid_generator.py index 7882f8d74..b01717442 100644 --- a/src/sonic_ax_impl/mibs/ietf/physical_entity_sub_oid_generator.py +++ b/src/sonic_ax_impl/mibs/ietf/physical_entity_sub_oid_generator.py @@ -168,3 +168,21 @@ def get_transceiver_sensor_sub_id(ifindex, offset): transceiver_oid, = get_transceiver_sub_id(ifindex) return (transceiver_oid + offset,) + +def get_chassis_voltage_sensor_sub_id(position): + """ + Returns sub OID for voltage sensors that belong to chassis. Sub OID is calculated as follows: + sub OID = CHASSIS_MGMT_SUB_ID + DEVICE_TYPE_POWER_MONITOR + position * DEVICE_INDEX_MULTIPLE + SENSOR_TYPE_VOLTAGE, + :param position: voltage sensor position + :return: sub OID of the voltage sensor + """ + return (CHASSIS_MGMT_SUB_ID + DEVICE_TYPE_POWER_MONITOR + position * DEVICE_INDEX_MULTIPLE + SENSOR_TYPE_VOLTAGE, ) + +def get_chassis_current_sensor_sub_id(position): + """ + Returns sub OID for current sensors that belong to chassis. Sub OID is calculated as follows: + sub OID = CHASSIS_MGMT_SUB_ID + DEVICE_TYPE_POWER_MONITOR + position * DEVICE_INDEX_MULTIPLE + SENSOR_TYPE_CURRENT, + :param position: current sensor position + :return: sub OID of the current sensor + """ + return (CHASSIS_MGMT_SUB_ID + DEVICE_TYPE_POWER_MONITOR + position * DEVICE_INDEX_MULTIPLE + SENSOR_TYPE_CURRENT, ) diff --git a/src/sonic_ax_impl/mibs/ietf/rfc2737.py b/src/sonic_ax_impl/mibs/ietf/rfc2737.py index 7a241567c..397eb0249 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc2737.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc2737.py @@ -21,6 +21,8 @@ from .physical_entity_sub_oid_generator import get_psu_sensor_sub_id from .physical_entity_sub_oid_generator import get_transceiver_sub_id from .physical_entity_sub_oid_generator import get_transceiver_sensor_sub_id +from .physical_entity_sub_oid_generator import get_chassis_voltage_sensor_sub_id +from .physical_entity_sub_oid_generator import get_chassis_current_sensor_sub_id from .sensor_data import TransceiverSensorData @unique @@ -111,6 +113,24 @@ class ThermalInfoDB(str, Enum): REPLACEABLE = 'is_replaceable' +@unique +class VoltageSensorInfoDB(str, Enum): + """ + Voltage sensor info keys + """ + VOLTAGE = 'voltage' + REPLACEABLE = 'is_replaceable' + + +@unique +class CurrentSensorInfoDB(str, Enum): + """ + Current Sensor info keys + """ + CURRENT = 'current' + REPLACEABLE = 'is_replaceable' + + # Map used to generate PSU sensor description PSU_SENSOR_NAME_MAP = { 'temperature': 'Temperature', @@ -1037,6 +1057,92 @@ def _update_entity_cache(self, thermal_name): else: self._remove_entity_cache(thermal_name) +@physical_entity_updater() +class VoltageSensorCacheUpdater(PhysicalEntityCacheUpdater): + KEY_PATTERN = mibs.voltage_sensor_info_table("*") + + def __init__(self, mib_updater): + super(VoltageSensorCacheUpdater, self).__init__(mib_updater) + + def get_key_pattern(self): + return VoltageSensorCacheUpdater.KEY_PATTERN + + def _update_entity_cache(self, voltage_sensor_name): + voltage_sensor_info = Namespace.dbs_get_all(self.mib_updater.statedb, mibs.STATE_DB, + mibs.voltage_sensor_info_table(voltage_sensor_name)) + if not voltage_sensor_info: + return + + voltage, replaceable = get_db_data(voltage_sensor_info, VoltageSensorInfoDB) + if voltage and not is_null_str(voltage): + voltage_sensor_relation_info = self.get_physical_relation_info(voltage_sensor_name) + if not voltage_sensor_relation_info: + return + voltage_sensor_position, voltage_sensor_parent_name = get_db_data(voltage_sensor_relation_info, PhysicalRelationInfoDB) + voltage_sensor_position = int(voltage_sensor_position) + + # only process voltage_sensors belong to chassis here, voltage_sensors belong to other + # physical entity will be processed in other entity updater, for example + # PSU voltage_sensor will be processed by PsuCacheUpdater + if voltage_sensor_parent_name in self.mib_updater.physical_name_to_oid_map and \ + self.mib_updater.physical_name_to_oid_map[voltage_sensor_parent_name] == (CHASSIS_SUB_ID,): + voltage_sensor_sub_id = get_chassis_voltage_sensor_sub_id(voltage_sensor_position) + self._add_entity_related_oid(voltage_sensor_name, voltage_sensor_sub_id) + + # add voltage_sensor to available OID list + self.mib_updater.add_sub_id(voltage_sensor_sub_id) + self.mib_updater.set_phy_class(voltage_sensor_sub_id, PhysicalClass.SENSOR) + self.mib_updater.set_phy_descr(voltage_sensor_sub_id, voltage_sensor_name) + self.mib_updater.set_phy_name(voltage_sensor_sub_id, voltage_sensor_name) + self.mib_updater.set_phy_parent_relative_pos(voltage_sensor_sub_id, voltage_sensor_position) + self.mib_updater.set_phy_contained_in(voltage_sensor_sub_id, CHASSIS_MGMT_SUB_ID) + self.mib_updater.set_phy_fru(voltage_sensor_sub_id, replaceable) + else: + self._remove_entity_cache(voltage_sensor_name) + +@physical_entity_updater() +class CurrentSensorCacheUpdater(PhysicalEntityCacheUpdater): + KEY_PATTERN = mibs.current_sensor_info_table("*") + + def __init__(self, mib_updater): + super(CurrentSensorCacheUpdater, self).__init__(mib_updater) + + def get_key_pattern(self): + return CurrentSensorCacheUpdater.KEY_PATTERN + + def _update_entity_cache(self, current_sensor_name): + current_sensor_info = Namespace.dbs_get_all(self.mib_updater.statedb, mibs.STATE_DB, + mibs.current_sensor_info_table(current_sensor_name)) + if not current_sensor_info: + return + + current, replaceable = get_db_data(current_sensor_info, CurrentSensorInfoDB) + if current and not is_null_str(current): + current_sensor_relation_info = self.get_physical_relation_info(current_sensor_name) + if not current_sensor_relation_info: + return + current_sensor_position, current_sensor_parent_name = get_db_data(current_sensor_relation_info, PhysicalRelationInfoDB) + current_sensor_position = int(current_sensor_position) + + # only process current_sensors belong to chassis here, current_sensors belong to other + # physical entity will be processed in other entity updater, for example + # PSU current_sensor will be processed by PsuCacheUpdater + if current_sensor_parent_name in self.mib_updater.physical_name_to_oid_map and \ + self.mib_updater.physical_name_to_oid_map[current_sensor_parent_name] == (CHASSIS_SUB_ID,): + current_sensor_sub_id = get_chassis_current_sensor_sub_id(current_sensor_position) + self._add_entity_related_oid(current_sensor_name, current_sensor_sub_id) + + # add current_sensor to available OID list + self.mib_updater.add_sub_id(current_sensor_sub_id) + self.mib_updater.set_phy_class(current_sensor_sub_id, PhysicalClass.SENSOR) + self.mib_updater.set_phy_descr(current_sensor_sub_id, current_sensor_name) + self.mib_updater.set_phy_name(current_sensor_sub_id, current_sensor_name) + self.mib_updater.set_phy_parent_relative_pos(current_sensor_sub_id, current_sensor_position) + self.mib_updater.set_phy_contained_in(current_sensor_sub_id, CHASSIS_MGMT_SUB_ID) + self.mib_updater.set_phy_fru(current_sensor_sub_id, replaceable) + else: + self._remove_entity_cache(current_sensor_name) + class PhysicalTableMIB(metaclass=MIBMeta, prefix='.1.3.6.1.2.1.47.1.1.1'): """ From 2fa034689e5d02762328ca62fab252ccd87ca70a Mon Sep 17 00:00:00 2001 From: Mridul Bajpai Date: Thu, 21 Sep 2023 15:59:42 -0700 Subject: [PATCH 2/4] Fixed comment --- src/sonic_ax_impl/mibs/ietf/rfc2737.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sonic_ax_impl/mibs/ietf/rfc2737.py b/src/sonic_ax_impl/mibs/ietf/rfc2737.py index 397eb0249..7925e31d7 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc2737.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc2737.py @@ -1081,9 +1081,8 @@ def _update_entity_cache(self, voltage_sensor_name): voltage_sensor_position, voltage_sensor_parent_name = get_db_data(voltage_sensor_relation_info, PhysicalRelationInfoDB) voltage_sensor_position = int(voltage_sensor_position) - # only process voltage_sensors belong to chassis here, voltage_sensors belong to other - # physical entity will be processed in other entity updater, for example - # PSU voltage_sensor will be processed by PsuCacheUpdater + # only process voltage_sensors belonging to chassis here, voltage_sensors belong to other + # physical entity will be processed in other entity updater if voltage_sensor_parent_name in self.mib_updater.physical_name_to_oid_map and \ self.mib_updater.physical_name_to_oid_map[voltage_sensor_parent_name] == (CHASSIS_SUB_ID,): voltage_sensor_sub_id = get_chassis_voltage_sensor_sub_id(voltage_sensor_position) @@ -1125,8 +1124,7 @@ def _update_entity_cache(self, current_sensor_name): current_sensor_position = int(current_sensor_position) # only process current_sensors belong to chassis here, current_sensors belong to other - # physical entity will be processed in other entity updater, for example - # PSU current_sensor will be processed by PsuCacheUpdater + # physical entity will be processed in other entity updater if current_sensor_parent_name in self.mib_updater.physical_name_to_oid_map and \ self.mib_updater.physical_name_to_oid_map[current_sensor_parent_name] == (CHASSIS_SUB_ID,): current_sensor_sub_id = get_chassis_current_sensor_sub_id(current_sensor_position) From e57a2173570cc8c907dc4a055e59ec6f87bcd9f4 Mon Sep 17 00:00:00 2001 From: Mridul Bajpai Date: Sun, 24 Sep 2023 23:33:08 -0700 Subject: [PATCH 3/4] Added UT --- tests/mock_tables/global_db/state_db.json | 16 +++++++++++++++ tests/mock_tables/state_db.json | 16 +++++++++++++++ tests/test_sn.py | 25 +++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/tests/mock_tables/global_db/state_db.json b/tests/mock_tables/global_db/state_db.json index 0674d83ab..6e73d90c8 100644 --- a/tests/mock_tables/global_db/state_db.json +++ b/tests/mock_tables/global_db/state_db.json @@ -98,6 +98,14 @@ "position_in_parent": "1", "parent_name": "PSU 2" }, + "PHYSICAL_ENTITY_INFO|current1": { + "position_in_parent": 1, + "parent_name": "chassis 1" + }, + "PHYSICAL_ENTITY_INFO|voltage1": { + "position_in_parent": 1, + "parent_name": "chassis 1" + }, "FAN_DRAWER_INFO|drawer1": { "model": "DRAWERMODEL", "serial": "DRAWERSERIAL", @@ -120,6 +128,14 @@ "serial": "PSUFANSERIAL", "is_replaceable": "False" }, + "VOLTAGE_INFO|voltage1": { + "voltage": "10", + "is_replaceable": "False" + }, + "CURRENT_INFO|current1": { + "current": "10", + "is_replaceable": "False" + }, "TEMPERATURE_INFO|thermal1": { "temperature": "20.5", "is_replaceable": "False" diff --git a/tests/mock_tables/state_db.json b/tests/mock_tables/state_db.json index abccdb386..2180d8e9e 100644 --- a/tests/mock_tables/state_db.json +++ b/tests/mock_tables/state_db.json @@ -122,6 +122,14 @@ "position_in_parent": "1", "parent_name": "PSU 2" }, + "PHYSICAL_ENTITY_INFO|voltage1": { + "position_in_parent": 1, + "parent_name": "chassis 1" + }, + "PHYSICAL_ENTITY_INFO|current1": { + "position_in_parent": 1, + "parent_name": "chassis 1" + }, "FAN_DRAWER_INFO|drawer1": { "model": "DRAWERMODEL", "serial": "DRAWERSERIAL", @@ -148,6 +156,14 @@ "temperature": "20.5", "is_replaceable": "False" }, + "CURRENT_INFO|current1": { + "current": "10", + "is_replaceable": "False" + }, + "VOLTAGE_INFO|voltage1": { + "voltage": "10", + "is_replaceable": "False" + }, "NEIGH_STATE_TABLE|10.0.0.57": { "state" : "6402" }, diff --git a/tests/test_sn.py b/tests/test_sn.py index e71971aac..eaa46f2d2 100644 --- a/tests/test_sn.py +++ b/tests/test_sn.py @@ -20,6 +20,7 @@ from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import get_psu_sensor_sub_id, get_psu_sub_id, get_fan_drawer_sub_id from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import get_fan_sub_id, get_fan_tachometers_sub_id from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import get_chassis_thermal_sub_id, get_transceiver_sub_id +from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import get_chassis_current_sensor_sub_id, get_chassis_voltage_sensor_sub_id from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import get_transceiver_sensor_sub_id from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import SENSOR_TYPE_TEMP from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import SENSOR_TYPE_VOLTAGE @@ -184,6 +185,30 @@ def test_getpdu_thermal_info(self): } self._check_getpdu(sub_id, expected_mib) + def test_getpdu_voltage_info(self): + sub_id = get_chassis_voltage_sensor_sub_id(1)[0] + expected_mib = { + 2: (ValueType.OCTET_STRING, "voltage1"), + 4: (ValueType.INTEGER, CHASSIS_MGMT_SUB_ID), + 5: (ValueType.INTEGER, PhysicalClass.SENSOR), + 6: (ValueType.INTEGER, 1), + 7: (ValueType.OCTET_STRING, "voltage1"), + 16: (ValueType.INTEGER, 2) + } + self._check_getpdu(sub_id, expected_mib) + + def test_getpdu_current_info(self): + sub_id = get_chassis_current_sensor_sub_id(1)[0] + expected_mib = { + 2: (ValueType.OCTET_STRING, "current1"), + 4: (ValueType.INTEGER, CHASSIS_MGMT_SUB_ID), + 5: (ValueType.INTEGER, PhysicalClass.SENSOR), + 6: (ValueType.INTEGER, 1), + 7: (ValueType.OCTET_STRING, "current1"), + 16: (ValueType.INTEGER, 2) + } + self._check_getpdu(sub_id, expected_mib) + def test_getpdu_xcvr_info(self): sub_id = get_transceiver_sub_id(1)[0] From 648a50119a720ab641a9d61c74eea1f0d83d9070 Mon Sep 17 00:00:00 2001 From: Mridul Bajpai Date: Thu, 28 Sep 2023 13:58:46 -0700 Subject: [PATCH 4/4] SensorMIB support for voltage and current sensors --- src/sonic_ax_impl/mibs/ietf/rfc3433.py | 138 +++++++++++++++++++++ src/sonic_ax_impl/mibs/ietf/sensor_data.py | 69 +++++++++++ tests/mock_tables/global_db/state_db.json | 4 +- tests/mock_tables/state_db.json | 4 +- tests/test_sensor.py | 34 +++++ 5 files changed, 245 insertions(+), 4 deletions(-) diff --git a/src/sonic_ax_impl/mibs/ietf/rfc3433.py b/src/sonic_ax_impl/mibs/ietf/rfc3433.py index 89be78327..77250e849 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc3433.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc3433.py @@ -18,7 +18,10 @@ from .physical_entity_sub_oid_generator import get_psu_sub_id from .physical_entity_sub_oid_generator import get_psu_sensor_sub_id from .physical_entity_sub_oid_generator import get_chassis_thermal_sub_id +from .physical_entity_sub_oid_generator import get_chassis_voltage_sensor_sub_id +from .physical_entity_sub_oid_generator import get_chassis_current_sensor_sub_id from .sensor_data import ThermalSensorData, FANSensorData, PSUSensorData, TransceiverSensorData +from .sensor_data import VoltageSensorData, CurrentSensorData NOT_AVAILABLE = 'N/A' CHASSIS_NAME_SUB_STRING = 'chassis' @@ -337,6 +340,33 @@ class ThermalSensor(SensorInterface): 'temperature': ThermalSensor }) +class VoltageSensor(SensorInterface): + """ + Voltage sensor. + """ + + TYPE = EntitySensorDataType.VOLTS_DC + SCALE = EntitySensorDataScale.MILLI + PRECISION = 0 + + +VoltageSensorData.bind_sensor_interface({ + 'voltage': VoltageSensor +}) + +class CurrentSensor(SensorInterface): + """ + Current sensor. + """ + + TYPE = EntitySensorDataType.AMPERES + SCALE = EntitySensorDataScale.MILLI + PRECISION = 0 + + +CurrentSensorData.bind_sensor_interface({ + 'current': CurrentSensor +}) class PhysicalSensorTableMIBUpdater(MIBUpdater): """ @@ -347,6 +377,8 @@ class PhysicalSensorTableMIBUpdater(MIBUpdater): PSU_SENSOR_KEY_PATTERN = mibs.psu_info_table("*") FAN_SENSOR_KEY_PATTERN = mibs.fan_info_table("*") THERMAL_SENSOR_KEY_PATTERN = mibs.thermal_info_table("*") + VOLTAGE_SENSOR_KEY_PATTERN = mibs.voltage_sensor_info_table("*") + CURRENT_SENSOR_KEY_PATTERN = mibs.current_sensor_info_table("*") def __init__(self): """ @@ -373,6 +405,8 @@ def __init__(self): self.psu_sensor = [] self.thermal_sensor = [] self.broken_transceiver_info = [] + self.voltage_sensor = [] + self.current_sensor = [] def reinit_data(self): """ @@ -407,6 +441,16 @@ def reinit_data(self): if thermal_sensor_encoded: self.thermal_sensor = [entry for entry in thermal_sensor_encoded] + voltage_sensor_encoded = self.statedb[HOST_NAMESPACE_DB_IDX].keys(self.statedb[HOST_NAMESPACE_DB_IDX].STATE_DB, + self.VOLTAGE_SENSOR_KEY_PATTERN) + if voltage_sensor_encoded: + self.voltage_sensor = [entry for entry in voltage_sensor_encoded] + + current_sensor_encoded = self.statedb[HOST_NAMESPACE_DB_IDX].keys(self.statedb[HOST_NAMESPACE_DB_IDX].STATE_DB, + self.CURRENT_SENSOR_KEY_PATTERN) + if current_sensor_encoded: + self.current_sensor = [entry for entry in current_sensor_encoded] + def update_xcvr_dom_data(self): if not self.transceiver_dom: return @@ -617,6 +661,96 @@ def update_thermal_sensor_data(self): self.sub_ids.append(sub_id) + def update_voltage_sensor_data(self): + if not self.voltage_sensor: + return + + for voltage_sensor_entry in self.voltage_sensor: + voltage_name = voltage_sensor_entry.split(mibs.TABLE_NAME_SEPARATOR_VBAR)[-1] + voltage_relation_info = self.statedb[HOST_NAMESPACE_DB_IDX].get_all( + self.statedb[HOST_NAMESPACE_DB_IDX].STATE_DB, mibs.physical_entity_info_table(voltage_name)) + voltage_position, voltage_parent_name = get_db_data(voltage_relation_info, PhysicalRelationInfoDB) + + if is_null_empty_str(voltage_parent_name) or is_null_empty_str(voltage_parent_name) or \ + CHASSIS_NAME_SUB_STRING not in voltage_parent_name.lower(): + continue + + voltage_position = int(voltage_position) + + voltage_sensor_entry_data = self.statedb[HOST_NAMESPACE_DB_IDX].get_all( + self.statedb[HOST_NAMESPACE_DB_IDX].STATE_DB, voltage_sensor_entry) + + if not voltage_sensor_entry_data: + continue + + sensor_data_list = VoltageSensorData.create_sensor_data(voltage_sensor_entry_data) + for sensor_data in sensor_data_list: + raw_sensor_value = sensor_data.get_raw_value() + if is_null_empty_str(raw_sensor_value): + continue + sensor = sensor_data.get_sensor_interface() + sub_id = get_chassis_voltage_sensor_sub_id(voltage_position) + + try: + mib_values = sensor.mib_values(raw_sensor_value) + except (ValueError, ArithmeticError): + mibs.logger.error("Exception occurred when converting" + "value for sensor {} : {}".format(sensor, voltage_name)) + continue + else: + self.ent_phy_sensor_type_map[sub_id], \ + self.ent_phy_sensor_scale_map[sub_id], \ + self.ent_phy_sensor_precision_map[sub_id], \ + self.ent_phy_sensor_value_map[sub_id], \ + self.ent_phy_sensor_oper_state_map[sub_id] = mib_values + + self.sub_ids.append(sub_id) + + def update_current_sensor_data(self): + if not self.current_sensor: + return + + for current_sensor_entry in self.current_sensor: + current_name = current_sensor_entry.split(mibs.TABLE_NAME_SEPARATOR_VBAR)[-1] + current_relation_info = self.statedb[HOST_NAMESPACE_DB_IDX].get_all( + self.statedb[HOST_NAMESPACE_DB_IDX].STATE_DB, mibs.physical_entity_info_table(current_name)) + current_position, current_parent_name = get_db_data(current_relation_info, PhysicalRelationInfoDB) + + if is_null_empty_str(current_parent_name) or is_null_empty_str(current_parent_name) or \ + CHASSIS_NAME_SUB_STRING not in current_parent_name.lower(): + continue + + current_position = int(current_position) + + current_sensor_entry_data = self.statedb[HOST_NAMESPACE_DB_IDX].get_all( + self.statedb[HOST_NAMESPACE_DB_IDX].STATE_DB, current_sensor_entry) + + if not current_sensor_entry_data: + continue + + sensor_data_list = CurrentSensorData.create_sensor_data(current_sensor_entry_data) + for sensor_data in sensor_data_list: + raw_sensor_value = sensor_data.get_raw_value() + if is_null_empty_str(raw_sensor_value): + continue + sensor = sensor_data.get_sensor_interface() + sub_id = get_chassis_current_sensor_sub_id(current_position) + + try: + mib_values = sensor.mib_values(raw_sensor_value) + except (ValueError, ArithmeticError): + mibs.logger.error("Exception occurred when converting" + "value for sensor {} : {}".format(sensor, current_name)) + continue + else: + self.ent_phy_sensor_type_map[sub_id], \ + self.ent_phy_sensor_scale_map[sub_id], \ + self.ent_phy_sensor_precision_map[sub_id], \ + self.ent_phy_sensor_value_map[sub_id], \ + self.ent_phy_sensor_oper_state_map[sub_id] = mib_values + + self.sub_ids.append(sub_id) + def update_data(self): """ Update sensors cache. @@ -632,6 +766,10 @@ def update_data(self): self.update_thermal_sensor_data() + self.update_voltage_sensor_data() + + self.update_current_sensor_data() + self.sub_ids.sort() def get_next(self, sub_id): diff --git a/src/sonic_ax_impl/mibs/ietf/sensor_data.py b/src/sonic_ax_impl/mibs/ietf/sensor_data.py index 7f864e57a..471a3601a 100644 --- a/src/sonic_ax_impl/mibs/ietf/sensor_data.py +++ b/src/sonic_ax_impl/mibs/ietf/sensor_data.py @@ -279,3 +279,72 @@ def create_sensor_data(cls, sensor_data_dict): sensor_data_list.append(sensor_data) return sensor_data_list + +class VoltageSensorData(BaseSensorData): + """ + Base Voltage sensor data class. Responsible for: + 1. Manage concrete sensor data class + 2. Create concrete sensor data instances + 3. Provide common logic for concrete sensor data class + """ + + sensor_attr_dict = { + 'voltage': { + 'pattern': 'voltage', + 'name': 'Voltage', + 'oid_offset_base': SENSOR_TYPE_VOLTAGE, + 'sort_factor': 0 + } + } + + @classmethod + def create_sensor_data(cls, sensor_data_dict): + """ + Create sensor data instances according to the sensor data got from redis + :param sensor_data_dict: sensor data got from redis + :return: A sorted sensor data instance list + """ + sensor_data_list = [] + for name, value in sensor_data_dict.items(): + for sensor_attrs in cls.sensor_attr_dict.values(): + match_result = re.fullmatch(sensor_attrs['pattern'], name) + if match_result: + sensor_data = VoltageSensorData(name, value, sensor_attrs, match_result) + sensor_data_list.append(sensor_data) + + return sensor_data_list + + +class CurrentSensorData(BaseSensorData): + """ + Base Current sensor data class. Responsible for: + 1. Manage concrete sensor data class + 2. Create concrete sensor data instances + 3. Provide common logic for concrete sensor data class + """ + + sensor_attr_dict = { + 'current': { + 'pattern': 'current', + 'name': 'Current', + 'oid_offset_base': SENSOR_TYPE_CURRENT, + 'sort_factor': 0 + } + } + + @classmethod + def create_sensor_data(cls, sensor_data_dict): + """ + Create sensor data instances according to the sensor data got from redis + :param sensor_data_dict: sensor data got from redis + :return: A sorted sensor data instance list + """ + sensor_data_list = [] + for name, value in sensor_data_dict.items(): + for sensor_attrs in cls.sensor_attr_dict.values(): + match_result = re.fullmatch(sensor_attrs['pattern'], name) + if match_result: + sensor_data = CurrentSensorData(name, value, sensor_attrs, match_result) + sensor_data_list.append(sensor_data) + + return sensor_data_list diff --git a/tests/mock_tables/global_db/state_db.json b/tests/mock_tables/global_db/state_db.json index 6e73d90c8..3d4d5a08b 100644 --- a/tests/mock_tables/global_db/state_db.json +++ b/tests/mock_tables/global_db/state_db.json @@ -129,11 +129,11 @@ "is_replaceable": "False" }, "VOLTAGE_INFO|voltage1": { - "voltage": "10", + "voltage": "54000", "is_replaceable": "False" }, "CURRENT_INFO|current1": { - "current": "10", + "current": "10000", "is_replaceable": "False" }, "TEMPERATURE_INFO|thermal1": { diff --git a/tests/mock_tables/state_db.json b/tests/mock_tables/state_db.json index 2180d8e9e..3a1438189 100644 --- a/tests/mock_tables/state_db.json +++ b/tests/mock_tables/state_db.json @@ -157,11 +157,11 @@ "is_replaceable": "False" }, "CURRENT_INFO|current1": { - "current": "10", + "current": "10000", "is_replaceable": "False" }, "VOLTAGE_INFO|voltage1": { - "voltage": "10", + "voltage": "54000", "is_replaceable": "False" }, "NEIGH_STATE_TABLE|10.0.0.57": { diff --git a/tests/test_sensor.py b/tests/test_sensor.py index 0b8a80af1..bf4be440c 100644 --- a/tests/test_sensor.py +++ b/tests/test_sensor.py @@ -22,6 +22,8 @@ from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import get_fan_sub_id from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import get_fan_tachometers_sub_id from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import get_chassis_thermal_sub_id +from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import get_chassis_voltage_sensor_sub_id +from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import get_chassis_current_sensor_sub_id from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import SENSOR_TYPE_TEMP from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import SENSOR_TYPE_VOLTAGE from sonic_ax_impl.mibs.ietf.physical_entity_sub_oid_generator import SENSOR_TYPE_PORT_RX_POWER @@ -43,6 +45,8 @@ def setUpClass(cls): cls.FAN_POSITION = 1 cls.PSU_FAN_POSITION = 1 cls.THERMAL_POSITION = 1 + cls.VOLTAGE_SENSOR_POSITION = 1 + cls.CURRENT_SENSOR_POSITION = 1 # Update MIBs for updater in cls.lut.updater_instances: @@ -400,3 +404,33 @@ def test_getpdu_chassis_temp_sensor(self): ] self._test_getpdu_sensor(get_chassis_thermal_sub_id(self.THERMAL_POSITION)[0], expected_values) + + def test_getpdu_chassis_voltage_sensor(self): + """ + Test case for correctness of chassis voltage sensors MIB values + """ + + expected_values = [ + rfc3433.EntitySensorDataType.VOLTS_DC, + rfc3433.EntitySensorDataScale.MILLI, + 0, # precision + 54000, # expected sensor value + rfc3433.EntitySensorStatus.OK + ] + + self._test_getpdu_sensor(get_chassis_voltage_sensor_sub_id(self.VOLTAGE_SENSOR_POSITION)[0], expected_values) + + def test_getpdu_chassis_current_sensor(self): + """ + Test case for correctness of chassis voltage sensors MIB values + """ + + expected_values = [ + rfc3433.EntitySensorDataType.AMPERES, + rfc3433.EntitySensorDataScale.MILLI, + 0, # precision + 10000, # expected sensor value + rfc3433.EntitySensorStatus.OK + ] + + self._test_getpdu_sensor(get_chassis_current_sensor_sub_id(self.CURRENT_SENSOR_POSITION)[0], expected_values)