[BFN] Canceling PSU platform API calls on SIGTERM (#10720)

* [BFN] Canceling PSU platform API calls on SIGTERM

Signed-off-by: Andriy Kokhan <andriyx.kokhan@intel.com>

* [BFN] Fixed SONiC fwutil exec time (#31)

Signed-off-by: Taras Keryk <tarasx.keryk@intel.com>

Signed-off-by: Andriy Kokhan <andriyx.kokhan@intel.com>
Signed-off-by: Taras Keryk <tarasx.keryk@intel.com>
Co-authored-by: Taras Keryk <tarasx.keryk@intel.com>
This commit is contained in:
Andriy Kokhan 2022-09-30 01:18:43 +03:00 committed by GitHub
parent d08fcc971c
commit 9bb0a7f33c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 89 additions and 3 deletions

View File

@ -6,6 +6,7 @@ try:
import json import json
from collections import OrderedDict from collections import OrderedDict
from sonic_py_common import device_info from sonic_py_common import device_info
from platform_utils import limit_execution_time
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") raise ImportError(str(e) + "- required module not found")
@ -24,6 +25,7 @@ def get_bios_version():
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
raise RuntimeError("Failed to get BIOS version") raise RuntimeError("Failed to get BIOS version")
@limit_execution_time(1)
def get_bmc_version(): def get_bmc_version():
""" """
Retrieves the firmware version of the BMC Retrieves the firmware version of the BMC

View File

@ -3,11 +3,19 @@
try: try:
import os import os
import subprocess import subprocess
import signal
from functools import wraps
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") raise ImportError(str(e) + "- required module not found")
def file_create(path, mode=None): def file_create(path, mode=None):
"""
Ensure that file is created with the appropriate permissions
Args:
path: full path of a file
mode: file permission in octal representation
"""
def run_cmd(cmd): def run_cmd(cmd):
if os.geteuid() != 0: if os.geteuid() != 0:
cmd.insert(0, 'sudo') cmd.insert(0, 'sudo')
@ -20,3 +28,53 @@ def file_create(path, mode=None):
run_cmd(['touch', path]) run_cmd(['touch', path])
if (mode is not None): if (mode is not None):
run_cmd(['chmod', mode, path]) run_cmd(['chmod', mode, path])
def cancel_on_sigterm(func):
"""
Wrapper for a function which has to be cancel on SIGTERM
"""
@wraps(func)
def wrapper(*args, **kwargs):
def handler(sig, frame):
if sigterm_handler:
sigterm_handler(sig, frame)
raise Exception("Canceling {}() execution...".format(func.__name__))
sigterm_handler = signal.getsignal(signal.SIGTERM)
signal.signal(signal.SIGTERM, handler)
result = None
try:
result = func(*args, **kwargs)
finally:
signal.signal(signal.SIGTERM, sigterm_handler)
return result
return wrapper
def limit_execution_time(execution_time_secs: int):
"""
Wrapper for a function whose execution time must be limited
Args:
execution_time_secs: maximum execution time in seconds,
after which the function execution will be stopped
"""
def wrapper(func):
@wraps(func)
def execution_func(*args, **kwargs):
def handler(sig, frame):
if sigalrm_handler:
sigalrm_handler(sig, frame)
raise Exception("Canceling {}() execution...".format(func.__name__))
sigalrm_handler = signal.getsignal(signal.SIGALRM)
signal.signal(signal.SIGALRM, handler)
signal.alarm(execution_time_secs)
result = None
try:
result = func(*args, **kwargs)
finally:
signal.alarm(0)
return result
return execution_func
return wrapper

View File

@ -4,18 +4,26 @@ try:
import os import os
import sys import sys
import time import time
import signal
import syslog
sys.path.append(os.path.dirname(__file__)) sys.path.append(os.path.dirname(__file__))
from .platform_thrift_client import thrift_try from .platform_thrift_client import thrift_try
from sonic_platform_base.psu_base import PsuBase from sonic_platform_base.psu_base import PsuBase
from platform_utils import cancel_on_sigterm
except ImportError as e: except ImportError as e:
raise ImportError (str(e) + "- required module not found") raise ImportError (str(e) + "- required module not found")
class Psu(PsuBase): class Psu(PsuBase):
"""Platform-specific PSU class""" """Platform-specific PSU class"""
sigterm = False
sigterm_default_handler = None
cls_inited = False
def __init__(self, index): def __init__(self, index):
PsuBase.__init__(self) PsuBase.__init__(self)
self.__index = index self.__index = index
@ -24,6 +32,21 @@ class Psu(PsuBase):
# STUB IMPLEMENTATION # STUB IMPLEMENTATION
self.color = "" self.color = ""
syslog.syslog(syslog.LOG_INFO, "Created PSU #{} instance".format(self.__index))
if not Psu.cls_inited:
Psu.sigterm_default_handler = signal.getsignal(signal.SIGTERM)
signal.signal(signal.SIGTERM, Psu.signal_handler)
if Psu.sigterm_default_handler:
syslog.syslog(syslog.LOG_INFO, "Default SIGTERM handler overridden!!")
Psu.cls_inited = True
@classmethod
def signal_handler(cls, sig, frame):
if cls.sigterm_default_handler:
cls.sigterm_default_handler(sig, frame)
syslog.syslog(syslog.LOG_INFO, "Canceling PSU platform API calls...")
cls.sigterm = True
''' '''
Units of returned info object values: Units of returned info object values:
vin - V vin - V
@ -33,20 +56,23 @@ class Psu(PsuBase):
fspeed - RPM fspeed - RPM
''' '''
def __info_get(self): def __info_get(self):
@cancel_on_sigterm
def psu_info_get(client): def psu_info_get(client):
return client.pltfm_mgr.pltfm_mgr_pwr_supply_info_get(self.__index) return client.pltfm_mgr.pltfm_mgr_pwr_supply_info_get(self.__index)
# Update cache once per 2 seconds # Update cache once per 2 seconds
if self.__ts + 2 < time.time(): if self.__ts + 2 < time.time() and not Psu.sigterm:
self.__info = None self.__info = None
try: try:
self.__info = thrift_try(psu_info_get, attempts=1) self.__info = thrift_try(psu_info_get, attempts=1)
except Exception as e:
if "Canceling" in str(e):
syslog.syslog(syslog.LOG_INFO, "{}".format(e))
finally: finally:
self.__ts = time.time() self.__ts = time.time()
return self.__info return self.__info
return self.__info return self.__info
@staticmethod @staticmethod
def get_num_psus(): def get_num_psus():
""" """