diff --git a/lisa/base_tools/mv.py b/lisa/base_tools/mv.py index 3102bf6aac..bf79259ba5 100644 --- a/lisa/base_tools/mv.py +++ b/lisa/base_tools/mv.py @@ -2,6 +2,7 @@ # Licensed under the MIT license. from lisa.executable import Tool +from typing import Union class Mv(Tool): @@ -14,13 +15,15 @@ def can_install(self) -> bool: return False def move( - self, src_path: str, dest_path: str, overwrite: bool = False, sudo: bool = False + self, src_path: str, dest_path: str, overwrite: bool = False, + sudo: bool = False, ignore_error: bool = False ) -> None: args = "-f" if overwrite else "" + expected_exit_code = None if ignore_error else 0 self.run( f"{args} {src_path} {dest_path}", sudo=sudo, shell=True, force_run=True, - expected_exit_code=0, + expected_exit_code=expected_exit_code, ) diff --git a/lisa/transformers/kernel_source_installer.py b/lisa/transformers/kernel_source_installer.py index 577e3975e3..3df48b626b 100644 --- a/lisa/transformers/kernel_source_installer.py +++ b/lisa/transformers/kernel_source_installer.py @@ -93,6 +93,9 @@ class SourceInstallerSchema(BaseInstallerSchema): ), ) + # Additional build dependencies + build_deps: List[str] = field(default_factory=list) + class SourceInstaller(BaseInstaller): _code_path: PurePath @@ -143,7 +146,7 @@ def install(self) -> str: runbook: SourceInstallerSchema = self.runbook assert runbook.location, "the repo must be defined." - self._install_build_tools(node) + self._install_build_tools(node, runbook.build_deps) factory = subclasses.Factory[BaseLocation](BaseLocation) source = factory.create_by_runbook( @@ -286,33 +289,49 @@ def _build_code(self, node: Node, code_path: PurePath, kconfig_file: str) -> Non ) result.assert_exit_code() - # the gcc version of Redhat 7.x is too old. Upgrade it. - if isinstance(node.os, Redhat) and node.os.information.version < "8.0.0": - node.os.install_packages(["devtoolset-8"]) - node.tools[Mv].move("/bin/gcc", "/bin/gcc_back", overwrite=True, sudo=True) - result.assert_exit_code() - result = node.execute( - "ln -s /opt/rh/devtoolset-8/root/usr/bin/gcc /bin/gcc", sudo=True - ) - result.assert_exit_code() - make = node.tools[Make] make.make(arguments="olddefconfig", cwd=code_path) # set timeout to 2 hours make.make(arguments="", cwd=code_path, timeout=60 * 60 * 2) - def _install_build_tools(self, node: Node) -> None: + def _fix_mirrorlist_to_vault(self, node: Node) -> None: + node.execute("sed -i '\ + s/^mirrorlist=/#mirrorlist=/;\ + s/^#baseurl=/baseurl=/;\ + /^baseurl=/ s/mirror/vault/\ + ' /etc/yum.repos.d/CentOS-*.repo", shell=True, sudo=True) + + def _install_build_tools(self, node: Node, build_deps: list[str]) -> None: os = node.os self._log.info("installing build tools") + if isinstance(node.os, Redhat) and node.os.information.version < "8.0.0": + self._fix_mirrorlist_to_vault(node) if isinstance(os, Redhat): for package in list( - ["elfutils-libelf-devel", "openssl-devel", "dwarves", "bc"] + ["elfutils-libelf-devel", "openssl-devel", "dwarves", "bc"] + build_deps ): if os.is_package_in_repo(package): os.install_packages(package) os.group_install_packages("Development Tools") + # if the kernel requires devtoolset, install its gcc + devtoolsets = [ + pkg + for pkg in build_deps + if pkg.startswith("devtoolset") + ] + if devtoolsets: + assert len(devtoolsets) == 1, f"only one devtoolset can be given, instead of {devtoolsets}" + devtoolset = devtoolsets[0] + node.os.install_packages(devtoolset) + node.tools[Mv].move("/bin/gcc", "/bin/gcc_back", overwrite=True, sudo=True) + result.assert_exit_code() + result = node.execute( + f"ln -s /opt/rh/{devtoolset}/root/usr/bin/gcc /bin/gcc", sudo=True + ) + result.assert_exit_code(f"can not link {devtoolset} to gcc") + if os.information.version < "8.0.0": # git from default CentOS/RedHat 7.x does not support git tag format # syntax temporarily use a community repo, then remove it @@ -336,7 +355,7 @@ def _install_build_tools(self, node: Node) -> None: "libssl-dev", "bc", "ccache", - ] + ] + build_deps ) elif isinstance(os, CBLMariner): os.install_packages( @@ -355,7 +374,7 @@ def _install_build_tools(self, node: Node) -> None: "xz-libs", "openssl-libs", "openssl-devel", - ] + ] + build_deps ) else: raise LisaException( diff --git a/microsoft/testsuites/dpdk/dpdktestpmd.py b/microsoft/testsuites/dpdk/dpdktestpmd.py index facea07d82..dfb7d3acf8 100644 --- a/microsoft/testsuites/dpdk/dpdktestpmd.py +++ b/microsoft/testsuites/dpdk/dpdktestpmd.py @@ -13,8 +13,9 @@ from lisa.executable import ExecutableResult, Tool from lisa.features import Disk from lisa.nic import NicInfo -from lisa.operating_system import Debian, Fedora, Suse, Ubuntu +from lisa.operating_system import Debian, Fedora, Suse, Ubuntu, Redhat from lisa.tools import ( + Cat, Chmod, Dmesg, Echo, @@ -325,6 +326,7 @@ def generate_testpmd_command( ).is_greater_than(0) return ( + f"env LD_LIBRARY_PATH=/usr/local/lib64 " f"{self._testpmd_install_path} {core_list} " f"{nic_include_info} {log_level_args}" f" -- --forward-mode={mode} " @@ -488,6 +490,8 @@ def get_dpdk_portmask(self, ports: List[int]) -> str: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + # do not update kernel on backporting + self.update_kernel = kwargs.pop("update_kernel", True) # set source args for builds if needed, first for dpdk self.dpdk_build_path: Optional[PurePath] = None self._dpdk_source: str = kwargs.pop("dpdk_source", PACKAGE_MANAGER_SOURCE) @@ -499,6 +503,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: node=self.node, rdma_core_source=rdma_core_source, rdma_core_ref=rdma_core_ref, + update_kernel=self.update_kernel, ) self._sample_apps_to_build = kwargs.pop("sample_apps", list()) self._dpdk_version_info = VersionInfo(0, 0) @@ -531,7 +536,8 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: ) # if dpdk is already installed, find the binary and check the version - if self.find_testpmd_binary(assert_on_fail=False): + if self.find_testpmd_binary(assert_on_fail=False) or \ + self.find_testpmd_binary(check_path='/usr/local/bin', assert_on_fail=False): pkgconfig = self.node.tools[Pkgconfig] if pkgconfig.package_info_exists( self._dpdk_lib_name, @@ -592,6 +598,13 @@ def _set_backport_repo_args(self) -> None: else: self._backport_repo_args = [] + def _fix_mirrorlist_to_vault(self, node) -> None: + node.execute("""sed -i ' + s/^mirrorlist=/#mirrorlist=/; + s/^#[ ]*baseurl=/baseurl=/; + /^baseurl=/ s/mirror/vault/; + ' /etc/yum.repos.d/CentOS-*.repo""", shell=True, sudo=True) + def _install(self) -> bool: self._testpmd_output_after_reenable = "" self._testpmd_output_before_rescind = "" @@ -610,6 +623,33 @@ def _install(self) -> bool: ) ) + if isinstance(node.os, Redhat) and node.os.information.version < "8.0.0": + self._fix_mirrorlist_to_vault(node) + node.os.install_packages(["centos-release-scl"]) + + # Fix CentOS-SCL's paths to mirrorlist + self._fix_mirrorlist_to_vault(node) + devtoolset_version = 8 + devtoolset_pkg = f"devtoolset-{devtoolset_version}" + node.os.install_packages([devtoolset_pkg]) + links = { + "gcc": ("gcc", "cc"), + "g++": ("g++", "c++"), + } + for binary in [alias + for aliases in links.values() + for alias in aliases + ]: + node.tools[Mv].move(f"/bin/{binary}", f"/bin/{binary}_back", + overwrite=True, sudo=True, ignore_error=None) + devtoolset_binpath = f"/opt/rh/{devtoolset_pkg}/root/bin" + for binary, aliases in links.items(): + for alias in aliases: + result = node.execute( + f"ln -s {devtoolset_binpath}/{binary} /bin/{alias}", sudo=True + ) + result.assert_exit_code() + # before doing anything: determine if backport repo needs to be enabled self._set_backport_repo_args() @@ -672,11 +712,11 @@ def _install(self) -> bool: if ( isinstance(distro, Debian) or isinstance(distro, (Fedora, Suse)) - and distro.package_exists("dpdk") ): # if not using package manager and dpdk is already installed, uninstall it # in preperation for source build - distro.uninstall_packages("dpdk") + if distro.package_exists("dpdk"): + distro.uninstall_packages("dpdk") else: raise NotImplementedError( "Dpdk package names are missing in dpdktestpmd.install" @@ -756,11 +796,20 @@ def _install(self) -> bool: # add mana driver to build if needed if self.vf_helper.is_mana(): drivers_to_build += ",net/mana" - # shrink build - build_flags += [ - f"-Denable_drivers={drivers_to_build}", - "-Denable_apps=app/test-pmd", - ] + + # shrink build, if supported + cat = node.tools[Cat] + meson_options_content = cat.run("meson_options.txt", + cwd=self.dpdk_path, shell=True).stdout + if "enable_drivers" in meson_options_content: + build_flags += [ + f"-Denable_drivers={drivers_to_build}" + ] + + if "enable_apps" in meson_options_content: + build_flags += [ + "-Denable_apps=app/test-pmd" + ] node.execute( f"meson setup {' '.join(build_flags)} build", @@ -861,7 +910,7 @@ def _load_drivers_for_dpdk(self) -> None: if isinstance(self.node.os, (Ubuntu, Suse)): # Ubuntu shouldn't need any special casing, skip to loading rdma/ib pass - elif isinstance(self.node.os, Debian): + elif self.update_kernel and isinstance(self.node.os, Debian): # NOTE: debian buster doesn't include rdma and ib drivers # on 5.4 specifically for linux-image-cloud: # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1012639 @@ -960,8 +1009,9 @@ def _install_ubuntu_dependencies(self) -> None: return # appease the type checker # apply update to latest first - ubuntu.update_packages("linux-azure") - node.reboot() + if self.update_kernel: + ubuntu.update_packages("linux-azure") + node.reboot() if ubuntu.information.version < "18.4.0": raise SkippedException( f"Ubuntu {str(ubuntu.information.version)} is not supported. " @@ -980,9 +1030,8 @@ def _install_ubuntu_dependencies(self) -> None: extra_args=self._backport_repo_args, ) # MANA tests use linux-modules-extra-azure, install if it's available. - if self.vf_helper.is_mana() and ubuntu.is_package_in_repo( - "linux-modules-extra-azure" - ): + if self.update_kernel and self.vf_helper.is_mana() and \ + ubuntu.is_package_in_repo("linux-modules-extra-azure"): ubuntu.install_packages("linux-modules-extra-azure") def _install_fedora_dependencies(self) -> None: @@ -997,12 +1046,13 @@ def _install_fedora_dependencies(self) -> None: # DPDK is very sensitive to rdma-core/kernel mismatches # update to latest kernel before installing dependencies - rhel.install_packages(["kernel", "kernel-modules-extra", "kernel-headers"]) - node.reboot() - try: - rhel.install_packages("kernel-devel") - except MissingPackagesException: - node.log.debug("Fedora: kernel-devel not found, attempting to continue") + if self.update_kernel: + rhel.install_packages(["kernel", "kernel-modules-extra", "kernel-headers"]) + node.reboot() + try: + rhel.install_packages("kernel-devel") + except MissingPackagesException: + node.log.debug("Fedora: kernel-devel not found, attempting to continue") if rhel.information.version.major == 7: # Add packages for rhel7 @@ -1015,6 +1065,7 @@ def _install_fedora_dependencies(self) -> None: rhel.group_install_packages("Development Tools") rhel.install_packages(self._fedora_packages) + rhel.uninstall_packages(["doxygen"]) # ensure RDMA service is started if present. diff --git a/microsoft/testsuites/dpdk/dpdkutil.py b/microsoft/testsuites/dpdk/dpdkutil.py index a425266b27..fa5b476d8c 100644 --- a/microsoft/testsuites/dpdk/dpdkutil.py +++ b/microsoft/testsuites/dpdk/dpdkutil.py @@ -23,7 +23,7 @@ from lisa.base_tools.uname import Uname from lisa.features import NetworkInterface from lisa.nic import NicInfo -from lisa.operating_system import Fedora, OperatingSystem, Ubuntu +from lisa.operating_system import Fedora, OperatingSystem, Ubuntu, CentOs from lisa.tools import ( Dmesg, Echo, @@ -178,8 +178,15 @@ def _set_forced_source_by_distro( # Default to 20.11 unless another version is provided by the # user. 20.11 is the latest dpdk version for 18.04. if ( - isinstance(node.os, Ubuntu) - and node.os.information.version < "20.4.0" + ( + isinstance(node.os, Ubuntu) + and node.os.information.version < "20.4.0" + ) + or + ( + isinstance(node.os, CentOs) + and node.os.information.version < "8.0.0" + ) or examples != None ): variables["dpdk_source"] = variables.get("dpdk_source", DPDK_STABLE_GIT_REPO) @@ -333,6 +340,7 @@ def initialize_node_resources( dpdk_branch = variables.get("dpdk_branch", "") rdma_core_source = variables.get("rdma_core_source", "") rdma_core_ref = variables.get("rdma_core_git_ref", "") + update_kernel = variables.get("dpdk_update_kernel", True) force_net_failsafe_pmd = variables.get("dpdk_force_net_failsafe_pmd", False) enforce_strict_threshold = variables.get("dpdk_enforce_strict_threshold", False) log.info( @@ -374,6 +382,7 @@ def initialize_node_resources( rdma_core_ref=rdma_core_ref, enforce_strict_threshold=enforce_strict_threshold, build_release=build_release, + update_kernel=update_kernel, ) # init and enable hugepages (required by dpdk) diff --git a/microsoft/testsuites/dpdk/rdma_core.py b/microsoft/testsuites/dpdk/rdma_core.py index d5e6334978..2dcf1485f0 100644 --- a/microsoft/testsuites/dpdk/rdma_core.py +++ b/microsoft/testsuites/dpdk/rdma_core.py @@ -14,7 +14,8 @@ class RdmaCoreManager: - def __init__(self, node: Node, rdma_core_source: str, rdma_core_ref: str) -> None: + def __init__(self, node: Node, rdma_core_source: str, rdma_core_ref: str, + update_kernel: bool) -> None: self.is_installed_from_source = False self.node = node self._rdma_core_source = rdma_core_source @@ -27,6 +28,8 @@ def __init__(self, node: Node, rdma_core_source: str, rdma_core_ref: str) -> Non assert build_location, "Could not find a location to build rdma-core" self._build_location = node.get_pure_path(build_location).joinpath("rdma") + self.update_kernel = update_kernel + def get_missing_distro_packages(self) -> str: distro = self.node.os package = "" @@ -186,13 +189,14 @@ def do_source_install(self) -> None: "libbpf-devel", ] ) - distro.install_packages( - [ - "kernel-devel", - "kernel-modules-extra", - "kernel-headers", - ] - ) + if self.update_kernel: + distro.install_packages( + [ + "kernel-devel", + "kernel-modules-extra", + "kernel-headers", + ] + ) else: # no-op, throw for invalid distro is before this function return