diff --git a/lisa/base_tools/wget.py b/lisa/base_tools/wget.py index 78e71ddd8a..4ceafe700c 100644 --- a/lisa/base_tools/wget.py +++ b/lisa/base_tools/wget.py @@ -14,6 +14,20 @@ class Wget(Tool): r"([\w\W]*?)(-|File) (‘|')(?P.+?)(’|') (saved|already there)" ) + # regex to validate url + # source - + # https://github.com/django/django/blob/stable/1.3.x/django/core/validators.py#L45 + __url_pattern = re.compile( + r"^(?:http|ftp)s?://" # http:// or https:// + r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)" + r"+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|" # ...domain + r"localhost|" # localhost... + r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" # ...or ip + r"(?::\d+)?" # optional port + r"(?:/?|[/?]\S+)$", + re.IGNORECASE, + ) + @property def command(self) -> str: return "wget" @@ -23,9 +37,8 @@ def can_install(self) -> bool: return True def install(self) -> bool: - if not self._check_exists(): - posix_os: Posix = self.node.os # type: ignore - posix_os.install_packages([self]) + posix_os: Posix = self.node.os # type: ignore + posix_os.install_packages([self]) return self._check_exists() def get( @@ -36,6 +49,8 @@ def get( overwrite: bool = True, executable: bool = False, ) -> str: + if re.match(self.__url_pattern, url) is None: + raise LisaException(f"Invalid URL '{url}'") # create folder when it doesn't exist self.node.execute(f"mkdir -p {file_path}", shell=True) # combine download file path diff --git a/lisa/features/gpu.py b/lisa/features/gpu.py index 6a76ee0016..4d5dc19ab2 100644 --- a/lisa/features/gpu.py +++ b/lisa/features/gpu.py @@ -3,12 +3,14 @@ import re from enum import Enum -from typing import Any, cast +from typing import Any +from lisa.base_tools.wget import Wget from lisa.feature import Feature -from lisa.operating_system import Linux, Redhat, Ubuntu +from lisa.operating_system import Redhat, Ubuntu from lisa.tools import Uname -from lisa.util import LisaException +from lisa.util import LisaException, SkippedException +from lisa.util.logger import get_logger FEATURE_NAME_GPU = "Gpu" @@ -31,51 +33,57 @@ class Gpu(Feature): def __init__(self, node: Any, platform: Any) -> None: super().__init__(node, platform) - self._log = self._node.log + self._log = get_logger("gpu", self.name(), self._node.log) @classmethod def name(cls) -> str: return FEATURE_NAME_GPU - # download and install NVIDIA grid driver - def _install_grid_driver(self, version: str) -> None: - self._log.info("Starting GRID driver installation") - if not version.strip(): - version = GRID_DRIVER - - # grid_filename = "NVIDIA-Linux-x86_64-grid.run" + def _is_supported(self) -> bool: + raise NotImplementedError() + # download and install NVIDIA grid driver + def _install_grid_driver(self, driver_url: str = GRID_DRIVER) -> None: + self._log.debug("Starting GRID driver installation") # download and install the NVIDIA GRID driver + wget_tool = self._node.tools[Wget] + grid_file_path = wget_tool.get( + driver_url, + str(self._node.working_path), + "NVIDIA-Linux-x86_64-grid.run", + executable=True, + ) + result = self._node.execute( + f"{grid_file_path} --no-nouveau-check --silent --no-cc-version-check" + ) + if result.exit_code != 0: + raise LisaException( + "Failed to install the GRID driver! " + f"exit-code: {result.exit_code} stderr: {result.stderr}" + ) + + self._log.debug("Successfully installed the GRID driver") # download and install CUDA Driver - def _install_cuda_driver(self, version: str) -> None: - self._log.info("Starting CUDA driver installation") + def _install_cuda_driver(self, version: str = "10.1.105-1") -> None: + self._log.debug("Starting CUDA driver installation") cuda_repo = "" - linux_os: Linux = cast(Linux, self._node.os) - - if not version.strip(): - version = "10.1.105-1" + os_version = self._node.os.os_version - # CUDA driver installation for redhat distros if isinstance(self._node.os, Redhat): - cuda_repo_pkg = f"cuda-repo-rhel7-{version}.x86_64.rpm" + release = os_version.release.split(".")[0] + cuda_repo_pkg = f"cuda-repo-rhel{release}-{version}.x86_64.rpm" cuda_repo = ( "http://developer.download.nvidia.com/" - f"compute/cuda/repos/rhel7/x86_64/{cuda_repo_pkg}" + f"compute/cuda/repos/rhel{release}/x86_64/{cuda_repo_pkg}" ) - linux_os = Redhat(self._node) - - # CUDA driver installation for Ubuntu distros elif isinstance(self._node.os, Ubuntu): - release_version = self._node.os._os_version.release - release = re.sub("[^0-9]+", "", release_version) + release = re.sub("[^0-9]+", "", os_version.release) cuda_repo_pkg = f"cuda-repo-ubuntu{release}_{version}_amd64.deb" cuda_repo = ( "http://developer.download.nvidia.com/compute/" f"cuda/repos/ubuntu{release}/x86_64/{cuda_repo_pkg}" ) - linux_os = Ubuntu(self._node) - else: raise LisaException( f"Distro {self._node.os.__class__.__name__}" @@ -83,39 +91,54 @@ def _install_cuda_driver(self, version: str) -> None: ) # download and install the cuda driver package from the repo - linux_os.install_packages(f"{cuda_repo}", signed=False) + self._node.os._install_package_from_url(f"{cuda_repo}", signed=False) - def install_gpu_dep(self) -> None: + def _install_gpu_dep(self) -> None: uname_tool = self._node.tools[Uname] uname_ver = uname_tool.get_linux_information().uname_version - # install dependency libraries for redhat and CentOS + # install dependency libraries for distros if isinstance(self._node.os, Redhat): # install the kernel-devel and kernel-header packages package_name = f"kernel-devel-{uname_ver} kernel-headers-{uname_ver}" self._node.os.install_packages(package_name) - # mesa-libEGL install/update is require to avoid a conflict between # libraries - bugzilla.redhat 1584740 package_name = "mesa-libGL mesa-libEGL libglvnd-devel" self._node.os.install_packages(package_name) - # install dkms package_name = "dkms" self._node.os.install_packages(package_name, signed=False) - - # install dependency libraraies for Ubuntu elif isinstance(self._node.os, Ubuntu): package_name = ( f"build-essential libelf-dev linux-tools-{uname_ver}" f" linux-cloud-tools-{uname_ver} python libglvnd-dev ubuntu-desktop" ) self._node.os.install_packages(package_name) + else: + raise LisaException( + f"Distro {self._node.os.__class__.__name__}" + " is not supported for GPU." + ) + + def check_support(self) -> None: + # TODO: more supportability can be defined here + if not self._is_supported(): + raise SkippedException(f"GPU is not supported with distro {self._node.os}") + + def install_compute_sdk( + self, driver: ComputeSDK = ComputeSDK.CUDA, version: str = "" + ) -> None: + # install GPU dependencies before installing driver + self._install_gpu_dep() - def install_compute_sdk(self, driver: ComputeSDK, version: str = "") -> None: + # install the driver if driver == ComputeSDK.GRID: self._install_grid_driver(version) elif driver == ComputeSDK.CUDA: self._install_cuda_driver(version) else: - raise LisaException("No valid driver SDK name provided to install.") + raise LisaException( + f"{ComputeSDK} is invalid." + "No valid driver SDK name provided to install." + ) diff --git a/lisa/operating_system.py b/lisa/operating_system.py index 19c5c4b753..80379dcf80 100644 --- a/lisa/operating_system.py +++ b/lisa/operating_system.py @@ -10,7 +10,6 @@ from lisa.executable import Tool from lisa.util import BaseClassMixin, LisaException, get_matched_str from lisa.util.logger import get_logger -from lisa.util.process import ExecutableResult from lisa.util.subclasses import Factory if TYPE_CHECKING: @@ -21,6 +20,9 @@ @dataclass +# OsVersion - To have full distro info. +# GetOSVersion() method at below link was useful to get distro info. +# https://github.com/microsoft/lisa/blob/master/Testscripts/Linux/utils.sh class OsVersion: # Vendor/Distributor vendor: str @@ -28,8 +30,6 @@ class OsVersion: release: str = "" # Codename for the release codename: str = "" - # Package type supported - package: str = "" # Update available update: str = "" @@ -56,7 +56,7 @@ def __init__(self, node: Any, is_posix: bool) -> None: self._node: Node = node self._is_posix = is_posix self._log = get_logger(name="os", parent=self._node.log) - self._os_version: OsVersion = OsVersion("") + self._os_version: Optional[OsVersion] = None @classmethod def create(cls, node: Any) -> Any: @@ -127,7 +127,6 @@ def _get_detect_string(cls, node: Any) -> Iterable[str]: cmd_result = typed_node.execute(cmd="lsb_release -d", no_error_log=True) yield get_matched_str(cmd_result.stdout, cls.__lsb_release_pattern) - # It covers distros like ClearLinux too cmd_result = typed_node.execute(cmd="cat /etc/os-release", no_error_log=True) yield get_matched_str(cmd_result.stdout, cls.__os_release_pattern_name) yield get_matched_str(cmd_result.stdout, cls.__os_release_pattern_id) @@ -165,36 +164,50 @@ def _get_os_version(self) -> OsVersion: class Windows(OperatingSystem): + __windows_version_pattern = re.compile( + r"^OS Version:[\"\']?\s+(?P.*?)[\"\']?$" + ) + def __init__(self, node: Any) -> None: super().__init__(node, is_posix=False) def _get_os_version(self) -> OsVersion: - self._os_version.vendor = "Microsoft Corporation" + os_version = OsVersion("Microsoft Corporation") cmd_result = self._node.execute( cmd='systeminfo | findstr /B /C:"OS Version"', no_error_log=True, ) if cmd_result.exit_code == 0 and cmd_result.stdout != "": - for row in cmd_result.stdout.split("\n"): - if ": " in row: - key, value = row.split(": ") - if "OS Version" in key: - self._os_version.release = value.strip() - return self._os_version + os_version.release = get_matched_str( + cmd_result.stdout, self.__windows_version_pattern + ) + if os_version.release == "": + raise LisaException("OS version information not found") + else: + raise LisaException( + "Error getting OS version info from systeminfo command" + f"exit_code: {cmd_result.exit_code} stderr: {cmd_result.stderr}" + ) + return os_version class Posix(OperatingSystem, BaseClassMixin): - - __url_pattern = re.compile( - r"^(?:http|ftp)s?://" # http:// or https:// - r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)" - r"+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|" - r"localhost|" # localhost... - r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" # ...or ip - r"(?::\d+)?" # optional port - r"(?:/?|[/?]\S+)$", - re.IGNORECASE, + __os_info_pattern = re.compile( + r"^(?P.*)=[\"\']?(?P.*?)[\"\']?$", re.MULTILINE ) + # output of /etc/fedora-release - Fedora release 22 (Twenty Two) + # output of /etc/redhat-release - Scientific Linux release 7.1 (Nitrogen) + # output of /etc/os-release - + # NAME="Debian GNU/Linux" + # VERSION_ID="7" + # VERSION="7 (wheezy)" + # output of lsb_release -a + # LSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch + # Distributor ID: Scientific + # Description: Scientific Linux release 6.7 (Carbon) + # In most of the distros, the text in the brackets is the codename. + # This regex gets the codename for the ditsro + __distro_codename_pattern = re.compile(r"^.*\(([^)]+)") def __init__(self, node: Any) -> None: super().__init__(node, is_posix=True) @@ -213,21 +226,52 @@ def _install_packages( ) -> None: raise NotImplementedError() - def _query_packages( - self, packages: Union[List[str]], signed: bool = True - ) -> ExecutableResult: + def _package_exists(self, package: str, signed: bool = True) -> bool: raise NotImplementedError() def _initialize_package_installation(self) -> None: # sub os can override it, but it's optional pass - def install_package_from_url( + def _get_os_version(self) -> OsVersion: + os_version = OsVersion("") + # try to set OsVersion from info in /etc/os-release. + cmd_result = self._node.execute(cmd="cat /etc/os-release", no_error_log=True) + if cmd_result.exit_code == 0 and cmd_result.stdout != "": + for row in cmd_result.stdout.splitlines(): + os_release_info = self.__os_info_pattern.match(row) + if os_release_info: + if os_release_info.group("name") == "NAME": + os_version.vendor = os_release_info.group("value") + elif os_release_info.group("name") == "VERSION_ID": + os_version.release = os_release_info.group("value") + elif os_release_info.group("name") == "VERSION": + os_version.codename = get_matched_str( + os_release_info.group("value"), + self.__distro_codename_pattern, + ) + if os_version.vendor == "": + raise LisaException("OS version information not found") + else: + raise LisaException( + "Error in running command 'cat /etc/os-release'" + f"stderr: {cmd_result.stderr}" + ) + + return os_version + + def _install_package_from_url( self, - packages: Union[str, Tool, Type[Tool], List[Union[str, Tool, Type[Tool]]]], + package: str, signed: bool = True, ) -> None: - pass + """ + Used if the package to be installed needs to be downloaded from a url first. + """ + # when package is URL, download the package first at the working path. + wget_tool = self._node.tools[Wget] + pkg = wget_tool.get(package, str(self._node.working_path)) + self.install_packages(f"{pkg}", signed) def install_packages( self, @@ -240,77 +284,45 @@ def install_packages( assert isinstance(packages, list), f"actual:{type(packages)}" for item in packages: - if isinstance(item, str): - # if item is a URL, download the package first - # and then append the downloaded file to package_names. - if re.match(self.__url_pattern, item) is not None: - wget_tool = self._node.tools[Wget] - wget_tool.install() - # download the package at the working path. - pkg = wget_tool.get(item, str(self._node.working_path)) - package_names.append(pkg) - else: - package_names.append(item) - elif isinstance(item, Tool): - package_names.append(item.package_name) - else: - assert isinstance(item, type), f"actual:{type(item)}" - # Create a temp object, it doesn't trigger install. - # So they can be installed together. - tool = item.create(self._node) - package_names.append(tool.package_name) + package_names.append(self.__resolve_package_name(item)) if self._first_time_installation: self._first_time_installation = False self._initialize_package_installation() self._install_packages(package_names, signed) - # query_packages - # Return Value - ExecutableResult - def query_packages( - self, packages: Union[str, Tool, Type[Tool], List[Union[str, Tool, Type[Tool]]]] - ) -> ExecutableResult: - package_names: List[str] = [] - if not isinstance(packages, list): - packages = [packages] + def package_exists( + self, package: Union[str, Tool, Type[Tool]], signed: bool = True + ) -> bool: + """ + Query if a package/tool is installed on the node. + Return Value - bool + """ + package_name = self.__resolve_package_name(package) + return self._package_exists(package_name) - assert isinstance(packages, list), f"actual:{type(packages)}" - for item in packages: - if isinstance(item, str): - package_names.append(item) - elif isinstance(item, Tool): - package_names.append(item.package_name) - else: - assert isinstance(item, type), f"actual:{type(item)}" - # Create a temp object, it doesn't query. - # So they can be queried together. - tool = item.create(self._node) - package_names.append(tool.package_name) - - return self._query_packages(package_names) - - # TODO: Implement update_packages def update_packages( self, packages: Union[str, Tool, Type[Tool], List[Union[str, Tool, Type[Tool]]]] ) -> None: - pass + raise NotImplementedError - def _get_os_version(self) -> OsVersion: - cmd_result = self._node.execute(cmd="cat /etc/os-release", no_error_log=True) - if cmd_result.exit_code == 0 and cmd_result.stdout != "": - for row in cmd_result.stdout.split("\n"): - if "=" in row: - key, value = row.split("=") - if "NAME" in key.upper(): - self._os_version.vendor = value.strip() - elif "VERSION_ID" in key.upper(): - self._os_version.release = value.strip() - elif "VERSION" in key.upper(): - check_codename = re.search(r"\(([^)]+)", value.strip()) - if check_codename is not None: - self._os_version.codename = check_codename.group(1) + def __resolve_package_name(self, package: Union[str, Tool, Type[Tool]]) -> str: + """ + A package can be a string or a tool or a type of tool. + Resolve it to a standard package_name so it can be installed. + """ + if isinstance(package, str): + package_name = package + elif isinstance(package, Tool): + package_name = package.package_name + else: + assert isinstance(package, type), f"actual:{type(package)}" + # Create a temp object, it doesn't query. + # So they can be queried together. + tool = package.create(self._node) + package_name = tool.package_name - return self._os_version + return package_name class BSD(Posix): @@ -322,6 +334,10 @@ class Linux(Posix): class Debian(Linux): + __lsb_os_info_pattern = re.compile( + r"^(?P.*):(\s+)(?P.*?)?$", re.MULTILINE + ) + @classmethod def name_pattern(cls) -> Pattern[str]: return re.compile("^debian|Forcepoint|Kali$") @@ -337,7 +353,7 @@ def _install_packages( f"apt-get -y install {' '.join(packages)}" ) if not signed: - command = command.__add__(" --allow-unauthenticated") + command += " --allow-unauthenticated" install_result = self._node.execute(command, sudo=True) if install_result.exit_code != 0: @@ -346,30 +362,38 @@ def _install_packages( f" stdout: {install_result.stdout}" ) - def _query_package( - self, packages: Union[List[str]], signed: bool = True - ) -> ExecutableResult: - command = f"apt list --installed | grep -Ei {'|'.join(packages)}" - - return self._node.execute(command, sudo=True) + def _package_exists(self, package: str, signed: bool = True) -> bool: + command = f"apt list --installed | grep -Ei {package}" + result = self._node.execute(command, sudo=True) + if result.exit_code == 0: + for row in result.stdout.split("\n"): + if package in row: + return True + return False def _get_os_version(self) -> OsVersion: + os_version = OsVersion("") cmd_result = self._node.execute(cmd="lsb_release -as", no_error_log=True) if cmd_result.exit_code == 0 and cmd_result.stdout != "": - for row in cmd_result.stdout.split("\n"): - if ": " in row: - key, value = row.split(": ") - if "Distributor ID" in key: - self._os_version.vendor = value.strip() - elif "Release" in key: - self._os_version.release = value.strip() - elif "Codename" in key: - self._os_version.codename = value.strip() - - if self._os_version.vendor in ["Debian", "Ubuntu", "LinuxMint"]: - self._os_version.package = "deb" + for row in cmd_result.stdout.splitlines(): + os_release_info = self.__lsb_os_info_pattern.match(row) + if os_release_info: + if os_release_info.group("name") == "Distributor ID": + os_version.vendor = os_release_info.group("value") + elif os_release_info.group("name") == "Release": + os_version.release = os_release_info.group("value") + elif os_release_info.group("name") == "Codename": + os_version.codename = os_release_info.group("value") + if os_version.vendor == "": + raise LisaException("OS version information not found") + else: + raise LisaException( + "Command 'lsb_release -as' failed with exit code -" + f" {cmd_result.exit_code}" + f"stderr: {cmd_result.stderr}" + ) - return self._os_version + return os_version class Ubuntu(Debian): @@ -377,10 +401,6 @@ class Ubuntu(Debian): def name_pattern(cls) -> Pattern[str]: return re.compile("^Ubuntu|ubuntu$") - def _get_os_version(self) -> OsVersion: - self._os_version.vendor = "Ubuntu" - return self._os_version - class FreeBSD(BSD): ... @@ -391,6 +411,8 @@ class OpenBSD(BSD): class Fedora(Linux): + __fedora_release_pattern_version = re.compile(r"^.*release\s+([0-9\.]+).*$") + @classmethod def name_pattern(cls) -> Pattern[str]: return re.compile("^Fedora|fedora$") @@ -400,46 +422,56 @@ def _install_packages( ) -> None: command = f"dnf install -y {' '.join(packages)}" if not signed: - command.__add__(" --nogpgcheck") + command += " --nogpgcheck" install_result = self._node.execute(command, sudo=True) if install_result.exit_code != 0: raise LisaException( - f"Failed to install {' '.join(packages)}." - f" stdout: {install_result.stdout}" + f"Failed to install {packages}. exit_code: {install_result.exit_code} " + f"stderr: {install_result.stderr}" ) else: - self._log.info( - f"{' '.join(packages)} is/are installed successfully." - f" stdout: {install_result.stdout}" - ) + self._log.debug(f"{packages} is/are installed successfully.") - def _query_packages( - self, packages: Union[List[str]], signed: bool = True - ) -> ExecutableResult: - command = f"dnf list installed | grep -Ei {'|'.join(packages)}" + def _package_exists(self, package: str, signed: bool = True) -> bool: + command = f"dnf list installed | grep -Ei {package}" + result = self._node.execute(command, sudo=True) + if result.exit_code == 0: + for row in result.stdout.split("\n"): + if package in row: + return True - return self._node.execute(command, sudo=True) + return False def _get_os_version(self) -> OsVersion: + os_version = OsVersion("") cmd_result = self._node.execute( - cmd="cat /etc/fedora-release", no_error_log=True + # Typical output of 'cat /etc/fedora-release' is - + # Fedora release 22 (Twenty Two) + cmd="cat /etc/fedora-release", + no_error_log=True, ) if cmd_result.exit_code == 0 and cmd_result.stdout != "": result = cmd_result.stdout for vendor in ["Fedora", "CentOS", "Red Hat", "XenServer"]: if vendor in result: - self._os_version.vendor = vendor - if re.search(r"\brelease\b", result, re.IGNORECASE): - self._os_version.release = re.split( - "release", result, flags=re.IGNORECASE - )[1].split()[0] - check_code = re.search(r"\(([^)]+)", result) - if check_code is not None: - self._os_version.codename = check_code.group(1) - break + os_version.vendor = vendor + os_version.release = get_matched_str( + cmd_result.stdout, self.__fedora_release_pattern_version + ) + os_version.codename = get_matched_str( + cmd_result.stdout, self.__distro_codename_pattern + ) + break + if os_version.vendor == "": + raise LisaException("OS version information not found") + else: + raise LisaException( + "Error in running command 'cat /etc/fedora-release'" + f"stderr: {cmd_result.stderr}" + ) - return self._os_version + return os_version class Redhat(Fedora): @@ -474,55 +506,56 @@ def _initialize_package_installation(self) -> None: def _install_packages( self, packages: Union[List[str]], signed: bool = True ) -> None: - command = f"yum install -y {'|'.join(packages)}" + command = f"yum install -y {' '.join(packages)}" if not signed: - command.__add__(" --nogpgcheck") + command += " --nogpgcheck" install_result = self._node.execute(command, sudo=True) # yum returns exit_code=1 if package is already installed. # We do not want to fail if exit_code=1. if install_result.exit_code == 1: - self._log.info( - f"{' '.join(packages)} is/are already installed." - f" stdout: {install_result.stdout}" - ) - elif install_result.exit_code != 0: - raise LisaException( - f"Failed to install {' '.join(packages)}." - f" stdout: {install_result.stdout}" - ) + self._log.debug(f"{packages} is/are already installed.") + elif install_result.exit_code == 0: + self._log.debug(f"{packages} is/are installed successfully.") else: - self._log.info( - f"{' '.join(packages)} is/are installed successfully." - f" stdout: {install_result.stdout}" + raise LisaException( + f"Failed to install {packages}. exit_code: {install_result.exit_code} " + f"stderr: {install_result.stderr}" ) - def _query_packages( - self, packages: Union[List[str]], signed: bool = True - ) -> ExecutableResult: - command = f"yum list installed | grep -Ei {' '.join(packages)}" + def _package_exists(self, package: str, signed: bool = True) -> bool: + command = f"yum list installed | grep -Ei {package}" + result = self._node.execute(command, sudo=True) + if result.exit_code == 0: + return True - return self._node.execute(command, sudo=True) + return False def _get_os_version(self) -> OsVersion: + os_version = OsVersion("") cmd_result = self._node.execute( cmd="cat /etc/redhat-release", no_error_log=True ) if cmd_result.exit_code == 0 and cmd_result.stdout != "": - result = cmd_result.stdout - for vendor in ["Red Hat", "CentOS", "Fedora", "XenServer"]: - if vendor in result: - self._os_version.vendor = vendor - if re.search(r"\brelease\b", result, re.IGNORECASE): - self._os_version.release = re.split( - "release", result, flags=re.IGNORECASE - )[1].split()[0] - check_codename = re.search(r"\(([^)]+)", result) - if check_codename is not None: - self._os_version.codename = check_codename.group(1) - break + for vendor in ["Red Hat", "CentOS", "XenServer"]: + if vendor in cmd_result.stdout: + os_version.vendor = vendor + os_version.release = get_matched_str( + cmd_result.stdout, self.__fedora_release_pattern_version + ) + os_version.codename = get_matched_str( + cmd_result.stdout, self.__redhat_release_pattern_bracket + ) + break + if os_version.vendor == "": + raise LisaException("OS version information not found") + else: + raise LisaException( + "Error in running command 'cat /etc/redhat-release'" + f"stderr: {cmd_result.stderr}" + ) - return self._os_version + return os_version class CentOs(Redhat): @@ -554,29 +587,21 @@ def _install_packages( ) -> None: command = f"zypper --non-interactive in {' '.join(packages)}" if not signed: - command.__add__(" --no-gpg-checks") + command += " --no-gpg-checks" install_result = self._node.execute(command, sudo=True) if install_result.exit_code in (1, 100): raise LisaException( - f"Failed to install {' '.join(packages)}." - f" stdout: {install_result.stdout}" + f"Failed to install {packages}. exit_code: {install_result.exit_code}" + f"stderr: {install_result.stderr}" ) elif install_result.exit_code == 0: - self._log.info( - f"{' '.join(packages)} is/are installed successfully." - f" stdout: {install_result.stdout}" - ) + self._log.debug(f"{packages} is/are installed successfully.") else: - self._log.info( - f"{' '.join(packages)} is/are installed." + self._log.debug( + f"{packages} is/are installed." " A system reboot or package manager restart might be required." - f" stdout: {install_result.stdout}" ) - def _get_os_version(self) -> OsVersion: - os_version = OsVersion("SUSE") - return os_version - class NixOS(Linux): pass diff --git a/lisa/sut_orchestrator/azure/features.py b/lisa/sut_orchestrator/azure/features.py index aaf51cbd15..e58a93c3e5 100644 --- a/lisa/sut_orchestrator/azure/features.py +++ b/lisa/sut_orchestrator/azure/features.py @@ -8,8 +8,7 @@ from lisa import features from lisa.node import Node -from lisa.operating_system import CentOs, Redhat, Ubuntu -from lisa.util import SkippedException +from lisa.operating_system import CentOs, Redhat, Suse, Ubuntu from .common import get_compute_client, get_node_context, wait_operation @@ -76,7 +75,8 @@ def _initialize(self, *args: Any, **kwargs: Any) -> None: super()._initialize(*args, **kwargs) self._initialize_information(self._node) - def _is_supported(self) -> None: - supported_distro = (CentOs, Redhat, Ubuntu) + def _is_supported(self) -> bool: + supported_distro = (CentOs, Redhat, Ubuntu, Suse) if not isinstance(self._node.os, supported_distro): - raise SkippedException(f"GPU is not supported with distro {self._node.os}") + return False + return True diff --git a/lisa/sut_orchestrator/azure/platform_.py b/lisa/sut_orchestrator/azure/platform_.py index 9c49b24b13..770095d70f 100644 --- a/lisa/sut_orchestrator/azure/platform_.py +++ b/lisa/sut_orchestrator/azure/platform_.py @@ -1164,6 +1164,7 @@ def _resource_sku_to_capability( excluded_features=search_space.SetSpace[str](is_allow_set=False), ) node_space.name = f"{location}_{resource_sku.name}" + node_space.features = search_space.SetSpace[str](is_allow_set=True) for sku_capability in resource_sku.capabilities: name = sku_capability.name if name == "vCPUs": @@ -1180,17 +1181,14 @@ def _resource_sku_to_capability( ) elif name == "GPUs": node_space.gpu_count = int(sku_capability.value) + # update features list if gpu feature is supported + node_space.features.update(features.Gpu.name()) # all nodes support following features - node_space.features = search_space.SetSpace[str](is_allow_set=True) node_space.features.update( [features.StartStop.name(), features.SerialConsole.name()] ) - # update features list if gpu feature is supported - if node_space.gpu_count: - node_space.features.update(features.Gpu.name()) - return node_space def _get_eligible_vm_sizes( diff --git a/lisa/tools/__init__.py b/lisa/tools/__init__.py index d011365215..a91a817cf8 100644 --- a/lisa/tools/__init__.py +++ b/lisa/tools/__init__.py @@ -17,8 +17,6 @@ from .reboot import Reboot from .uname import Uname from .uptime import Uptime - -# from .wget import Wget from .who import Who __all__ = [