From 22b55f29fd88b6131829ae9c158255d58ee0f6fb 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 | 72 +++- microsoft/testsuites/ltp/ltp.py | 400 +++++++++++--------- microsoft/testsuites/ltp/ltpsuite.py | 6 +- 3 files changed, 270 insertions(+), 208 deletions(-) diff --git a/microsoft/testsuites/kselftest/kselftest.py b/microsoft/testsuites/kselftest/kselftest.py index 8c2f3cda7e..026ecf9be6 100644 --- a/microsoft/testsuites/kselftest/kselftest.py +++ b/microsoft/testsuites/kselftest/kselftest.py @@ -10,12 +10,21 @@ 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 ( + CBLMariner, + Debian, + Linux, + NixOS, + OtherLinux, + Posix, + RPMDistro, + Suse, + Ubuntu, +) from lisa.testsuite import TestResult from lisa.tools import Cp, Git, Ls, Make, RemoteCopy, Tar from lisa.tools.chmod import Chmod from lisa.tools.mkdir import Mkdir -from lisa.tools.whoami import Whoami from lisa.util import LisaException, UnsupportedDistroException, find_groups_in_lines _UBUNTU_OS_PACKAGES = [ @@ -98,31 +107,56 @@ def __init__( # tar file path specified in yml self._tar_file_path = kselftest_file_path + kselftest_install_path = "/tmp/kselftest" + kselftest_packages = "kselftest-packages" if self._tar_file_path: - 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._remote_tar_path = ( + self.node.get_pure_path( + kselftest_install_path + ) / os.path.basename(self._tar_file_path) + ) + self._kself_installed_dir = ( + self.node.get_pure_path( + kselftest_install_path + ) / kselftest_packages + ) + else: + self._remote_tar_path = ( + self.get_tool_path( + use_global=True + ) / os.path.basename(self._tar_file_path) + ) + 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 ( + if ( ( + isinstance(self.node.os, Posix) + and not isinstance(self.node.os, Linux) + ) + or ( + isinstance(self.node.os, Debian) + and not isinstance(self.node.os, Ubuntu) + ) + or ( isinstance(self.node.os, Ubuntu) - and self.node.os.information.version >= "18.4.0" + and self.node.os.information.version < "18.4.0" ) - or isinstance(self.node.os, CBLMariner) + or ( + isinstance(self.node.os, RPMDistro) + and not isinstance(self.node.os, CBLMariner) + ) + or (isinstance(self.node.os, (Suse, NixOS, OtherLinux))) ): raise UnsupportedDistroException( - self.node.os, "kselftests in LISA does not support this os" + self.node.os, + "kselftests in LISA does not support this os" ) - if self._tar_file_path: mkdir = self.node.tools[Mkdir] mkdir.create_directory(self._remote_tar_path.parent.as_posix()) @@ -202,14 +236,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 = "/tmp/" if os.path.exists(result_directory) is False: mkdir = self.node.tools[Mkdir] mkdir.create_directory(result_directory) @@ -218,7 +250,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 f315a71a06..080ffb9f33 100644 --- a/microsoft/testsuites/ltp/ltp.py +++ b/microsoft/testsuites/ltp/ltp.py @@ -1,5 +1,6 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT license. + import os import re from dataclasses import dataclass @@ -24,7 +25,6 @@ Make, Mkdir, Pgrep, - RemoteCopy, Rm, Swap, Sysctl, @@ -54,30 +54,55 @@ 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" + LTP_RUN_COMMAND = "runltp" 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}{self.LTP_RUN_COMMAND}" @property def dependencies(self) -> List[Type[Tool]]: - return [Make, Gcc, Git] + if self._prebuilt_file: + return [] + else: + return [Make, Gcc, Git] @property def can_install(self) -> bool: return True - def __init__(self, node: Node, source_file: str, *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 __init__(self, + node: Node, + prebuilt_file: 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._source_file = source_file + + self._prebuilt_file = prebuilt_file + if self._prebuilt_file: + self._command_path = "/tmp/ltp/" + else: + self._command_path = "/opt/ltp/" def run_test( self, @@ -94,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)} " @@ -127,9 +152,9 @@ 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: @@ -144,20 +169,21 @@ def run_test( ) pgrep = self.node.tools[Pgrep] - pgrep.wait_processes("runltp", timeout=self.RUN_TIMEOUT) + pgrep.wait_processes(self.LTP_RUN_COMMAND, 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._prebuilt_file: + # 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 @@ -194,170 +220,172 @@ 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", - ] + if self._prebuilt_file: + remote_tar_path = self.node.get_pure_path( + self._command_path + ) / os.path.basename(self._prebuilt_file) + 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._prebuilt_file), remote_tar_path ) - - # 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.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, + ) + cpu_file = "/sys/fs/cgroup/cpu/user.slice/cpu.rt_runtime_us" + self.node.tools[Echo].write_to_file( + "950000", + PurePosixPath(cpu_file), + 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) - if self._source_file: - self._log.debug( - f"Use downloaded source code tar file: {self._source_file}!" - ) - remote_source_file = self.get_tool_path(use_global=True) / os.path.basename( - self._source_file - ) - - copy = self.node.tools[RemoteCopy] - copy.copy_to_remote(PurePath(self._source_file), remote_source_file) - self.node.tools[Tar].extract( - str(remote_source_file), top_src_dir, sudo=True - ) - ltp_path = self.node.get_pure_path(top_src_dir) - else: # clone ltp git = self.node.tools[Git] ltp_path = git.clone( @@ -367,17 +395,17 @@ def _install(self) -> bool: # 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) - - # 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) + # 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) return self._check_exists() diff --git a/microsoft/testsuites/ltp/ltpsuite.py b/microsoft/testsuites/ltp/ltpsuite.py index 1bb1656338..7cc383b741 100644 --- a/microsoft/testsuites/ltp/ltpsuite.py +++ b/microsoft/testsuites/ltp/ltpsuite.py @@ -62,10 +62,10 @@ def verify_ltp_lite( result: TestResult, ) -> None: # parse variables - ltp_source_file = variables.get("ltp_source_file", "") 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 @@ -94,7 +94,9 @@ def verify_ltp_lite( # run ltp lite tests ltp: Ltp = node.tools.get( - Ltp, git_tag=ltp_tests_git_tag, source_file=ltp_source_file + Ltp, + prebuilt_file=ltp_prebuilt_file, + git_tag=ltp_tests_git_tag, ) ltp.run_test( result,