[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:
parent
d08fcc971c
commit
9bb0a7f33c
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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():
|
||||||
"""
|
"""
|
||||||
|
Reference in New Issue
Block a user