[Mellanox] Fix issue: PSU model/serial/revision info should be updated after replacing PSU (#9040)
This commit is contained in:
parent
ada705050d
commit
48d412d49f
@ -13,6 +13,7 @@ try:
|
||||
from sonic_platform.fan import Fan
|
||||
from .led import PsuLed, SharedLed, ComponentFaultyIndicator
|
||||
from .device_data import DEVICE_DATA
|
||||
from .vpd_parser import VpdParser
|
||||
except ImportError as e:
|
||||
raise ImportError (str(e) + "- required module not found")
|
||||
|
||||
@ -88,30 +89,10 @@ class Psu(PsuBase):
|
||||
self.psu_data = DEVICE_DATA[platform]['psus']
|
||||
psu_vpd = filemap[PSU_VPD]
|
||||
|
||||
self.model = "N/A"
|
||||
self.serial = "N/A"
|
||||
self.rev = "N/A"
|
||||
|
||||
if psu_vpd is not None:
|
||||
self.psu_vpd = os.path.join(self.psu_path, psu_vpd.format(self.index))
|
||||
self.vpd_data = self._read_vpd_file(self.psu_vpd)
|
||||
|
||||
if PN_VPD_FIELD in self.vpd_data:
|
||||
self.model = self.vpd_data[PN_VPD_FIELD]
|
||||
else:
|
||||
logger.log_error("Fail to read PSU{} model number: No key {} in VPD {}".format(self.index, PN_VPD_FIELD, self.psu_vpd))
|
||||
|
||||
if SN_VPD_FIELD in self.vpd_data:
|
||||
self.serial = self.vpd_data[SN_VPD_FIELD]
|
||||
else:
|
||||
logger.log_error("Fail to read PSU{} serial number: No key {} in VPD {}".format(self.index, SN_VPD_FIELD, self.psu_vpd))
|
||||
|
||||
if REV_VPD_FIELD in self.vpd_data:
|
||||
self.rev = self.vpd_data[REV_VPD_FIELD]
|
||||
else:
|
||||
logger.log_error("Fail to read PSU{} serial number: No key {} in VPD {}".format(self.index, REV_VPD_FIELD, self.psu_vpd))
|
||||
|
||||
self.vpd_parser = VpdParser(os.path.join(self.psu_path, psu_vpd.format(self.index)))
|
||||
else:
|
||||
self.vpd_parser = None
|
||||
logger.log_info("Not reading PSU{} VPD data: Platform is fixed".format(self.index))
|
||||
|
||||
if not self.psu_data['hot_swappable']:
|
||||
@ -162,24 +143,6 @@ class Psu(PsuBase):
|
||||
return self._name
|
||||
|
||||
|
||||
def _read_vpd_file(self, filename):
|
||||
"""
|
||||
Read a vpd file parsed from eeprom with keys and values.
|
||||
Returns a dictionary.
|
||||
"""
|
||||
result = {}
|
||||
try:
|
||||
if not os.path.exists(filename):
|
||||
return result
|
||||
with open(filename, 'r') as fileobj:
|
||||
for line in fileobj.readlines():
|
||||
key, val = line.split(":")
|
||||
result[key.strip()] = val.strip()
|
||||
except Exception as e:
|
||||
logger.log_error("Fail to read VPD file {} due to {}".format(filename, repr(e)))
|
||||
return result
|
||||
|
||||
|
||||
def _read_generic_file(self, filename, len):
|
||||
"""
|
||||
Read a generic file, returns the contents of the file
|
||||
@ -202,7 +165,7 @@ class Psu(PsuBase):
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
return self.model
|
||||
return 'N/A' if self.vpd_parser is None else self.vpd_parser.get_model()
|
||||
|
||||
|
||||
def get_serial(self):
|
||||
@ -212,7 +175,7 @@ class Psu(PsuBase):
|
||||
Returns:
|
||||
string: Serial number of device
|
||||
"""
|
||||
return self.serial
|
||||
return 'N/A' if self.vpd_parser is None else self.vpd_parser.get_serial()
|
||||
|
||||
|
||||
def get_revision(self):
|
||||
@ -222,7 +185,7 @@ class Psu(PsuBase):
|
||||
Returns:
|
||||
string: Revision value of device
|
||||
"""
|
||||
return self.rev
|
||||
return 'N/A' if self.vpd_parser is None else self.vpd_parser.get_revision()
|
||||
|
||||
|
||||
def get_powergood_status(self):
|
||||
|
@ -1,10 +1,37 @@
|
||||
import functools
|
||||
import subprocess
|
||||
from sonic_py_common.logger import Logger
|
||||
|
||||
logger = Logger()
|
||||
|
||||
# flags to indicate whether this process is running in docker or host
|
||||
_is_host = None
|
||||
|
||||
|
||||
def read_from_file(file_path, target_type, default='', raise_exception=False, log_func=logger.log_error):
|
||||
"""
|
||||
Read content from file and convert to target type
|
||||
:param file_path: File path
|
||||
:param target_type: target type
|
||||
:param default: Default return value if any exception occur
|
||||
:param raise_exception: Raise exception to caller if True else just return default value
|
||||
:param log_func: function to log the error
|
||||
:return: String content of the file
|
||||
"""
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
value = target_type(f.read().strip())
|
||||
except (ValueError, IOError) as e:
|
||||
if log_func:
|
||||
log_func('Failed to read from file {} - {}'.format(file_path, repr(e)))
|
||||
if not raise_exception:
|
||||
value = default
|
||||
else:
|
||||
raise e
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def read_str_from_file(file_path, default='', raise_exception=False):
|
||||
"""
|
||||
Read string content from file
|
||||
@ -45,6 +72,28 @@ def read_int_from_file(file_path, default=0, raise_exception=False):
|
||||
return value
|
||||
|
||||
|
||||
def _key_value_converter(content):
|
||||
ret = {}
|
||||
for line in content.splitlines():
|
||||
k,v = line.split(':')
|
||||
ret[k.strip()] = v.strip()
|
||||
return ret
|
||||
|
||||
|
||||
def read_key_value_file(file_path, default={}, raise_exception=False, log_func=logger.log_error):
|
||||
"""Read file content and parse the content to a dict. The file content should like:
|
||||
key1:value1
|
||||
key2:value2
|
||||
|
||||
Args:
|
||||
file_path (str): file path
|
||||
default (dict, optional): default return value. Defaults to {}.
|
||||
raise_exception (bool, optional): If exception should be raised or hiden. Defaults to False.
|
||||
log_func (optional): logger function.. Defaults to logger.log_error.
|
||||
"""
|
||||
return read_from_file(file_path=file_path, target_type=_key_value_converter, default=default, raise_exception=raise_exception, log_func=log_func)
|
||||
|
||||
|
||||
def write_file(file_path, content, raise_exception=False):
|
||||
"""
|
||||
Write the given value to a file
|
||||
|
@ -0,0 +1,84 @@
|
||||
#
|
||||
# Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES.
|
||||
# Apache-2.0
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
import os
|
||||
from sonic_py_common.logger import Logger
|
||||
|
||||
from . import utils
|
||||
|
||||
logger = Logger()
|
||||
SN_VPD_FIELD = "SN_VPD_FIELD"
|
||||
PN_VPD_FIELD = "PN_VPD_FIELD"
|
||||
REV_VPD_FIELD = "REV_VPD_FIELD"
|
||||
|
||||
|
||||
class VpdParser:
|
||||
def __init__(self, file_path):
|
||||
self.vpd_data = {}
|
||||
self.vpd_file = file_path
|
||||
self.vpd_file_last_mtime = None
|
||||
|
||||
def _get_data(self):
|
||||
if not os.path.exists(self.vpd_file):
|
||||
self.vpd_data = {}
|
||||
return False
|
||||
|
||||
try:
|
||||
mtime = os.stat(self.vpd_file).st_mtime
|
||||
if mtime != self.vpd_file_last_mtime:
|
||||
self.vpd_file_last_mtime = mtime
|
||||
self.vpd_data = utils.read_key_value_file(self.vpd_file)
|
||||
return True
|
||||
except Exception as e:
|
||||
self.vpd_data = {}
|
||||
return False
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
if self._get_data() and PN_VPD_FIELD not in self.vpd_data:
|
||||
logger.log_error("Fail to read model number: No key {} in VPD {}".format(PN_VPD_FIELD, self.vpd_file))
|
||||
return 'N/A'
|
||||
return self.vpd_data.get(PN_VPD_FIELD, 'N/A')
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the device
|
||||
|
||||
Returns:
|
||||
string: Serial number of device
|
||||
"""
|
||||
if self._get_data() and SN_VPD_FIELD not in self.vpd_data:
|
||||
logger.log_error("Fail to read serial number: No key {} in VPD {}".format(SN_VPD_FIELD, self.vpd_file))
|
||||
return 'N/A'
|
||||
return self.vpd_data.get(SN_VPD_FIELD, 'N/A')
|
||||
|
||||
def get_revision(self):
|
||||
"""
|
||||
Retrieves the hardware revision of the device
|
||||
|
||||
Returns:
|
||||
string: Revision value of device
|
||||
"""
|
||||
if self._get_data() and REV_VPD_FIELD not in self.vpd_data:
|
||||
logger.log_error("Fail to read revision: No key {} in VPD {}".format(REV_VPD_FIELD, self.vpd_file))
|
||||
return 'N/A'
|
||||
return self.vpd_data.get(REV_VPD_FIELD, 'N/A')
|
Reference in New Issue
Block a user