2021-10-17 11:03:02 -05:00
|
|
|
#
|
|
|
|
# Copyright (c) 2020-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.
|
|
|
|
#
|
2021-06-20 09:58:11 -05:00
|
|
|
import functools
|
2021-03-11 20:54:33 -06:00
|
|
|
import subprocess
|
2021-10-24 23:59:06 -05:00
|
|
|
from sonic_py_common.logger import Logger
|
2021-03-11 20:54:33 -06:00
|
|
|
|
2021-10-24 23:59:06 -05:00
|
|
|
logger = Logger()
|
2021-03-11 20:54:33 -06:00
|
|
|
|
|
|
|
|
2021-10-24 23:59:06 -05:00
|
|
|
def read_from_file(file_path, target_type, default='', raise_exception=False, log_func=logger.log_error):
|
2020-10-26 14:47:12 -05:00
|
|
|
"""
|
2021-10-24 23:59:06 -05:00
|
|
|
Read content from file and convert to target type
|
2020-10-26 14:47:12 -05:00
|
|
|
:param file_path: File path
|
2021-10-24 23:59:06 -05:00
|
|
|
:param target_type: target type
|
2020-10-26 14:47:12 -05:00
|
|
|
:param default: Default return value if any exception occur
|
|
|
|
:param raise_exception: Raise exception to caller if True else just return default value
|
2021-10-24 23:59:06 -05:00
|
|
|
:param log_func: function to log the error
|
2020-10-26 14:47:12 -05:00
|
|
|
:return: String content of the file
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
with open(file_path, 'r') as f:
|
2021-10-24 23:59:06 -05:00
|
|
|
value = target_type(f.read().strip())
|
2020-10-26 14:47:12 -05:00
|
|
|
except (ValueError, IOError) as e:
|
2021-10-24 23:59:06 -05:00
|
|
|
if log_func:
|
|
|
|
log_func('Failed to read from file {} - {}'.format(file_path, repr(e)))
|
2020-10-26 14:47:12 -05:00
|
|
|
if not raise_exception:
|
|
|
|
value = default
|
|
|
|
else:
|
|
|
|
raise e
|
|
|
|
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
2021-10-24 23:59:06 -05:00
|
|
|
def read_str_from_file(file_path, default='', raise_exception=False, log_func=logger.log_error):
|
|
|
|
"""
|
|
|
|
Read string content from file
|
|
|
|
:param file_path: File path
|
|
|
|
: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
|
|
|
|
"""
|
|
|
|
return read_from_file(file_path=file_path, target_type=str, default=default, raise_exception=raise_exception, log_func=log_func)
|
|
|
|
|
|
|
|
|
|
|
|
def read_int_from_file(file_path, default=0, raise_exception=False, log_func=logger.log_error):
|
2020-10-26 14:47:12 -05:00
|
|
|
"""
|
|
|
|
Read content from file and cast it to integer
|
|
|
|
:param file_path: File path
|
|
|
|
:param default: Default return value if any exception occur
|
|
|
|
:param raise_exception: Raise exception to caller if True else just return default value
|
2021-10-24 23:59:06 -05:00
|
|
|
:param log_func: function to log the error
|
2020-10-26 14:47:12 -05:00
|
|
|
:return: Integer value of the file content
|
|
|
|
"""
|
2021-10-24 23:59:06 -05:00
|
|
|
return read_from_file(file_path=file_path, target_type=int, default=default, raise_exception=raise_exception, log_func=log_func)
|
2020-10-26 14:47:12 -05:00
|
|
|
|
2021-10-24 23:59:06 -05:00
|
|
|
|
|
|
|
def read_float_from_file(file_path, default=0.0, raise_exception=False, log_func=logger.log_error):
|
|
|
|
"""
|
|
|
|
Read content from file and cast it to integer
|
|
|
|
:param file_path: File path
|
|
|
|
: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: Integer value of the file content
|
|
|
|
"""
|
|
|
|
return read_from_file(file_path=file_path, target_type=float, default=default, raise_exception=raise_exception, log_func=log_func)
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
2020-10-26 14:47:12 -05:00
|
|
|
|
|
|
|
|
2021-10-24 23:59:06 -05:00
|
|
|
def write_file(file_path, content, raise_exception=False, log_func=logger.log_error):
|
2020-10-26 14:47:12 -05:00
|
|
|
"""
|
|
|
|
Write the given value to a file
|
|
|
|
:param file_path: File path
|
|
|
|
:param content: Value to write to the file
|
|
|
|
:param raise_exception: Raise exception to caller if True
|
|
|
|
:return: True if write success else False
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
with open(file_path, 'w') as f:
|
|
|
|
f.write(str(content))
|
|
|
|
except (ValueError, IOError) as e:
|
2021-10-24 23:59:06 -05:00
|
|
|
if log_func:
|
|
|
|
log_func('Failed to write {} to file {} - {}'.format(content, file_path, repr(e)))
|
2020-10-26 14:47:12 -05:00
|
|
|
if not raise_exception:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
raise e
|
|
|
|
return True
|
2021-03-11 20:54:33 -06:00
|
|
|
|
|
|
|
|
2021-10-24 23:59:06 -05:00
|
|
|
def pre_initialize(init_func):
|
|
|
|
def decorator(method):
|
|
|
|
@functools.wraps(method)
|
|
|
|
def _impl(self, *args, **kwargs):
|
|
|
|
init_func(self)
|
|
|
|
return method(self, *args, **kwargs)
|
|
|
|
return _impl
|
|
|
|
return decorator
|
|
|
|
|
|
|
|
|
|
|
|
def pre_initialize_one(init_func):
|
|
|
|
def decorator(method):
|
|
|
|
@functools.wraps(method)
|
|
|
|
def _impl(self, index):
|
|
|
|
init_func(self, index)
|
|
|
|
return method(self, index)
|
|
|
|
return _impl
|
|
|
|
return decorator
|
|
|
|
|
|
|
|
|
|
|
|
def read_only_cache():
|
|
|
|
"""Decorator to cache return value for a method/function once.
|
|
|
|
This decorator should be used for method/function when:
|
|
|
|
1. Executing the method/function takes time. e.g. reading sysfs.
|
|
|
|
2. The return value of this method/function never changes.
|
|
|
|
"""
|
|
|
|
def decorator(method):
|
|
|
|
method.return_value = None
|
|
|
|
|
|
|
|
@functools.wraps(method)
|
|
|
|
def _impl(*args, **kwargs):
|
|
|
|
if not method.return_value:
|
|
|
|
method.return_value = method(*args, **kwargs)
|
|
|
|
return method.return_value
|
|
|
|
return _impl
|
|
|
|
return decorator
|
|
|
|
|
|
|
|
|
|
|
|
@read_only_cache()
|
2021-03-11 20:54:33 -06:00
|
|
|
def is_host():
|
|
|
|
"""
|
|
|
|
Test whether current process is running on the host or an docker
|
|
|
|
return True for host and False for docker
|
2021-10-24 23:59:06 -05:00
|
|
|
"""
|
2021-03-11 20:54:33 -06:00
|
|
|
try:
|
|
|
|
proc = subprocess.Popen("docker --version 2>/dev/null",
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
shell=True,
|
|
|
|
stderr=subprocess.STDOUT,
|
|
|
|
universal_newlines=True)
|
|
|
|
stdout = proc.communicate()[0]
|
|
|
|
proc.wait()
|
|
|
|
result = stdout.rstrip('\n')
|
2021-10-24 23:59:06 -05:00
|
|
|
return result != ''
|
2021-03-11 20:54:33 -06:00
|
|
|
except OSError as e:
|
2021-10-24 23:59:06 -05:00
|
|
|
return False
|
2021-06-20 09:58:11 -05:00
|
|
|
|
|
|
|
|
2021-10-24 23:59:06 -05:00
|
|
|
def default_return(return_value, log_func=logger.log_debug):
|
2021-06-20 09:58:11 -05:00
|
|
|
def wrapper(method):
|
|
|
|
@functools.wraps(method)
|
|
|
|
def _impl(*args, **kwargs):
|
|
|
|
try:
|
|
|
|
return method(*args, **kwargs)
|
2021-10-24 23:59:06 -05:00
|
|
|
except Exception as e:
|
|
|
|
if log_func:
|
|
|
|
log_func('Faield to execute method {} - {}'.format(method.__name__, repr(e)))
|
2021-06-20 09:58:11 -05:00
|
|
|
return return_value
|
|
|
|
return _impl
|
|
|
|
return wrapper
|
2022-04-14 00:14:40 -05:00
|
|
|
|
|
|
|
|
|
|
|
def run_command(command):
|
|
|
|
"""
|
|
|
|
Utility function to run an shell command and return the output.
|
|
|
|
:param command: Shell command string.
|
|
|
|
:return: Output of the shell command.
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
process = subprocess.Popen(command, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
|
|
return process.communicate()[0].strip()
|
|
|
|
except Exception:
|
|
|
|
return None
|