diff --git a/src/sonic_ax_impl/mibs/__init__.py b/src/sonic_ax_impl/mibs/__init__.py index 6fc528669..27dbe4812 100644 --- a/src/sonic_ax_impl/mibs/__init__.py +++ b/src/sonic_ax_impl/mibs/__init__.py @@ -46,6 +46,22 @@ redis_kwargs = {'unix_socket_path': '/var/run/redis/redis.sock'} +def chassis_info_table(chassis_name): + """ + :param: chassis_name: chassis name + :return: chassis info entry for this chassis + """ + + return "CHASSIS_INFO" + TABLE_NAME_SEPARATOR_VBAR + chassis_name + +def psu_info_table(psu_name): + """ + :param: psu_name: psu name + :return: psu info entry for this psu + """ + + return "PSU_INFO" + TABLE_NAME_SEPARATOR_VBAR + psu_name + def counter_table(sai_id): """ :param if_name: given sai_id to cast. diff --git a/src/sonic_ax_impl/mibs/vendor/cisco/ciscoEntityFruControlMIB.py b/src/sonic_ax_impl/mibs/vendor/cisco/ciscoEntityFruControlMIB.py index 5c6fa69b5..d7d15c802 100644 --- a/src/sonic_ax_impl/mibs/vendor/cisco/ciscoEntityFruControlMIB.py +++ b/src/sonic_ax_impl/mibs/vendor/cisco/ciscoEntityFruControlMIB.py @@ -1,14 +1,48 @@ -import imp -import re -import sys - +from enum import Enum, unique from sonic_ax_impl import mibs -from ax_interface import MIBMeta, ValueType, MIBUpdater, MIBEntry, SubtreeMIBEntry -from ax_interface.encodings import ObjectIdentifier +from ax_interface import MIBMeta, ValueType, SubtreeMIBEntry +from swsssdk import SonicV2Connector + +CHASSIS_INFO_KEY_TEMPLATE = 'chassis {}' +PSU_INFO_KEY_TEMPLATE = 'PSU {}' + +PSU_PRESENCE_OK = 'true' +PSU_STATUS_OK = 'true' + +@unique +class CHASSISInfoDB(bytes, Enum): + """ + CHASSIS info keys + """ + + PSU_NUM = b"psu_num" + +@unique +class PSUInfoDB(bytes, Enum): + """ + PSU info keys + """ + + PRESENCE = b"presence" + STATUS = b"status" + +def get_chassis_data(chassis_info): + """ + :param chassis_info: chassis info dict + :return: tuple (psu_num) of chassis; + Empty string if field not in chassis_info + """ + + return tuple(chassis_info.get(chassis_field.value, b"").decode() for chassis_field in CHASSISInfoDB) + +def get_psu_data(psu_info): + """ + :param psu_info: psu info dict + :return: tuple (presence, status) of psu; + Empty string if field not in psu_info + """ -PSU_PLUGIN_MODULE_NAME = 'psuutil' -PSU_PLUGIN_MODULE_PATH = "/usr/share/sonic/platform/plugins/{}.py".format(PSU_PLUGIN_MODULE_NAME) -PSU_PLUGIN_CLASS_NAME = 'PsuUtil' + return tuple(psu_info.get(psu_field.value, b"").decode() for psu_field in PSUInfoDB) class PowerStatusHandler: """ @@ -18,38 +52,57 @@ def __init__(self): """ init the handler """ - self.psuutil = None + self.statedb = SonicV2Connector() + self.statedb.connect(self.statedb.STATE_DB) - try: - module = imp.load_source(PSU_PLUGIN_MODULE_NAME, PSU_PLUGIN_MODULE_PATH) - except ImportError as e: - mibs.logger.error("Failed to load PSU module '%s': %s" % (PSU_PLUGIN_MODULE_NAME, str(e)), True) - return - except FileNotFoundError as e: - mibs.logger.error("Failed to get platform specific PSU module '%s': %s" % (PSU_PLUGIN_MODULE_NAME, str(e)), True) - return + def _get_num_psus(self): + """ + Get PSU number + :return: the number of supported PSU + """ + chassis_name = CHASSIS_INFO_KEY_TEMPLATE.format(1) + chassis_info = self.statedb.get_all(self.statedb.STATE_DB, mibs.chassis_info_table(chassis_name)) + num_psus = get_chassis_data(chassis_info) - try: - platform_psuutil_class = getattr(module, PSU_PLUGIN_CLASS_NAME) - self.psuutil = platform_psuutil_class() - except AttributeError as e: - mibs.logger.error("Failed to instantiate '%s' class: %s" % (PLATFORM_SPECIFIC_CLASS_NAME, str(e)), True) + return int(num_psus[0]) + + def _get_psu_presence(self, psu_index): + """ + Get PSU presence + :return: the presence of particular PSU + """ + psu_name = PSU_INFO_KEY_TEMPLATE.format(psu_index) + psu_info = self.statedb.get_all(self.statedb.STATE_DB, mibs.psu_info_table(psu_name)) + presence, status = get_psu_data(psu_info) + + return presence == PSU_PRESENCE_OK - def _getPsuIndex(self, sub_id): + def _get_psu_status(self, psu_index): + """ + Get PSU status + :return: the status of particular PSU + """ + psu_name = PSU_INFO_KEY_TEMPLATE.format(psu_index) + psu_info = self.statedb.get_all(self.statedb.STATE_DB, mibs.psu_info_table(psu_name)) + presence, status = get_psu_data(psu_info) + + return status == PSU_STATUS_OK + + def _get_psu_index(self, sub_id): """ Get the PSU index from sub_id :return: the index of supported PSU """ - if not self.psuutil or not sub_id or len(sub_id) > 1: + if not sub_id or len(sub_id) > 1: return None psu_index = int(sub_id[0]) try: - num_psus = self.psuutil.get_num_psus() + num_psus = self._get_num_psus() except Exception: # Any unexpected exception or error, log it and keep running - mibs.logger.exception("PowerStatusHandler._getPsuIndex() caught an unexpected exception during get_num_psus()") + mibs.logger.exception("PowerStatusHandler._get_psu_index() caught an unexpected exception during _get_num_psus()") return None if psu_index < 1 or psu_index > num_psus: @@ -62,27 +115,23 @@ def get_next(self, sub_id): :param sub_id: The 1-based snmp sub-identifier query. :return: the next sub id. """ - if not self.psuutil: - return None - if not sub_id: return (1,) - psu_index = self._getPsuIndex(sub_id) + psu_index = self._get_psu_index(sub_id) try: - num_psus = self.psuutil.get_num_psus() + num_psus = self._get_num_psus() except Exception: # Any unexpected exception or error, log it and keep running - mibs.logger.exception("PowerStatusHandler.get_next() caught an unexpected exception during get_num_psus()") + mibs.logger.exception("PowerStatusHandler.get_next() caught an unexpected exception during _get_num_psus()") return None - if psu_index and psu_index + 1 <= num_psus: return (psu_index + 1,) return None - def getPsuStatus(self, sub_id): + def get_psu_status(self, sub_id): """ :param sub_id: The 1-based sub-identifier query. :return: the status of requested PSU according to cefcModuleOperStatus ModuleOperType @@ -91,24 +140,24 @@ def getPsuStatus(self, sub_id): 8 - the module is provisioned, but it is missing. This is a failure state. :ref: https://www.cisco.com/c/en/us/td/docs/switches/wan/mgx/mgx_8850/software/mgx_r2-0-10/pxm/reference/guide/pxm/cscoent.html """ - psu_index = self._getPsuIndex(sub_id) + psu_index = self._get_psu_index(sub_id) if not psu_index: return None try: - psu_presence = self.psuutil.get_psu_presence(psu_index) + psu_presence = self._get_psu_presence(psu_index) except Exception: # Any unexpected exception or error, log it and keep running - mibs.logger.exception("PowerStatusHandler.getPsuStatus() caught an unexpected exception during get_psu_presence()") + mibs.logger.exception("PowerStatusHandler.get_psu_status() caught an unexpected exception during _get_psu_presence()") return None if psu_presence: try: - psu_status = self.psuutil.get_psu_status(psu_index) + psu_status = self._get_psu_status(psu_index) except Exception: # Any unexpected exception or error, log it and keep running - mibs.logger.exception("PowerStatusHandler.getPsuStatus() caught an unexpected exception during get_psu_status()") + mibs.logger.exception("PowerStatusHandler.get_psu_status() caught an unexpected exception during _get_psu_status()") return None if psu_status: @@ -118,7 +167,6 @@ def getPsuStatus(self, sub_id): else: return 8 - class cefcFruPowerStatusTable(metaclass=MIBMeta, prefix='.1.3.6.1.4.1.9.9.117.1.1.2'): """ 'cefcFruPowerStatusTable' http://oidref.com/1.3.6.1.4.1.9.9.117.1.1.2 @@ -129,4 +177,4 @@ class cefcFruPowerStatusTable(metaclass=MIBMeta, prefix='.1.3.6.1.4.1.9.9.117.1. # cefcFruPowerStatusTable = '1.3.6.1.4.1.9.9.117.1.1.2' # csqIfQosGroupStatsEntry = '1.3.6.1.4.1.9.9.117.1.1.2.1' - psu_status = SubtreeMIBEntry('1.2', power_status_handler, ValueType.INTEGER, power_status_handler.getPsuStatus) + psu_status = SubtreeMIBEntry('1.2', power_status_handler, ValueType.INTEGER, power_status_handler.get_psu_status) diff --git a/tests/__init__.py b/tests/__init__.py index 16fb37ac9..e69de29bb 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1 +0,0 @@ -import tests.mock_tables.imp diff --git a/tests/mock_tables/imp.py b/tests/mock_tables/imp.py deleted file mode 100644 index 8dee765a5..000000000 --- a/tests/mock_tables/imp.py +++ /dev/null @@ -1,15 +0,0 @@ -import imp -import os - -TEST_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - -# Backup original function -_load_source = getattr(imp, 'load_source') - -# Monkey patch -def load_source(name, pathname): - if name == 'psuutil': - return _load_source(name, TEST_DIR + '/plugins/psuutil.py') - -# Replace the function with mocked one -imp.load_source = load_source diff --git a/tests/mock_tables/state_db.json b/tests/mock_tables/state_db.json index 89b5c0c52..4944366f7 100644 --- a/tests/mock_tables/state_db.json +++ b/tests/mock_tables/state_db.json @@ -2,28 +2,43 @@ "DEVICE_METADATA|localhost": { "chassis_serial_number": "SAMPLETESTSN" }, + "PSU_INFO|PSU 1": { + "presence": "false", + "status": "false" + }, + "PSU_INFO|PSU 2": { + "presence": "true", + "status": "true" + }, + "PSU_INFO|PSU 3": { + "presence": "true", + "status": "false" + }, + "CHASSIS_INFO|chassis 1": { + "psu_num": "3" + }, "TRANSCEIVER_INFO|Ethernet0": { - "type": "QSFP+", - "hardwarerev" : "A1", - "serialnum": "SERIAL_NUM", - "manufacturename": "VENDOR_NAME", - "modelname": "MODEL_NAME" + "type": "QSFP+", + "hardwarerev" : "A1", + "serialnum": "SERIAL_NUM", + "manufacturename": "VENDOR_NAME", + "modelname": "MODEL_NAME" }, "TRANSCEIVER_DOM_SENSOR|Ethernet0": { - "temperature": 25.39, - "voltage": 3.37, - "tx1bias": "N/A", - "tx2bias": 4.44, - "tx3bias": "inf", - "tx4bias": 4.44, - "rx1power": "-inf", - "rx2power": -0.97, - "rx3power": -0.97, - "rx4power": -0.97, - "tx1power": -5.4, - "tx2power": -5.4, - "tx3power": -5.4, - "tx4power": -5.4 + "temperature": 25.39, + "voltage": 3.37, + "tx1bias": "N/A", + "tx2bias": 4.44, + "tx3bias": "inf", + "tx4bias": 4.44, + "rx1power": "-inf", + "rx2power": -0.97, + "rx3power": -0.97, + "rx4power": -0.97, + "tx1power": -5.4, + "tx2power": -5.4, + "tx3power": -5.4, + "tx4power": -5.4 }, "MGMT_PORT_TABLE|eth0": { "oper_status": "down" diff --git a/tests/plugins/psuutil.py b/tests/plugins/psuutil.py deleted file mode 100644 index 52d6304cc..000000000 --- a/tests/plugins/psuutil.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python - -############################################################################# -# Mellanox -# -# Module contains an implementation of SONiC PSU Base API and -# provides the PSUs status for SNMP testing -# -############################################################################# - -class PsuUtil(): - """PSUutil class for SNMP testing""" - - def __init__(self): - """ For testing purpose only """ - self.num_of_psus = 3 - self.psu_status = { 1: False, 2: True, 3: False } - self.psu_presence = { 1: False, 2: True, 3: True } - - def get_num_psus(self): - """ - Retrieves the number of PSUs available on the device - - :return: An integer, the number of PSUs available on the device - """ - """ For testing purpose only """ - return self.num_of_psus - - def get_psu_status(self, index): - """ - Retrieves the oprational status of power supply unit (PSU) defined - by 1-based index - - :param index: An integer, 1-based index of the PSU of which to query status - :return: Boolean, True if PSU is operating properly, False if PSU is faulty - """ - """ For testing purpose only """ - if not isinstance(index, int): - return False - elif index > 0 and index <= self.num_of_psus: - if self.psu_presence[index]: - return self.psu_status[index] - else: - raise ValueError(index) - else: - return False - - def get_psu_presence(self, index): - """ - Retrieves the presence status of power supply unit (PSU) defined - by 1-based index - - :param index: An integer, 1-based index of the PSU of which to query status - :return: Boolean, True if PSU is plugged, False if not - """ - """ For testing purpose only """ - if not isinstance(index, int): - return False - elif index > 0 and index <= self.num_of_psus: - return self.psu_presence[index] - else: - return False