1840b1e01SJuraj Linkeš# SPDX-License-Identifier: BSD-3-Clause 2840b1e01SJuraj Linkeš# Copyright(c) 2023 PANTHEON.tech s.r.o. 3840b1e01SJuraj Linkeš# Copyright(c) 2023 University of New Hampshire 4fd8cd8eeSLuca Vizzarro# Copyright(c) 2024 Arm Limited 5840b1e01SJuraj Linkeš 66ef07151SJuraj Linkeš"""OS-aware remote session. 76ef07151SJuraj Linkeš 86ef07151SJuraj LinkešDPDK supports multiple different operating systems, meaning it can run on these different operating 96ef07151SJuraj Linkešsystems. This module defines the common API that OS-unaware layers use and translates the API into 106ef07151SJuraj LinkešOS-aware calls/utility usage. 116ef07151SJuraj Linkeš 126ef07151SJuraj LinkešNote: 136ef07151SJuraj Linkeš Running commands with administrative privileges requires OS awareness. This is the only layer 146ef07151SJuraj Linkeš that's aware of OS differences, so this is where non-privileged command get converted 156ef07151SJuraj Linkeš to privileged commands. 166ef07151SJuraj Linkeš 176ef07151SJuraj LinkešExample: 186ef07151SJuraj Linkeš A user wishes to remove a directory on a remote :class:`~.sut_node.SutNode`. 196ef07151SJuraj Linkeš The :class:`~.sut_node.SutNode` object isn't aware what OS the node is running - it delegates 206ef07151SJuraj Linkeš the OS translation logic to :attr:`~.node.Node.main_session`. The SUT node calls 216ef07151SJuraj Linkeš :meth:`~OSSession.remove_remote_dir` with a generic, OS-unaware path and 226ef07151SJuraj Linkeš the :attr:`~.node.Node.main_session` translates that to ``rm -rf`` if the node's OS is Linux 236ef07151SJuraj Linkeš and other commands for other OSs. It also translates the path to match the underlying OS. 246ef07151SJuraj Linkeš""" 25840b1e01SJuraj Linkešfrom abc import ABC, abstractmethod 26840b1e01SJuraj Linkešfrom collections.abc import Iterable 27c72ff85dSLuca Vizzarrofrom dataclasses import dataclass 2880158fd4STomáš Ďurovecfrom pathlib import Path, PurePath, PurePosixPath 29840b1e01SJuraj Linkeš 30c72ff85dSLuca Vizzarrofrom framework.config import Architecture, NodeConfiguration 3104f5a5a6SJuraj Linkešfrom framework.logger import DTSLogger 32840b1e01SJuraj Linkešfrom framework.remote_session import ( 33840b1e01SJuraj Linkeš InteractiveRemoteSession, 34840b1e01SJuraj Linkeš RemoteSession, 35840b1e01SJuraj Linkeš create_interactive_session, 36840b1e01SJuraj Linkeš create_remote_session, 37840b1e01SJuraj Linkeš) 382b2f5a8aSLuca Vizzarrofrom framework.remote_session.remote_session import CommandResult 39840b1e01SJuraj Linkešfrom framework.settings import SETTINGS 4080158fd4STomáš Ďurovecfrom framework.utils import MesonArgs, TarCompressionFormat 41840b1e01SJuraj Linkeš 42840b1e01SJuraj Linkešfrom .cpu import LogicalCore 43840b1e01SJuraj Linkešfrom .port import Port 44840b1e01SJuraj Linkeš 45840b1e01SJuraj Linkeš 46c72ff85dSLuca Vizzarro@dataclass(slots=True, frozen=True) 47c72ff85dSLuca Vizzarroclass OSSessionInfo: 48c72ff85dSLuca Vizzarro """Supplemental OS session information. 49c72ff85dSLuca Vizzarro 50c72ff85dSLuca Vizzarro Attributes: 51c72ff85dSLuca Vizzarro os_name: The name of the running operating system of 52c72ff85dSLuca Vizzarro the :class:`~framework.testbed_model.node.Node`. 53c72ff85dSLuca Vizzarro os_version: The version of the running operating system of 54c72ff85dSLuca Vizzarro the :class:`~framework.testbed_model.node.Node`. 55c72ff85dSLuca Vizzarro kernel_version: The kernel version of the running operating system of 56c72ff85dSLuca Vizzarro the :class:`~framework.testbed_model.node.Node`. 57c72ff85dSLuca Vizzarro """ 58c72ff85dSLuca Vizzarro 59c72ff85dSLuca Vizzarro os_name: str 60c72ff85dSLuca Vizzarro os_version: str 61c72ff85dSLuca Vizzarro kernel_version: str 62c72ff85dSLuca Vizzarro 63c72ff85dSLuca Vizzarro 64840b1e01SJuraj Linkešclass OSSession(ABC): 656ef07151SJuraj Linkeš """OS-unaware to OS-aware translation API definition. 666ef07151SJuraj Linkeš 676ef07151SJuraj Linkeš The OSSession classes create a remote session to a DTS node and implement OS specific 68840b1e01SJuraj Linkeš behavior. There a few control methods implemented by the base class, the rest need 696ef07151SJuraj Linkeš to be implemented by subclasses. 706ef07151SJuraj Linkeš 716ef07151SJuraj Linkeš Attributes: 726ef07151SJuraj Linkeš name: The name of the session. 736ef07151SJuraj Linkeš remote_session: The remote session maintaining the connection to the node. 746ef07151SJuraj Linkeš interactive_session: The interactive remote session maintaining the connection to the node. 75840b1e01SJuraj Linkeš """ 76840b1e01SJuraj Linkeš 77840b1e01SJuraj Linkeš _config: NodeConfiguration 78840b1e01SJuraj Linkeš name: str 7904f5a5a6SJuraj Linkeš _logger: DTSLogger 80840b1e01SJuraj Linkeš remote_session: RemoteSession 81840b1e01SJuraj Linkeš interactive_session: InteractiveRemoteSession 82e5307b25SNicholas Pratte hugepage_size: int 83840b1e01SJuraj Linkeš 84840b1e01SJuraj Linkeš def __init__( 85840b1e01SJuraj Linkeš self, 86840b1e01SJuraj Linkeš node_config: NodeConfiguration, 87840b1e01SJuraj Linkeš name: str, 8804f5a5a6SJuraj Linkeš logger: DTSLogger, 89840b1e01SJuraj Linkeš ): 906ef07151SJuraj Linkeš """Initialize the OS-aware session. 916ef07151SJuraj Linkeš 926ef07151SJuraj Linkeš Connect to the node right away and also create an interactive remote session. 936ef07151SJuraj Linkeš 946ef07151SJuraj Linkeš Args: 956ef07151SJuraj Linkeš node_config: The test run configuration of the node to connect to. 966ef07151SJuraj Linkeš name: The name of the session. 976ef07151SJuraj Linkeš logger: The logger instance this session will use. 986ef07151SJuraj Linkeš """ 99e5307b25SNicholas Pratte self.hugepage_size = 2048 100840b1e01SJuraj Linkeš self._config = node_config 101840b1e01SJuraj Linkeš self.name = name 102840b1e01SJuraj Linkeš self._logger = logger 103840b1e01SJuraj Linkeš self.remote_session = create_remote_session(node_config, name, logger) 104840b1e01SJuraj Linkeš self.interactive_session = create_interactive_session(node_config, logger) 105840b1e01SJuraj Linkeš 106840b1e01SJuraj Linkeš def is_alive(self) -> bool: 1076ef07151SJuraj Linkeš """Check whether the underlying remote session is still responding.""" 108840b1e01SJuraj Linkeš return self.remote_session.is_alive() 109840b1e01SJuraj Linkeš 110840b1e01SJuraj Linkeš def send_command( 111840b1e01SJuraj Linkeš self, 112840b1e01SJuraj Linkeš command: str, 113840b1e01SJuraj Linkeš timeout: float = SETTINGS.timeout, 114840b1e01SJuraj Linkeš privileged: bool = False, 115840b1e01SJuraj Linkeš verify: bool = False, 116840b1e01SJuraj Linkeš env: dict | None = None, 117840b1e01SJuraj Linkeš ) -> CommandResult: 1186ef07151SJuraj Linkeš """An all-purpose API for OS-agnostic commands. 1196ef07151SJuraj Linkeš 1206ef07151SJuraj Linkeš This can be used for an execution of a portable command that's executed the same way 1216ef07151SJuraj Linkeš on all operating systems, such as Python. 1226ef07151SJuraj Linkeš 1236ef07151SJuraj Linkeš The :option:`--timeout` command line argument and the :envvar:`DTS_TIMEOUT` 1246ef07151SJuraj Linkeš environment variable configure the timeout of command execution. 1256ef07151SJuraj Linkeš 1266ef07151SJuraj Linkeš Args: 1276ef07151SJuraj Linkeš command: The command to execute. 1286ef07151SJuraj Linkeš timeout: Wait at most this long in seconds for `command` execution to complete. 1296ef07151SJuraj Linkeš privileged: Whether to run the command with administrative privileges. 1306ef07151SJuraj Linkeš verify: If :data:`True`, will check the exit code of the command. 1316ef07151SJuraj Linkeš env: A dictionary with environment variables to be used with the command execution. 1326ef07151SJuraj Linkeš 1336ef07151SJuraj Linkeš Raises: 1346ef07151SJuraj Linkeš RemoteCommandExecutionError: If verify is :data:`True` and the command failed. 135840b1e01SJuraj Linkeš """ 136840b1e01SJuraj Linkeš if privileged: 137840b1e01SJuraj Linkeš command = self._get_privileged_command(command) 138840b1e01SJuraj Linkeš 139840b1e01SJuraj Linkeš return self.remote_session.send_command(command, timeout, verify, env) 140840b1e01SJuraj Linkeš 1416e3cdef8SJuraj Linkeš def close(self) -> None: 1426e3cdef8SJuraj Linkeš """Close the underlying remote session.""" 1436e3cdef8SJuraj Linkeš self.remote_session.close() 1446e3cdef8SJuraj Linkeš 145840b1e01SJuraj Linkeš @staticmethod 146840b1e01SJuraj Linkeš @abstractmethod 147840b1e01SJuraj Linkeš def _get_privileged_command(command: str) -> str: 148840b1e01SJuraj Linkeš """Modify the command so that it executes with administrative privileges. 149840b1e01SJuraj Linkeš 150840b1e01SJuraj Linkeš Args: 151840b1e01SJuraj Linkeš command: The command to modify. 152840b1e01SJuraj Linkeš 153840b1e01SJuraj Linkeš Returns: 154840b1e01SJuraj Linkeš The modified command that executes with administrative privileges. 155840b1e01SJuraj Linkeš """ 156840b1e01SJuraj Linkeš 157840b1e01SJuraj Linkeš @abstractmethod 158840b1e01SJuraj Linkeš def get_remote_tmp_dir(self) -> PurePath: 1596ef07151SJuraj Linkeš """Get the path of the temporary directory of the remote OS. 1606ef07151SJuraj Linkeš 1616ef07151SJuraj Linkeš Returns: 1626ef07151SJuraj Linkeš The absolute path of the temporary directory. 163840b1e01SJuraj Linkeš """ 164840b1e01SJuraj Linkeš 165840b1e01SJuraj Linkeš @abstractmethod 166840b1e01SJuraj Linkeš def get_dpdk_build_env_vars(self, arch: Architecture) -> dict: 1676ef07151SJuraj Linkeš """Create extra environment variables needed for the target architecture. 1686ef07151SJuraj Linkeš 1696ef07151SJuraj Linkeš Different architectures may require different configuration, such as setting 32-bit CFLAGS. 1706ef07151SJuraj Linkeš 1716ef07151SJuraj Linkeš Returns: 1726ef07151SJuraj Linkeš A dictionary with keys as environment variables. 173840b1e01SJuraj Linkeš """ 174840b1e01SJuraj Linkeš 175840b1e01SJuraj Linkeš @abstractmethod 176840b1e01SJuraj Linkeš def join_remote_path(self, *args: str | PurePath) -> PurePath: 1776ef07151SJuraj Linkeš """Join path parts using the path separator that fits the remote OS. 1786ef07151SJuraj Linkeš 1796ef07151SJuraj Linkeš Args: 1806ef07151SJuraj Linkeš args: Any number of paths to join. 1816ef07151SJuraj Linkeš 1826ef07151SJuraj Linkeš Returns: 1836ef07151SJuraj Linkeš The resulting joined path. 184840b1e01SJuraj Linkeš """ 185840b1e01SJuraj Linkeš 186840b1e01SJuraj Linkeš @abstractmethod 187f9957667STomáš Ďurovec def remote_path_exists(self, remote_path: str | PurePath) -> bool: 188f9957667STomáš Ďurovec """Check whether `remote_path` exists on the remote system. 189f9957667STomáš Ďurovec 190f9957667STomáš Ďurovec Args: 191f9957667STomáš Ďurovec remote_path: The path to check. 192f9957667STomáš Ďurovec 193f9957667STomáš Ďurovec Returns: 194f9957667STomáš Ďurovec :data:`True` if the path exists, :data:`False` otherwise. 195f9957667STomáš Ďurovec """ 196f9957667STomáš Ďurovec 197f9957667STomáš Ďurovec @abstractmethod 198441c5fbfSTomáš Ďurovec def copy_from(self, source_file: str | PurePath, destination_dir: str | Path) -> None: 1996ef07151SJuraj Linkeš """Copy a file from the remote node to the local filesystem. 200840b1e01SJuraj Linkeš 2016ef07151SJuraj Linkeš Copy `source_file` from the remote node associated with this remote 202441c5fbfSTomáš Ďurovec session to `destination_dir` on the local filesystem. 203840b1e01SJuraj Linkeš 204840b1e01SJuraj Linkeš Args: 205441c5fbfSTomáš Ďurovec source_file: The file on the remote node. 206441c5fbfSTomáš Ďurovec destination_dir: The directory path on the local filesystem where the `source_file` 207441c5fbfSTomáš Ďurovec will be saved. 208840b1e01SJuraj Linkeš """ 209840b1e01SJuraj Linkeš 210840b1e01SJuraj Linkeš @abstractmethod 211441c5fbfSTomáš Ďurovec def copy_to(self, source_file: str | Path, destination_dir: str | PurePath) -> None: 2126ef07151SJuraj Linkeš """Copy a file from local filesystem to the remote node. 213840b1e01SJuraj Linkeš 214441c5fbfSTomáš Ďurovec Copy `source_file` from local filesystem to `destination_dir` 2156ef07151SJuraj Linkeš on the remote node associated with this remote session. 216840b1e01SJuraj Linkeš 217840b1e01SJuraj Linkeš Args: 218441c5fbfSTomáš Ďurovec source_file: The file on the local filesystem. 219441c5fbfSTomáš Ďurovec destination_dir: The directory path on the remote Node where the `source_file` 220441c5fbfSTomáš Ďurovec will be saved. 221840b1e01SJuraj Linkeš """ 222840b1e01SJuraj Linkeš 223840b1e01SJuraj Linkeš @abstractmethod 22480158fd4STomáš Ďurovec def copy_dir_from( 22580158fd4STomáš Ďurovec self, 22680158fd4STomáš Ďurovec source_dir: str | PurePath, 22780158fd4STomáš Ďurovec destination_dir: str | Path, 22880158fd4STomáš Ďurovec compress_format: TarCompressionFormat = TarCompressionFormat.none, 22980158fd4STomáš Ďurovec exclude: str | list[str] | None = None, 23080158fd4STomáš Ďurovec ) -> None: 23180158fd4STomáš Ďurovec """Copy a directory from the remote node to the local filesystem. 23280158fd4STomáš Ďurovec 23380158fd4STomáš Ďurovec Copy `source_dir` from the remote node associated with this remote session to 23480158fd4STomáš Ďurovec `destination_dir` on the local filesystem. The new local directory will be created 23580158fd4STomáš Ďurovec at `destination_dir` path. 23680158fd4STomáš Ďurovec 23780158fd4STomáš Ďurovec Example: 23880158fd4STomáš Ďurovec source_dir = '/remote/path/to/source' 23980158fd4STomáš Ďurovec destination_dir = '/local/path/to/destination' 24080158fd4STomáš Ďurovec compress_format = TarCompressionFormat.xz 24180158fd4STomáš Ďurovec 24280158fd4STomáš Ďurovec The method will: 24380158fd4STomáš Ďurovec 1. Create a tarball from `source_dir`, resulting in: 24480158fd4STomáš Ďurovec '/remote/path/to/source.tar.xz', 24580158fd4STomáš Ďurovec 2. Copy '/remote/path/to/source.tar.xz' to 24680158fd4STomáš Ďurovec '/local/path/to/destination/source.tar.xz', 24780158fd4STomáš Ďurovec 3. Extract the contents of the tarball, resulting in: 24880158fd4STomáš Ďurovec '/local/path/to/destination/source/', 24980158fd4STomáš Ďurovec 4. Remove the tarball after extraction 25080158fd4STomáš Ďurovec ('/local/path/to/destination/source.tar.xz'). 25180158fd4STomáš Ďurovec 25280158fd4STomáš Ďurovec Final Path Structure: 25380158fd4STomáš Ďurovec '/local/path/to/destination/source/' 25480158fd4STomáš Ďurovec 25580158fd4STomáš Ďurovec Args: 25680158fd4STomáš Ďurovec source_dir: The directory on the remote node. 25780158fd4STomáš Ďurovec destination_dir: The directory path on the local filesystem. 25880158fd4STomáš Ďurovec compress_format: The compression format to use. Defaults to no compression. 25980158fd4STomáš Ďurovec exclude: Patterns for files or directories to exclude from the tarball. 26080158fd4STomáš Ďurovec These patterns are used with `tar`'s `--exclude` option. 26180158fd4STomáš Ďurovec """ 26280158fd4STomáš Ďurovec 26380158fd4STomáš Ďurovec @abstractmethod 26480158fd4STomáš Ďurovec def copy_dir_to( 26580158fd4STomáš Ďurovec self, 26680158fd4STomáš Ďurovec source_dir: str | Path, 26780158fd4STomáš Ďurovec destination_dir: str | PurePath, 26880158fd4STomáš Ďurovec compress_format: TarCompressionFormat = TarCompressionFormat.none, 26980158fd4STomáš Ďurovec exclude: str | list[str] | None = None, 27080158fd4STomáš Ďurovec ) -> None: 27180158fd4STomáš Ďurovec """Copy a directory from the local filesystem to the remote node. 27280158fd4STomáš Ďurovec 27380158fd4STomáš Ďurovec Copy `source_dir` from the local filesystem to `destination_dir` on the remote node 27480158fd4STomáš Ďurovec associated with this remote session. The new remote directory will be created at 27580158fd4STomáš Ďurovec `destination_dir` path. 27680158fd4STomáš Ďurovec 27780158fd4STomáš Ďurovec Example: 27880158fd4STomáš Ďurovec source_dir = '/local/path/to/source' 27980158fd4STomáš Ďurovec destination_dir = '/remote/path/to/destination' 28080158fd4STomáš Ďurovec compress_format = TarCompressionFormat.xz 28180158fd4STomáš Ďurovec 28280158fd4STomáš Ďurovec The method will: 28380158fd4STomáš Ďurovec 1. Create a tarball from `source_dir`, resulting in: 28480158fd4STomáš Ďurovec '/local/path/to/source.tar.xz', 28580158fd4STomáš Ďurovec 2. Copy '/local/path/to/source.tar.xz' to 28680158fd4STomáš Ďurovec '/remote/path/to/destination/source.tar.xz', 28780158fd4STomáš Ďurovec 3. Extract the contents of the tarball, resulting in: 28880158fd4STomáš Ďurovec '/remote/path/to/destination/source/', 28980158fd4STomáš Ďurovec 4. Remove the tarball after extraction 29080158fd4STomáš Ďurovec ('/remote/path/to/destination/source.tar.xz'). 29180158fd4STomáš Ďurovec 29280158fd4STomáš Ďurovec Final Path Structure: 29380158fd4STomáš Ďurovec '/remote/path/to/destination/source/' 29480158fd4STomáš Ďurovec 29580158fd4STomáš Ďurovec Args: 29680158fd4STomáš Ďurovec source_dir: The directory on the local filesystem. 29780158fd4STomáš Ďurovec destination_dir: The directory path on the remote node. 29880158fd4STomáš Ďurovec compress_format: The compression format to use. Defaults to no compression. 29980158fd4STomáš Ďurovec exclude: Patterns for files or directories to exclude from the tarball. 30080158fd4STomáš Ďurovec These patterns are used with `fnmatch.fnmatch` to filter out files. 30180158fd4STomáš Ďurovec """ 30280158fd4STomáš Ďurovec 30380158fd4STomáš Ďurovec @abstractmethod 30480158fd4STomáš Ďurovec def remove_remote_file(self, remote_file_path: str | PurePath, force: bool = True) -> None: 30580158fd4STomáš Ďurovec """Remove remote file, by default remove forcefully. 30680158fd4STomáš Ďurovec 30780158fd4STomáš Ďurovec Args: 30880158fd4STomáš Ďurovec remote_file_path: The file path to remove. 30980158fd4STomáš Ďurovec force: If :data:`True`, ignore all warnings and try to remove at all costs. 31080158fd4STomáš Ďurovec """ 31180158fd4STomáš Ďurovec 31280158fd4STomáš Ďurovec @abstractmethod 313840b1e01SJuraj Linkeš def remove_remote_dir( 314840b1e01SJuraj Linkeš self, 315840b1e01SJuraj Linkeš remote_dir_path: str | PurePath, 316840b1e01SJuraj Linkeš recursive: bool = True, 317840b1e01SJuraj Linkeš force: bool = True, 318840b1e01SJuraj Linkeš ) -> None: 3196ef07151SJuraj Linkeš """Remove remote directory, by default remove recursively and forcefully. 3206ef07151SJuraj Linkeš 3216ef07151SJuraj Linkeš Args: 32280158fd4STomáš Ďurovec remote_dir_path: The directory path to remove. 3236ef07151SJuraj Linkeš recursive: If :data:`True`, also remove all contents inside the directory. 3246ef07151SJuraj Linkeš force: If :data:`True`, ignore all warnings and try to remove at all costs. 325840b1e01SJuraj Linkeš """ 326840b1e01SJuraj Linkeš 327840b1e01SJuraj Linkeš @abstractmethod 32880158fd4STomáš Ďurovec def create_remote_tarball( 32980158fd4STomáš Ďurovec self, 33080158fd4STomáš Ďurovec remote_dir_path: str | PurePath, 33180158fd4STomáš Ďurovec compress_format: TarCompressionFormat = TarCompressionFormat.none, 33280158fd4STomáš Ďurovec exclude: str | list[str] | None = None, 33380158fd4STomáš Ďurovec ) -> PurePosixPath: 33480158fd4STomáš Ďurovec """Create a tarball from the contents of the specified remote directory. 33580158fd4STomáš Ďurovec 33680158fd4STomáš Ďurovec This method creates a tarball containing all files and directories 33780158fd4STomáš Ďurovec within `remote_dir_path`. The tarball will be saved in the directory of 33880158fd4STomáš Ďurovec `remote_dir_path` and will be named based on `remote_dir_path`. 33980158fd4STomáš Ďurovec 34080158fd4STomáš Ďurovec Args: 34180158fd4STomáš Ďurovec remote_dir_path: The directory path on the remote node. 34280158fd4STomáš Ďurovec compress_format: The compression format to use. Defaults to no compression. 34380158fd4STomáš Ďurovec exclude: Patterns for files or directories to exclude from the tarball. 34480158fd4STomáš Ďurovec These patterns are used with `tar`'s `--exclude` option. 34580158fd4STomáš Ďurovec 34680158fd4STomáš Ďurovec Returns: 34780158fd4STomáš Ďurovec The path to the created tarball on the remote node. 34880158fd4STomáš Ďurovec """ 34980158fd4STomáš Ďurovec 35080158fd4STomáš Ďurovec @abstractmethod 351840b1e01SJuraj Linkeš def extract_remote_tarball( 352840b1e01SJuraj Linkeš self, 353840b1e01SJuraj Linkeš remote_tarball_path: str | PurePath, 354840b1e01SJuraj Linkeš expected_dir: str | PurePath | None = None, 355840b1e01SJuraj Linkeš ) -> None: 3566ef07151SJuraj Linkeš """Extract remote tarball in its remote directory. 3576ef07151SJuraj Linkeš 3586ef07151SJuraj Linkeš Args: 35980158fd4STomáš Ďurovec remote_tarball_path: The tarball path on the remote node. 3606ef07151SJuraj Linkeš expected_dir: If non-empty, check whether `expected_dir` exists after extracting 3616ef07151SJuraj Linkeš the archive. 362840b1e01SJuraj Linkeš """ 363840b1e01SJuraj Linkeš 364840b1e01SJuraj Linkeš @abstractmethod 365*b935bdc3SLuca Vizzarro def is_remote_dir(self, remote_path: PurePath) -> bool: 366f9957667STomáš Ďurovec """Check if the `remote_path` is a directory. 367f9957667STomáš Ďurovec 368f9957667STomáš Ďurovec Args: 369f9957667STomáš Ďurovec remote_tarball_path: The path to the remote tarball. 370f9957667STomáš Ďurovec 371f9957667STomáš Ďurovec Returns: 372f9957667STomáš Ďurovec If :data:`True` the `remote_path` is a directory, otherwise :data:`False`. 373f9957667STomáš Ďurovec """ 374f9957667STomáš Ďurovec 375f9957667STomáš Ďurovec @abstractmethod 376*b935bdc3SLuca Vizzarro def is_remote_tarfile(self, remote_tarball_path: PurePath) -> bool: 377f9957667STomáš Ďurovec """Check if the `remote_tarball_path` is a tar archive. 378f9957667STomáš Ďurovec 379f9957667STomáš Ďurovec Args: 380f9957667STomáš Ďurovec remote_tarball_path: The path to the remote tarball. 381f9957667STomáš Ďurovec 382f9957667STomáš Ďurovec Returns: 383f9957667STomáš Ďurovec If :data:`True` the `remote_tarball_path` is a tar archive, otherwise :data:`False`. 384f9957667STomáš Ďurovec """ 385f9957667STomáš Ďurovec 386f9957667STomáš Ďurovec @abstractmethod 387f9957667STomáš Ďurovec def get_tarball_top_dir( 388f9957667STomáš Ďurovec self, remote_tarball_path: str | PurePath 389f9957667STomáš Ďurovec ) -> str | PurePosixPath | None: 390f9957667STomáš Ďurovec """Get the top directory of the remote tarball. 391f9957667STomáš Ďurovec 392f9957667STomáš Ďurovec Examines the contents of a tarball located at the given `remote_tarball_path` and 393f9957667STomáš Ďurovec determines the top-level directory. If all files and directories in the tarball share 394f9957667STomáš Ďurovec the same top-level directory, that directory name is returned. If the tarball contains 395f9957667STomáš Ďurovec multiple top-level directories or is empty, the method return None. 396f9957667STomáš Ďurovec 397f9957667STomáš Ďurovec Args: 398f9957667STomáš Ďurovec remote_tarball_path: The path to the remote tarball. 399f9957667STomáš Ďurovec 400f9957667STomáš Ďurovec Returns: 401f9957667STomáš Ďurovec The top directory of the tarball. If there are multiple top directories 402f9957667STomáš Ďurovec or the tarball is empty, returns :data:`None`. 403f9957667STomáš Ďurovec """ 404f9957667STomáš Ďurovec 405f9957667STomáš Ďurovec @abstractmethod 406840b1e01SJuraj Linkeš def build_dpdk( 407840b1e01SJuraj Linkeš self, 408840b1e01SJuraj Linkeš env_vars: dict, 409840b1e01SJuraj Linkeš meson_args: MesonArgs, 410840b1e01SJuraj Linkeš remote_dpdk_dir: str | PurePath, 411840b1e01SJuraj Linkeš remote_dpdk_build_dir: str | PurePath, 412840b1e01SJuraj Linkeš rebuild: bool = False, 413840b1e01SJuraj Linkeš timeout: float = SETTINGS.compile_timeout, 414840b1e01SJuraj Linkeš ) -> None: 4156ef07151SJuraj Linkeš """Build DPDK on the remote node. 4166ef07151SJuraj Linkeš 4176ef07151SJuraj Linkeš An extracted DPDK tarball must be present on the node. The build consists of two steps:: 4186ef07151SJuraj Linkeš 4196ef07151SJuraj Linkeš meson setup <meson args> remote_dpdk_dir remote_dpdk_build_dir 4206ef07151SJuraj Linkeš ninja -C remote_dpdk_build_dir 4216ef07151SJuraj Linkeš 4226ef07151SJuraj Linkeš The :option:`--compile-timeout` command line argument and the :envvar:`DTS_COMPILE_TIMEOUT` 4236ef07151SJuraj Linkeš environment variable configure the timeout of DPDK build. 4246ef07151SJuraj Linkeš 4256ef07151SJuraj Linkeš Args: 4266ef07151SJuraj Linkeš env_vars: Use these environment variables when building DPDK. 4276ef07151SJuraj Linkeš meson_args: Use these meson arguments when building DPDK. 4286ef07151SJuraj Linkeš remote_dpdk_dir: The directory on the remote node where DPDK will be built. 4296ef07151SJuraj Linkeš remote_dpdk_build_dir: The target build directory on the remote node. 4306ef07151SJuraj Linkeš rebuild: If :data:`True`, do a subsequent build with ``meson configure`` instead 4316ef07151SJuraj Linkeš of ``meson setup``. 4326ef07151SJuraj Linkeš timeout: Wait at most this long in seconds for the build execution to complete. 433840b1e01SJuraj Linkeš """ 434840b1e01SJuraj Linkeš 435840b1e01SJuraj Linkeš @abstractmethod 436840b1e01SJuraj Linkeš def get_dpdk_version(self, version_path: str | PurePath) -> str: 4376ef07151SJuraj Linkeš """Inspect the DPDK version on the remote node. 4386ef07151SJuraj Linkeš 4396ef07151SJuraj Linkeš Args: 4406ef07151SJuraj Linkeš version_path: The path to the VERSION file containing the DPDK version. 4416ef07151SJuraj Linkeš 4426ef07151SJuraj Linkeš Returns: 4436ef07151SJuraj Linkeš The DPDK version. 444840b1e01SJuraj Linkeš """ 445840b1e01SJuraj Linkeš 446840b1e01SJuraj Linkeš @abstractmethod 447840b1e01SJuraj Linkeš def get_remote_cpus(self, use_first_core: bool) -> list[LogicalCore]: 4486ef07151SJuraj Linkeš r"""Get the list of :class:`~.cpu.LogicalCore`\s on the remote node. 4496ef07151SJuraj Linkeš 4506ef07151SJuraj Linkeš Args: 4516ef07151SJuraj Linkeš use_first_core: If :data:`False`, the first physical core won't be used. 4526ef07151SJuraj Linkeš 4536ef07151SJuraj Linkeš Returns: 4546ef07151SJuraj Linkeš The logical cores present on the node. 455840b1e01SJuraj Linkeš """ 456840b1e01SJuraj Linkeš 457840b1e01SJuraj Linkeš @abstractmethod 458840b1e01SJuraj Linkeš def kill_cleanup_dpdk_apps(self, dpdk_prefix_list: Iterable[str]) -> None: 4596ef07151SJuraj Linkeš """Kill and cleanup all DPDK apps. 4606ef07151SJuraj Linkeš 4616ef07151SJuraj Linkeš Args: 4626ef07151SJuraj Linkeš dpdk_prefix_list: Kill all apps identified by `dpdk_prefix_list`. 4636ef07151SJuraj Linkeš If `dpdk_prefix_list` is empty, attempt to find running DPDK apps to kill and clean. 464840b1e01SJuraj Linkeš """ 465840b1e01SJuraj Linkeš 466840b1e01SJuraj Linkeš @abstractmethod 467840b1e01SJuraj Linkeš def get_dpdk_file_prefix(self, dpdk_prefix: str) -> str: 4686ef07151SJuraj Linkeš """Make OS-specific modification to the DPDK file prefix. 4696ef07151SJuraj Linkeš 4706ef07151SJuraj Linkeš Args: 4716ef07151SJuraj Linkeš dpdk_prefix: The OS-unaware file prefix. 4726ef07151SJuraj Linkeš 4736ef07151SJuraj Linkeš Returns: 4746ef07151SJuraj Linkeš The OS-specific file prefix. 475840b1e01SJuraj Linkeš """ 476840b1e01SJuraj Linkeš 477840b1e01SJuraj Linkeš @abstractmethod 478c0dd39deSNicholas Pratte def setup_hugepages(self, number_of: int, hugepage_size: int, force_first_numa: bool) -> None: 4796ef07151SJuraj Linkeš """Configure hugepages on the node. 4806ef07151SJuraj Linkeš 4816ef07151SJuraj Linkeš Get the node's Hugepage Size, configure the specified count of hugepages 482840b1e01SJuraj Linkeš if needed and mount the hugepages if needed. 4836ef07151SJuraj Linkeš 4846ef07151SJuraj Linkeš Args: 485c0dd39deSNicholas Pratte number_of: Configure this many hugepages. 486e5307b25SNicholas Pratte hugepage_size: Configure hugepages of this size. 487c0dd39deSNicholas Pratte force_first_numa: If :data:`True`, configure just on the first numa node. 488840b1e01SJuraj Linkeš """ 489840b1e01SJuraj Linkeš 490840b1e01SJuraj Linkeš @abstractmethod 491840b1e01SJuraj Linkeš def get_compiler_version(self, compiler_name: str) -> str: 4926ef07151SJuraj Linkeš """Get installed version of compiler used for DPDK. 4936ef07151SJuraj Linkeš 4946ef07151SJuraj Linkeš Args: 4956ef07151SJuraj Linkeš compiler_name: The name of the compiler executable. 4966ef07151SJuraj Linkeš 4976ef07151SJuraj Linkeš Returns: 4986ef07151SJuraj Linkeš The compiler's version. 499840b1e01SJuraj Linkeš """ 500840b1e01SJuraj Linkeš 501840b1e01SJuraj Linkeš @abstractmethod 502c72ff85dSLuca Vizzarro def get_node_info(self) -> OSSessionInfo: 5036ef07151SJuraj Linkeš """Collect additional information about the node. 5046ef07151SJuraj Linkeš 5056ef07151SJuraj Linkeš Returns: 5066ef07151SJuraj Linkeš Node information. 507840b1e01SJuraj Linkeš """ 508840b1e01SJuraj Linkeš 509840b1e01SJuraj Linkeš @abstractmethod 510840b1e01SJuraj Linkeš def update_ports(self, ports: list[Port]) -> None: 5116ef07151SJuraj Linkeš """Get additional information about ports from the operating system and update them. 5126ef07151SJuraj Linkeš 5136ef07151SJuraj Linkeš The additional information is: 5146ef07151SJuraj Linkeš 5156ef07151SJuraj Linkeš * Logical name (e.g. ``enp7s0``) if applicable, 5166ef07151SJuraj Linkeš * Mac address. 5176ef07151SJuraj Linkeš 5186ef07151SJuraj Linkeš Args: 5196ef07151SJuraj Linkeš ports: The ports to update. 520840b1e01SJuraj Linkeš """ 521840b1e01SJuraj Linkeš 522840b1e01SJuraj Linkeš @abstractmethod 523ace78563SJeremy Spewock def configure_port_mtu(self, mtu: int, port: Port) -> None: 524ace78563SJeremy Spewock """Configure `mtu` on `port`. 525ace78563SJeremy Spewock 526ace78563SJeremy Spewock Args: 527ace78563SJeremy Spewock mtu: Desired MTU value. 528ace78563SJeremy Spewock port: Port to set `mtu` on. 529ace78563SJeremy Spewock """ 530