[Mellanox] Fix issue: PSU model/serial/revision info should be updated after replacing PSU (#9040)

This commit is contained in:
Junchao-Mellanox 2021-11-01 12:27:09 +08:00 committed by GitHub
parent ada705050d
commit 48d412d49f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 156 additions and 60 deletions

View File

@ -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):

View File

@ -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

View 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')