From 1461515b24bacef7a1be7ae7950684f039a719c0 Mon Sep 17 00:00:00 2001 From: paull Date: Fri, 2 Aug 2024 21:16:39 -0700 Subject: [PATCH] Added BareMetal platform support for LTP/Kselftest --- microsoft/testsuites/kselftest/kselftest.py | 42 ++- microsoft/testsuites/ltp/ltp.py | 398 +++++++++++--------- microsoft/testsuites/ltp/ltpsuite.py | 3 +- 3 files changed, 243 insertions(+), 200 deletions(-) diff --git a/microsoft/testsuites/kselftest/kselftest.py b/microsoft/testsuites/kselftest/kselftest.py index 8c2f3cda7e..e4232519bc 100644 --- a/microsoft/testsuites/kselftest/kselftest.py +++ b/microsoft/testsuites/kselftest/kselftest.py @@ -10,7 +10,11 @@ from lisa.executable import Tool from lisa.messages import TestStatus, send_sub_test_result_message from lisa.node import Node -from lisa.operating_system import CBLMariner, Ubuntu +from lisa.operating_system import ( + BSD, FreeBSD, OpenBSD, BMC, MacOS, CoreOs, Alpine, + Debian, Ubuntu, RPMDistro, Fedora, Redhat, CentOs, + Oracle, AlmaLinux, CBLMariner, Suse, SLES, NixOS, OtherLinux, +) from lisa.testsuite import TestResult from lisa.tools import Cp, Git, Ls, Make, RemoteCopy, Tar from lisa.tools.chmod import Chmod @@ -99,27 +103,31 @@ def __init__( # tar file path specified in yml self._tar_file_path = kselftest_file_path if self._tar_file_path: + self._remote_tar_path = ( + self.node.get_pure_path("/tmp/kselftest") / os.path.basename(self._tar_file_path) + ) + self._kself_installed_dir = ( + self.node.get_pure_path("/tmp/kselftest") / "kselftest-packages" + ) + else: self._remote_tar_path = self.get_tool_path( use_global=True ) / os.path.basename(self._tar_file_path) - - # command to run kselftests - self._kself_installed_dir = ( - self.get_tool_path(use_global=True) / "kselftest-packages" - ) + self._kself_installed_dir = ( + self.get_tool_path(use_global=True) / "kselftest-packages" + ) self._command = self._kself_installed_dir / "run_kselftest.sh" # install common dependencies def _install(self) -> bool: - if not ( - ( - isinstance(self.node.os, Ubuntu) - and self.node.os.information.version >= "18.4.0" - ) - or isinstance(self.node.os, CBLMariner) + if (isinstance(self.node.os, + (BSD, FreeBSD, OpenBSD, BMC, MacOS, CoreOs, Alpine, + Debian, RPMDistro, Fedora, Redhat, CentOs, Oracle, + AlmaLinux, Suse, SLES, NixOS, OtherLinux)) + or (isinstance(self.node.os, Ubuntu) and self.node.os.information.version < "18.4.0") ): - raise UnsupportedDistroException( + raise UnsupportedDistroException( self.node.os, "kselftests in LISA does not support this os" ) @@ -202,14 +210,12 @@ def run_all( test_result: TestResult, log_path: str, timeout: int = 5000, - run_test_as_root: bool = False, ) -> List[KselftestResult]: # Executing kselftest as root may cause # VM to hang - # get username - username = self.node.tools[Whoami].get_username() - result_directory = f"/home/{username}" + # get result directory + result_directory = f"/tmp/" if os.path.exists(result_directory) is False: mkdir = self.node.tools[Mkdir] mkdir.create_directory(result_directory) @@ -218,7 +224,7 @@ def run_all( result_file = f"{result_directory}/{result_file_name}" self.run( f" 2>&1 | tee {result_file}", - sudo=run_test_as_root, + sudo=True, force_run=True, shell=True, timeout=timeout, diff --git a/microsoft/testsuites/ltp/ltp.py b/microsoft/testsuites/ltp/ltp.py index b45bd4a7e9..dd5148c783 100644 --- a/microsoft/testsuites/ltp/ltp.py +++ b/microsoft/testsuites/ltp/ltp.py @@ -1,6 +1,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT license. +import os import re from dataclasses import dataclass from pathlib import PurePath, PurePosixPath @@ -27,6 +28,7 @@ Rm, Swap, Sysctl, + Tar, ) from lisa.util import LisaException, find_patterns_in_lines @@ -52,30 +54,56 @@ class Ltp(Tool): LTP_DIR_NAME = "ltp" DEFAULT_LTP_TESTS_GIT_TAG = "20230929" LTP_GIT_URL = "https://github.com/linux-test-project/ltp.git" + LTP_RESULT_FILE = "ltp-results.log" + LTP_OUTPUT_FILE = "ltp-output.log" + LTP_SKIP_FILE = "skipfile" BUILD_REQUIRED_DISK_SIZE_IN_GB = 2 - LTP_RESULT_PATH = "/opt/ltp/ltp-results.log" - LTP_OUTPUT_PATH = "/opt/ltp/ltp-output.log" - LTP_SKIP_FILE = "/opt/ltp/skipfile" COMPILE_TIMEOUT = 1800 RUN_TIMEOUT = 12000 @property def command(self) -> str: - return "/opt/ltp/runltp" + return f"{self._command_path}runltp" @property def dependencies(self) -> List[Type[Tool]]: - return [Make, Gcc, Git] + if self._prebuild_package: + return [] + else: + return [Make, Gcc, Git] @property def can_install(self) -> bool: return True - def __init__(self, node: Node, *args: Any, **kwargs: Any) -> None: + @property + def result_path(self) -> str: + return f"{self._command_path}self.LTP_RESULT_FILE" + + @property + def output_path(self) -> str: + return f"{self._command_path}self.LTP_OUTPUT_FILE" + + @property + def skip_path(self) -> str: + return f"{self._command_path}self.LTP_SKIP_FILE" + + def _check_exists(self) -> bool: + return ( + len(self.node.tools[Ls].list(str(self._command_path), sudo=True)) > 0 + ) + + def __init__(self, node: Node, prebuild_package: str, *args: Any, **kwargs: Any) -> None: super().__init__(node, args, kwargs) git_tag = kwargs.get("git_tag", "") self._git_tag = git_tag if git_tag else self.DEFAULT_LTP_TESTS_GIT_TAG + self._prebuild_package = prebuild_package + if self._prebuild_package: + self._command_path = "/tmp/ltp/" + else: + self._command_path = "/opt/ltp/" + def run_test( self, test_result: TestResult, @@ -91,22 +119,22 @@ def run_test( rm = self.node.tools[Rm] # remove skipfile if it exists - if ls.path_exists(self.LTP_SKIP_FILE): - self._log.debug(f"Removing skipfile: {self.LTP_SKIP_FILE}") - rm.remove_file(self.LTP_SKIP_FILE, sudo=True) + if ls.path_exists(self.skip_path): + self._log.debug(f"Removing skipfile: {self.skip_path}") + rm.remove_file(self.skip_path, sudo=True) # remove results file if it exists - if ls.path_exists(self.LTP_RESULT_PATH, sudo=True): - self._log.debug(f"Removing {self.LTP_RESULT_PATH}") - rm.remove_file(self.LTP_RESULT_PATH, sudo=True) + if ls.path_exists(self.result_path, sudo=True): + self._log.debug(f"Removing {self.result_path}") + rm.remove_file(self.result_path, sudo=True) # remove output file if it exists - if ls.path_exists(self.LTP_OUTPUT_PATH, sudo=True): - self._log.debug(f"Removing {self.LTP_OUTPUT_PATH}") - rm.remove_file(self.LTP_OUTPUT_PATH, sudo=True) + if ls.path_exists(self.output_path, sudo=True): + self._log.debug(f"Removing {self.output_path}") + rm.remove_file(self.output_path, sudo=True) # add parameters for the test logging - parameters = f"-p -q -l {self.LTP_RESULT_PATH} -o {self.LTP_OUTPUT_PATH} " + parameters = f"-p -q -l {self.result_path} -o {self.output_path} " # add the list of tests to run parameters += f"-f {','.join(ltp_tests)} " @@ -124,37 +152,36 @@ def run_test( # write skip test to skipfile with newline separator skip_file_value = "\n".join(skip_tests) self.node.tools[Echo].write_to_file( - skip_file_value, PurePosixPath(self.LTP_SKIP_FILE), sudo=True + skip_file_value, PurePosixPath(self.skip_path), sudo=True ) - parameters += f"-S {self.LTP_SKIP_FILE} " + parameters += f"-S {self.skip_path} " # Minimum 4M swap space is needed by some mmp test if self.node.tools[Free].get_swap_size() < 4: self.node.tools[Swap].create_swap() # run ltp tests - command = f"{self.command} {parameters}" - self.node.execute_async( - f"echo y | {command}", + self.run( + parameters, sudo=True, + force_run=True, shell=True, + timeout=self.RUN_TIMEOUT, ) - pgrep = self.node.tools[Pgrep] - pgrep.wait_processes("runltp", timeout=self.RUN_TIMEOUT) - - # to avoid no permission issue when copying back files - self.node.tools[Chmod].update_folder("/opt", "a+rwX", sudo=True) + if not self._prebuild_package: + # to avoid no permission issue when copying back files + self.node.tools[Chmod].update_folder("/opt", "a+rwX", sudo=True) # write output to log path self.node.shell.copy_back( - PurePosixPath(self.LTP_OUTPUT_PATH), PurePath(log_path) / "ltp-output.log" + PurePosixPath(self.output_path), PurePath(log_path) / self.LTP_OUTPUT_FILE ) # write results to log path - local_ltp_results_path = PurePath(log_path) / "ltp-results.log" + local_ltp_results_path = PurePath(log_path) / self.LTP_RESULT_FILE self.node.shell.copy_back( - PurePosixPath(self.LTP_RESULT_PATH), local_ltp_results_path + PurePosixPath(self.result_path), local_ltp_results_path ) # parse results from local_ltp_results_path file @@ -191,175 +218,184 @@ def run_test( def _install(self) -> bool: assert isinstance(self.node.os, Posix), f"{self.node.os} is not supported" - # install common dependencies - self.node.os.install_packages( - [ - "m4", - "bison", - "flex", - "psmisc", - "autoconf", - "automake", - ] - ) - - # install distro specific dependencies - if isinstance(self.node.os, Fedora): - self.node.os.install_packages( - [ - "libaio-devel", - "libattr", - "libcap-devel", - "libdb", - "pkgconf", - "kernel-headers", - "glibc-headers", - ] - ) - - # db4-utils and ntp are not available in Redhat >= 8.0 - # ntp is replaced by chrony in Redhat8 release - if not ( - isinstance(self.node.os, Redhat) - and self.node.os.information.version >= "8.0.0" - ): - self.node.os.install_packages(["db4-utils", "ntp"]) - elif isinstance(self.node.os, Debian): + if self._prebuild_package: + remote_tar_path = self.node.get_pure_path(self._command_path) / os.path.basename(self._prebuild_package) + ltp_installed_dir = self.node.get_pure_path("/tmp") + mkdir = self.node.tools[Mkdir] + mkdir.create_directory(remote_tar_path.parent.as_posix()) + self.node.shell.copy(PurePath(self._prebuild_package), remote_tar_path) + self.node.tools[Tar].extract(str(remote_tar_path), str(ltp_installed_dir), sudo=True) + self._log.debug(f"Extracted tar from path {remote_tar_path}!") + else: + # install common dependencies self.node.os.install_packages( [ - "ntp", - "libaio-dev", - "libattr1", - "libcap-dev", - "keyutils", - "libdb4.8", - "libberkeleydb-perl", - "expect", - "dh-autoreconf", - "gdb", - "libnuma-dev", - "quota", - "genisoimage", - "db-util", - "unzip", - "pkgconf", - "libc6-dev", + "m4", + "bison", + "flex", + "psmisc", + "autoconf", + "automake", ] ) - # install "exfat-utils" - # Note: Package has been renamed to exfatprogs - try: - self.node.os.install_packages(["exfat-utils"]) - except Exception as e: - self._log.debug( - f"Failed to install exfat-utils: {e}, " - "Trying alternative package: exfatprogs" + # install distro specific dependencies + if isinstance(self.node.os, Fedora): + self.node.os.install_packages( + [ + "libaio-devel", + "libattr", + "libcap-devel", + "libdb", + "pkgconf", + "kernel-headers", + "glibc-headers", + ] ) - self.node.os.install_packages(["exfatprogs"]) - elif isinstance(self.node.os, Suse): - self.node.os.install_packages( - [ - "ntp", - "git-core", - "db48-utils", - "libaio-devel", - "libattr1", - "libcap-progs", - "libdb-4_8", - "perl-BerkeleyDB", - "pkg-config", - "linux-glibc-devel", - "glibc-devel", - ] - ) - elif isinstance(self.node.os, CBLMariner): - self.node.os.install_packages( - [ - "kernel-headers", - "binutils", - "glibc-devel", - "zlib-devel", - ] - ) - else: - raise LisaException(f"{self.node.os} is not supported") - - # Some CPU time is assigned to set real-time scheduler and it affects - # all cgroup test cases. The values for rt_period_us(1000000us or 1s) - # and rt_runtime_us (950000us or 0.95s). This gives 0.05s to be used - # by non-RT tasks. - if self.node.shell.exists( - PurePosixPath("/sys/fs/cgroup/cpu/user.slice/cpu.rt_runtime_us") - ): - runtime_us = self.node.tools[Cat].read( - "/sys/fs/cgroup/cpu/user.slice/cpu.rt_runtime_us", - force_run=True, - sudo=True, - ) - runtime_us_int = int(runtime_us) - if runtime_us_int == 0: - self.node.tools[Echo].write_to_file( - "1000000", - PurePosixPath("/sys/fs/cgroup/cpu/cpu.rt_period_us"), - sudo=True, + + # db4-utils and ntp are not available in Redhat >= 8.0 + # ntp is replaced by chrony in Redhat8 release + if not ( + isinstance(self.node.os, Redhat) + and self.node.os.information.version >= "8.0.0" + ): + self.node.os.install_packages(["db4-utils", "ntp"]) + elif isinstance(self.node.os, Debian): + self.node.os.install_packages( + [ + "ntp", + "libaio-dev", + "libattr1", + "libcap-dev", + "keyutils", + "libdb4.8", + "libberkeleydb-perl", + "expect", + "dh-autoreconf", + "gdb", + "libnuma-dev", + "quota", + "genisoimage", + "db-util", + "unzip", + "pkgconf", + "libc6-dev", + ] ) - self.node.tools[Echo].write_to_file( - "950000", - PurePosixPath("/sys/fs/cgroup/cpu/cpu.rt_runtime_us"), - sudo=True, + + # install "exfat-utils" + # Note: Package has been renamed to exfatprogs + try: + self.node.os.install_packages(["exfat-utils"]) + except Exception as e: + self._log.debug( + f"Failed to install exfat-utils: {e}, " + "Trying alternative package: exfatprogs" + ) + self.node.os.install_packages(["exfatprogs"]) + elif isinstance(self.node.os, Suse): + self.node.os.install_packages( + [ + "ntp", + "git-core", + "db48-utils", + "libaio-devel", + "libattr1", + "libcap-progs", + "libdb-4_8", + "perl-BerkeleyDB", + "pkg-config", + "linux-glibc-devel", + "glibc-devel", + ] ) - self.node.tools[Echo].write_to_file( - "1000000", - PurePosixPath("/sys/fs/cgroup/cpu/user.slice/cpu.rt_period_us"), - sudo=True, + elif isinstance(self.node.os, CBLMariner): + self.node.os.install_packages( + [ + "kernel-headers", + "binutils", + "glibc-devel", + "zlib-devel", + ] ) - self.node.tools[Echo].write_to_file( - "950000", - PurePosixPath("/sys/fs/cgroup/cpu/user.slice/cpu.rt_runtime_us"), + else: + raise LisaException(f"{self.node.os} is not supported") + + # Some CPU time is assigned to set real-time scheduler and it affects + # all cgroup test cases. The values for rt_period_us(1000000us or 1s) + # and rt_runtime_us (950000us or 0.95s). This gives 0.05s to be used + # by non-RT tasks. + if self.node.shell.exists( + PurePosixPath("/sys/fs/cgroup/cpu/user.slice/cpu.rt_runtime_us") + ): + runtime_us = self.node.tools[Cat].read( + "/sys/fs/cgroup/cpu/user.slice/cpu.rt_runtime_us", + force_run=True, sudo=True, ) + runtime_us_int = int(runtime_us) + if runtime_us_int == 0: + self.node.tools[Echo].write_to_file( + "1000000", + PurePosixPath("/sys/fs/cgroup/cpu/cpu.rt_period_us"), + sudo=True, + ) + self.node.tools[Echo].write_to_file( + "950000", + PurePosixPath("/sys/fs/cgroup/cpu/cpu.rt_runtime_us"), + sudo=True, + ) + self.node.tools[Echo].write_to_file( + "1000000", + PurePosixPath("/sys/fs/cgroup/cpu/user.slice/cpu.rt_period_us"), + sudo=True, + ) + self.node.tools[Echo].write_to_file( + "950000", + PurePosixPath("/sys/fs/cgroup/cpu/user.slice/cpu.rt_runtime_us"), + sudo=True, + ) + + # Fix hung_task_timeout_secs and blocked for more than 120 seconds problem + sysctl = self.node.tools[Sysctl] + sysctl.write("vm.dirty_ratio", "10") + sysctl.write("vm.dirty_background_ratio", "5") + sysctl.run("-p") + + # find partition to install ltp + build_dir = self.node.find_partition_with_freespace( + self.BUILD_REQUIRED_DISK_SIZE_IN_GB + ) + top_src_dir = f"{build_dir}/{self.LTP_DIR_NAME}".replace("//", "/") - # Fix hung_task_timeout_secs and blocked for more than 120 seconds problem - sysctl = self.node.tools[Sysctl] - sysctl.write("vm.dirty_ratio", "10") - sysctl.write("vm.dirty_background_ratio", "5") - sysctl.run("-p") - - # find partition to install ltp - build_dir = self.node.find_partition_with_freespace( - self.BUILD_REQUIRED_DISK_SIZE_IN_GB - ) - top_src_dir = f"{build_dir}/{self.LTP_DIR_NAME}".replace("//", "/") - - # remove build directory if it exists - if self.node.tools[Ls].path_exists(top_src_dir, sudo=True): - self.node.tools[Rm].remove_directory(top_src_dir, sudo=True) + # remove build directory if it exists + if self.node.tools[Ls].path_exists(top_src_dir, sudo=True): + self.node.tools[Rm].remove_directory(top_src_dir, sudo=True) - # setup build directory - self.node.tools[Mkdir].create_directory(top_src_dir, sudo=True) - self.node.tools[Chmod].update_folder(top_src_dir, "a+rwX", sudo=True) + # setup build directory + self.node.tools[Mkdir].create_directory(top_src_dir, sudo=True) + self.node.tools[Chmod].update_folder(top_src_dir, "a+rwX", sudo=True) - # clone ltp - git = self.node.tools[Git] - ltp_path = git.clone( - self.LTP_GIT_URL, cwd=PurePosixPath(top_src_dir), dir_name=top_src_dir - ) + # clone ltp + git = self.node.tools[Git] + ltp_path = git.clone( + self.LTP_GIT_URL, cwd=PurePosixPath(top_src_dir), dir_name=top_src_dir + ) - # checkout tag - git.checkout(ref=f"tags/{self._git_tag}", cwd=ltp_path) + # checkout tag + git.checkout(ref=f"tags/{self._git_tag}", cwd=ltp_path) - # build ltp in /opt/ltp since this path is used by some - # tests, e.g, block_dev test - make = self.node.tools[Make] - self.node.execute("autoreconf -f", cwd=ltp_path, sudo=True) - make.make("autotools", cwd=ltp_path, sudo=True) - self.node.execute("./configure --prefix=/opt/ltp", cwd=ltp_path, sudo=True) - make.make("all", cwd=ltp_path, sudo=True, timeout=self.COMPILE_TIMEOUT) + # build ltp in /opt/ltp since this path is used by some + # tests, e.g, block_dev test + make = self.node.tools[Make] + self.node.execute("autoreconf -f", cwd=ltp_path, sudo=True) + make.make("autotools", cwd=ltp_path, sudo=True) + self.node.execute("./configure --prefix=/opt/ltp", cwd=ltp_path, sudo=True) + make.make("all", cwd=ltp_path, sudo=True, timeout=self.COMPILE_TIMEOUT) - # Specify SKIP_IDCHECK=1 since we don't want to modify /etc/{group,passwd} - # on the remote system's sysroot - make.make_install(ltp_path, "SKIP_IDCHECK=1", sudo=True) + # Specify SKIP_IDCHECK=1 since we don't want to modify /etc/{group,passwd} + # on the remote system's sysroot + make.make_install(ltp_path, "SKIP_IDCHECK=1", sudo=True) return self._check_exists() diff --git a/microsoft/testsuites/ltp/ltpsuite.py b/microsoft/testsuites/ltp/ltpsuite.py index 04e6a6e95c..50cf81b9d7 100644 --- a/microsoft/testsuites/ltp/ltpsuite.py +++ b/microsoft/testsuites/ltp/ltpsuite.py @@ -58,6 +58,7 @@ def verify_ltp_lite( tests = variables.get("ltp_test", "") skip_tests = variables.get("ltp_skip_test", "") ltp_tests_git_tag = variables.get("ltp_tests_git_tag", "") + ltp_prebuilt_file = variables.get("ltp_prebuilt_file", "") # block device is required for few ltp tests # If not provided, we will find a disk with enough space @@ -85,7 +86,7 @@ def verify_ltp_lite( ) # run ltp lite tests - ltp: Ltp = node.tools.get(Ltp, git_tag=ltp_tests_git_tag) + ltp: Ltp = node.tools.get(Ltp, ltp_prebuilt_file, git_tag=ltp_tests_git_tag) ltp.run_test( result, test_list,