зеркало из https://github.com/microsoft/lisa.git
support OS detection and add some tools
1. update OS to support Ubuntu and CentOS 2. add logic to detect OS. 3. support package installation 4. add gcc, make tools 5. support git, ntttcp install 6. other minor improvements
This commit is contained in:
Родитель
75ce9d66d2
Коммит
a698de989e
|
@ -37,10 +37,11 @@ class HelloWorld(TestSuite):
|
|||
|
||||
# get process output directly.
|
||||
echo = node.tools[Echo]
|
||||
result = echo.run("hello world!")
|
||||
self.log.info(f"stdout of node: '{result.stdout}'")
|
||||
self.log.info(f"stderr of node: '{result.stderr}'")
|
||||
self.log.info(f"exitCode of node: '{result.exit_code}'")
|
||||
hello_world = "hello world!"
|
||||
result = echo.run(hello_world)
|
||||
self.assertEquals(hello_world, result.stdout)
|
||||
self.assertEquals("", result.stderr)
|
||||
self.assertEqual(0, result.exit_code)
|
||||
|
||||
@TestCaseMetadata(
|
||||
description="""
|
||||
|
@ -52,7 +53,7 @@ class HelloWorld(TestSuite):
|
|||
node = self.environment.default_node
|
||||
# use it once like this way before use short cut
|
||||
node.tools[Echo]
|
||||
self.log.info(f"stdout of node: '{node.tools.echo('bye!')}'")
|
||||
self.assertEqual("bye!", str(node.tools.echo("bye!")))
|
||||
|
||||
def before_suite(self) -> None:
|
||||
self.log.info("setup my test suite")
|
||||
|
|
|
@ -16,7 +16,7 @@ from lisa.tools import Lscpu, Ntttcp
|
|||
class MutipleNodesDemo(TestSuite):
|
||||
@TestCaseMetadata(
|
||||
description="""
|
||||
this test case send and receive data by ntttcp
|
||||
This test case send and receive data by ntttcp
|
||||
""",
|
||||
priority=1,
|
||||
)
|
||||
|
@ -43,5 +43,7 @@ class MutipleNodesDemo(TestSuite):
|
|||
ntttcp_client = client_node.tools[Ntttcp]
|
||||
|
||||
server_process = ntttcp_server.run_async("-P 1 -t 5 -e")
|
||||
ntttcp_client.run(f"-s {server_node.internal_address} -P 1 -n 1 -t 5 -W 1")
|
||||
ntttcp_client.run(
|
||||
f"-s {server_node.internal_address} -P 1 -n 1 -t 5 -W 1", no_info_log=False
|
||||
)
|
||||
server_process.wait_result()
|
||||
|
|
|
@ -4,6 +4,7 @@ from lisa import TestCaseMetadata, TestSuite, TestSuiteMetadata
|
|||
from lisa.executable import CustomScript, CustomScriptBuilder
|
||||
from lisa.operating_system import Windows
|
||||
from lisa.testsuite import simple_requirement
|
||||
from lisa.util.perf_timer import create_timer
|
||||
|
||||
|
||||
@TestSuiteMetadata(
|
||||
|
@ -22,16 +23,28 @@ class WithScript(TestSuite):
|
|||
|
||||
@TestCaseMetadata(
|
||||
description="""
|
||||
this test case run script on test node.
|
||||
this test case run script on a linux node, and demostrate
|
||||
1. how to use customized script on tested node.
|
||||
1. how to use requirement to limit case excludes an os.
|
||||
2. use perf_timer to measure performance and output result.
|
||||
""",
|
||||
priority=1,
|
||||
requirement=simple_requirement(unsupported_os=[Windows]),
|
||||
)
|
||||
def script(self) -> None:
|
||||
node = self.environment.default_node
|
||||
timer1 = create_timer()
|
||||
script: CustomScript = node.tools[self._echo_script]
|
||||
result = script.run()
|
||||
self.log.info(f"result1 stdout: {result}")
|
||||
# the second time should be faster, without uploading
|
||||
result = script.run()
|
||||
self.log.info(f"result2 stdout: {result}")
|
||||
result1 = script.run()
|
||||
self.log.info(f"first run finished within {timer1}")
|
||||
timer2 = create_timer()
|
||||
result2 = script.run()
|
||||
self.assertEqual(result1.stdout, result2.stdout)
|
||||
self.assertGreater(
|
||||
timer1.elapsed(),
|
||||
timer2.elapsed(),
|
||||
"the second time should be faster, without uploading",
|
||||
)
|
||||
self.log.info(
|
||||
f"second run finished within {timer2}, total: {timer1.elapsed_text(False)}"
|
||||
)
|
||||
|
|
|
@ -84,6 +84,14 @@ class Tool(ABC, InitializableMixin):
|
|||
"""
|
||||
return None
|
||||
|
||||
@property
|
||||
def package_name(self) -> str:
|
||||
"""
|
||||
return package name,
|
||||
it may be different with command or different platform.
|
||||
"""
|
||||
return self.command
|
||||
|
||||
@classmethod
|
||||
def create(cls, node: Node) -> Tool:
|
||||
"""
|
||||
|
@ -218,7 +226,7 @@ class Tool(ABC, InitializableMixin):
|
|||
parameters: str = "",
|
||||
shell: bool = False,
|
||||
no_error_log: bool = False,
|
||||
no_info_log: bool = False,
|
||||
no_info_log: bool = True,
|
||||
cwd: Optional[pathlib.PurePath] = None,
|
||||
) -> ExecutableResult:
|
||||
return self.run(
|
||||
|
@ -445,7 +453,7 @@ class Tools:
|
|||
tool_log.debug(f"installed in {timer}")
|
||||
else:
|
||||
raise LisaException(
|
||||
"doesn't support install on "
|
||||
f"doesn't support install {tool.name} on "
|
||||
f"Node({self._node.index}), "
|
||||
f"Linux({self._node.is_linux}), "
|
||||
f"Remote({self._node.is_remote})"
|
||||
|
|
53
lisa/main.py
53
lisa/main.py
|
@ -9,6 +9,7 @@ from retry import retry # type: ignore
|
|||
from lisa.parameter_parser.argparser import parse_args
|
||||
from lisa.util import constants
|
||||
from lisa.util.logger import get_logger, set_level, set_log_file
|
||||
from lisa.util.perf_timer import create_timer
|
||||
|
||||
|
||||
@retry(FileExistsError, tries=10, delay=0) # type: ignore
|
||||
|
@ -23,37 +24,41 @@ def create_run_path(root_path: Path) -> Path:
|
|||
|
||||
|
||||
def main() -> None:
|
||||
runtime_root = Path("runtime").absolute()
|
||||
total_timer = create_timer()
|
||||
try:
|
||||
runtime_root = Path("runtime").absolute()
|
||||
|
||||
constants.CACHE_PATH = runtime_root.joinpath("cache")
|
||||
constants.CACHE_PATH.mkdir(parents=True, exist_ok=True)
|
||||
# create run root path
|
||||
runs_path = runtime_root.joinpath("runs")
|
||||
logic_path = create_run_path(runs_path)
|
||||
local_path = runs_path.joinpath(logic_path)
|
||||
local_path.mkdir(parents=True)
|
||||
constants.CACHE_PATH = runtime_root.joinpath("cache")
|
||||
constants.CACHE_PATH.mkdir(parents=True, exist_ok=True)
|
||||
# create run root path
|
||||
runs_path = runtime_root.joinpath("runs")
|
||||
logic_path = create_run_path(runs_path)
|
||||
local_path = runs_path.joinpath(logic_path)
|
||||
local_path.mkdir(parents=True)
|
||||
|
||||
constants.RUN_ID = logic_path.name
|
||||
constants.RUN_LOCAL_PATH = local_path
|
||||
constants.RUN_LOGIC_PATH = logic_path
|
||||
constants.RUN_ID = logic_path.name
|
||||
constants.RUN_LOCAL_PATH = local_path
|
||||
constants.RUN_LOGIC_PATH = logic_path
|
||||
|
||||
args = parse_args()
|
||||
args = parse_args()
|
||||
|
||||
set_log_file(f"{local_path}/lisa-host.log")
|
||||
set_log_file(f"{local_path}/lisa-host.log")
|
||||
|
||||
log = get_logger()
|
||||
log.info(f"Python version: {sys.version}")
|
||||
log.info(f"local time: {datetime.now().astimezone()}")
|
||||
log.info(f"command line args: {sys.argv}")
|
||||
log.info(f"run local path: {runtime_root}")
|
||||
log = get_logger()
|
||||
log.info(f"Python version: {sys.version}")
|
||||
log.info(f"local time: {datetime.now().astimezone()}")
|
||||
log.info(f"command line args: {sys.argv}")
|
||||
log.info(f"run local path: {runtime_root}")
|
||||
|
||||
if args.debug:
|
||||
log_level = DEBUG
|
||||
else:
|
||||
log_level = INFO
|
||||
set_level(log_level)
|
||||
if args.debug:
|
||||
log_level = DEBUG
|
||||
else:
|
||||
log_level = INFO
|
||||
set_level(log_level)
|
||||
|
||||
args.func(args)
|
||||
args.func(args)
|
||||
finally:
|
||||
log.info(f"finished in {total_timer}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
35
lisa/node.py
35
lisa/node.py
|
@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Iterable, List, Optional, TypeVar, Union, cast
|
|||
|
||||
from lisa import schema
|
||||
from lisa.executable import Tools
|
||||
from lisa.operating_system import Linux, OperatingSystem, Windows
|
||||
from lisa.operating_system import OperatingSystem
|
||||
from lisa.tools import Echo
|
||||
from lisa.util import (
|
||||
ContextMixin,
|
||||
|
@ -30,6 +30,7 @@ class Node(ContextMixin, InitializableMixin):
|
|||
capability: schema.NodeSpace,
|
||||
is_remote: bool = True,
|
||||
is_default: bool = False,
|
||||
logger_name: str = "node",
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.is_default = is_default
|
||||
|
@ -44,7 +45,7 @@ class Node(ContextMixin, InitializableMixin):
|
|||
self.working_path: pathlib.PurePath = pathlib.PurePath()
|
||||
|
||||
self._connection_info: Optional[ConnectionInfo] = None
|
||||
self.log = get_logger("node", str(self.index))
|
||||
self.log = get_logger(logger_name, str(self.index))
|
||||
|
||||
@staticmethod
|
||||
def create(
|
||||
|
@ -52,6 +53,7 @@ class Node(ContextMixin, InitializableMixin):
|
|||
capability: schema.NodeSpace,
|
||||
node_type: str = constants.ENVIRONMENTS_NODES_REMOTE,
|
||||
is_default: bool = False,
|
||||
logger_name: str = "node",
|
||||
) -> Node:
|
||||
if node_type == constants.ENVIRONMENTS_NODES_REMOTE:
|
||||
is_remote = True
|
||||
|
@ -60,7 +62,11 @@ class Node(ContextMixin, InitializableMixin):
|
|||
else:
|
||||
raise LisaException(f"unsupported node_type '{node_type}'")
|
||||
node = Node(
|
||||
index, capability=capability, is_remote=is_remote, is_default=is_default
|
||||
index,
|
||||
capability=capability,
|
||||
is_remote=is_remote,
|
||||
is_default=is_default,
|
||||
logger_name=logger_name,
|
||||
)
|
||||
node.log.debug(f"created, type: '{node_type}', isDefault: {is_default}")
|
||||
return node
|
||||
|
@ -92,7 +98,7 @@ class Node(ContextMixin, InitializableMixin):
|
|||
cmd: str,
|
||||
shell: bool = False,
|
||||
no_error_log: bool = False,
|
||||
no_info_log: bool = False,
|
||||
no_info_log: bool = True,
|
||||
cwd: Optional[pathlib.PurePath] = None,
|
||||
) -> ExecutableResult:
|
||||
process = self.execute_async(
|
||||
|
@ -109,7 +115,7 @@ class Node(ContextMixin, InitializableMixin):
|
|||
cmd: str,
|
||||
shell: bool = False,
|
||||
no_error_log: bool = False,
|
||||
no_info_log: bool = False,
|
||||
no_info_log: bool = True,
|
||||
cwd: Optional[pathlib.PurePath] = None,
|
||||
) -> Process:
|
||||
self.initialize()
|
||||
|
@ -132,10 +138,7 @@ class Node(ContextMixin, InitializableMixin):
|
|||
def _initialize(self) -> None:
|
||||
self.log.debug(f"initializing node {self.name}")
|
||||
self.shell.initialize()
|
||||
if self.shell.is_linux:
|
||||
self.os: OperatingSystem = Linux(self)
|
||||
else:
|
||||
self.os = Windows(self)
|
||||
self.os: OperatingSystem = OperatingSystem.create(self)
|
||||
|
||||
# set working path
|
||||
if self.is_remote:
|
||||
|
@ -175,9 +178,7 @@ class Node(ContextMixin, InitializableMixin):
|
|||
cwd: Optional[pathlib.PurePath] = None,
|
||||
) -> Process:
|
||||
cmd_id = str(random.randint(0, 10000))
|
||||
process = Process(
|
||||
cmd_id, self.shell, parent_logger=self.log, is_linux=self.is_linux
|
||||
)
|
||||
process = Process(cmd_id, self.shell, parent_logger=self.log)
|
||||
process.start(
|
||||
cmd,
|
||||
shell=shell,
|
||||
|
@ -257,7 +258,9 @@ class Nodes(NodesDict):
|
|||
for node in self._list:
|
||||
node.close()
|
||||
|
||||
def from_local(self, node_runbook: schema.LocalNode) -> Node:
|
||||
def from_local(
|
||||
self, node_runbook: schema.LocalNode, logger_name: str = "node",
|
||||
) -> Node:
|
||||
assert isinstance(
|
||||
node_runbook, schema.LocalNode
|
||||
), f"actual: {type(node_runbook)}"
|
||||
|
@ -266,12 +269,15 @@ class Nodes(NodesDict):
|
|||
capability=node_runbook.capability,
|
||||
node_type=node_runbook.type,
|
||||
is_default=node_runbook.is_default,
|
||||
logger_name=logger_name,
|
||||
)
|
||||
self._list.append(node)
|
||||
|
||||
return node
|
||||
|
||||
def from_remote(self, node_runbook: schema.RemoteNode) -> Optional[Node]:
|
||||
def from_remote(
|
||||
self, node_runbook: schema.RemoteNode, logger_name: str = "node",
|
||||
) -> Optional[Node]:
|
||||
assert isinstance(
|
||||
node_runbook, schema.RemoteNode
|
||||
), f"actual: {type(node_runbook)}"
|
||||
|
@ -281,6 +287,7 @@ class Nodes(NodesDict):
|
|||
capability=node_runbook.capability,
|
||||
node_type=node_runbook.type,
|
||||
is_default=node_runbook.is_default,
|
||||
logger_name=logger_name,
|
||||
)
|
||||
self._list.append(node)
|
||||
|
||||
|
|
|
@ -1,14 +1,54 @@
|
|||
from typing import TYPE_CHECKING, Any
|
||||
import re
|
||||
from functools import partial
|
||||
from typing import TYPE_CHECKING, Any, List, Optional, Type, Union
|
||||
|
||||
from lisa.executable import Tool
|
||||
from lisa.util import LisaException
|
||||
from lisa.util.logger import get_logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from lisa.node import Node
|
||||
|
||||
_get_init_logger = partial(get_logger, name="os")
|
||||
|
||||
|
||||
class OperatingSystem:
|
||||
__lsb_release_pattern = re.compile(r"^Description:[ \t]+([\w]+)[ ]+")
|
||||
__os_release_pattern = re.compile(r"^NAME=\"?([\w]+)[^\" ]*\"?", re.M)
|
||||
|
||||
def __init__(self, node: Any, is_linux: bool) -> None:
|
||||
super().__init__()
|
||||
self._node: Node = node
|
||||
self._is_linux = is_linux
|
||||
self._log = get_logger(name="os", parent=self._node.log)
|
||||
|
||||
@classmethod
|
||||
def create(cls, node: Any) -> Any:
|
||||
typed_node: Node = node
|
||||
log = _get_init_logger(parent=typed_node.log)
|
||||
result: Optional[OperatingSystem] = None
|
||||
if typed_node.shell.is_linux:
|
||||
lsb_output = typed_node.execute("lsb_release -d")
|
||||
if lsb_output.stdout:
|
||||
os_info = cls.__lsb_release_pattern.findall(lsb_output.stdout)
|
||||
if os_info and os_info[0] == "Ubuntu":
|
||||
result = Ubuntu(typed_node)
|
||||
if not result:
|
||||
os_release_output = typed_node.execute("cat /etc/os-release")
|
||||
if os_release_output.stdout:
|
||||
os_info = cls.__os_release_pattern.findall(os_release_output.stdout)
|
||||
if os_info and os_info[0] == "CentOS":
|
||||
result = CentOs(typed_node)
|
||||
if not result:
|
||||
raise LisaException(
|
||||
f"unknown linux distro {lsb_output.stdout}\n"
|
||||
f" {os_release_output.stdout}\n"
|
||||
f"support it in operating_system"
|
||||
)
|
||||
else:
|
||||
result = Windows(typed_node)
|
||||
log.debug(f"detected OS: {result.__class__.__name__}")
|
||||
return result
|
||||
|
||||
@property
|
||||
def is_windows(self) -> bool:
|
||||
|
@ -27,3 +67,59 @@ class Windows(OperatingSystem):
|
|||
class Linux(OperatingSystem):
|
||||
def __init__(self, node: Any) -> None:
|
||||
super().__init__(node, is_linux=True)
|
||||
|
||||
def _install_packages(self, packages: Union[List[str]]) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
def install_packages(
|
||||
self, packages: Union[str, Tool, Type[Tool], List[Union[str, Tool, Type[Tool]]]]
|
||||
) -> None:
|
||||
package_names: List[str] = []
|
||||
if not isinstance(packages, list):
|
||||
packages = [packages]
|
||||
|
||||
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 trigger install.
|
||||
# So they can be installed together.
|
||||
tool = item.create(self._node)
|
||||
package_names.append(tool.package_name)
|
||||
self._install_packages(package_names)
|
||||
|
||||
|
||||
class Ubuntu(Linux):
|
||||
def __init__(self, node: Any) -> None:
|
||||
super().__init__(node)
|
||||
self._first_time: bool = True
|
||||
|
||||
def _install_packages(self, packages: Union[List[str]]) -> None:
|
||||
if self._first_time:
|
||||
self._first_time = False
|
||||
self._node.execute("sudo apt-get update")
|
||||
|
||||
command = (
|
||||
f"sudo DEBIAN_FRONTEND=noninteractive "
|
||||
f"apt-get -y install {' '.join(packages)}"
|
||||
)
|
||||
self._node.execute(command)
|
||||
|
||||
|
||||
class CentOs(Linux):
|
||||
def __init__(self, node: Any) -> None:
|
||||
super().__init__(node)
|
||||
self._first_time: bool = True
|
||||
|
||||
def _install_packages(self, packages: Union[List[str]]) -> None:
|
||||
if self._first_time:
|
||||
self._first_time = False
|
||||
self._node.execute("sudo yum update")
|
||||
|
||||
self._node.execute(
|
||||
f"sudo DEBIAN_FRONTEND=noninteractive yum install -y {' '.join(packages)}"
|
||||
)
|
||||
|
|
|
@ -171,9 +171,9 @@ class LISARunner(Action):
|
|||
result_count_dict[result.status] = result_count
|
||||
|
||||
self._log.info("result summary")
|
||||
self._log.info(f" TOTAL\t: {len(selected_case_results)}")
|
||||
self._log.info(f" TOTAL : {len(selected_case_results)}")
|
||||
for key in TestStatus:
|
||||
self._log.info(f" {key.name}\t: {result_count_dict.get(key, 0)}")
|
||||
self._log.info(f" {key.name:<9}: {result_count_dict.get(key, 0)}")
|
||||
|
||||
# delete enviroment after run
|
||||
self.set_status(ActionStatus.SUCCESS)
|
||||
|
|
|
@ -220,13 +220,14 @@ class TestCaseRuntimeData:
|
|||
return cloned
|
||||
|
||||
|
||||
class TestSuite(Action, unittest.TestCase, metaclass=ABCMeta):
|
||||
class TestSuite(unittest.TestCase, Action, metaclass=ABCMeta):
|
||||
def __init__(
|
||||
self,
|
||||
environment: Environment,
|
||||
case_results: List[TestResult],
|
||||
metadata: TestSuiteMetadata,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.environment = environment
|
||||
# test cases to run, must be a test method in this class.
|
||||
self.case_results = case_results
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
from .echo import Echo
|
||||
from .gcc import Gcc
|
||||
from .git import Git
|
||||
from .lscpu import Lscpu
|
||||
from .make import Make
|
||||
from .ntttcp import Ntttcp
|
||||
from .uname import Uname
|
||||
|
||||
__all__ = ["Echo", "Git", "Lscpu", "Ntttcp", "Uname"]
|
||||
__all__ = ["Echo", "Gcc", "Git", "Lscpu", "Make", "Ntttcp", "Uname"]
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
from typing import cast
|
||||
|
||||
from lisa.executable import Tool
|
||||
from lisa.operating_system import Linux
|
||||
|
||||
|
||||
class Gcc(Tool):
|
||||
@property
|
||||
def command(self) -> str:
|
||||
return "gcc"
|
||||
|
||||
@property
|
||||
def can_install(self) -> bool:
|
||||
return True
|
||||
|
||||
def _install(self) -> bool:
|
||||
linux_os: Linux = cast(Linux, self.node.os)
|
||||
linux_os.install_packages("gcc")
|
||||
return self._check_exists()
|
|
@ -1,6 +1,8 @@
|
|||
import pathlib
|
||||
from typing import cast
|
||||
|
||||
from lisa.executable import Tool
|
||||
from lisa.operating_system import Linux
|
||||
|
||||
|
||||
class Git(Tool):
|
||||
|
@ -10,8 +12,12 @@ class Git(Tool):
|
|||
|
||||
@property
|
||||
def can_install(self) -> bool:
|
||||
# TODO support installation later
|
||||
return False
|
||||
return True
|
||||
|
||||
def _install(self) -> bool:
|
||||
linux_os: Linux = cast(Linux, self.node.os)
|
||||
linux_os.install_packages([self])
|
||||
return self._check_exists()
|
||||
|
||||
def clone(self, url: str, cwd: pathlib.PurePath) -> None:
|
||||
# git print to stderr for normal info, so set no_error_log to True.
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
from pathlib import PurePath
|
||||
from typing import cast
|
||||
|
||||
from lisa.executable import Tool
|
||||
from lisa.operating_system import Linux
|
||||
from lisa.tools import Gcc
|
||||
|
||||
|
||||
class Make(Tool):
|
||||
repo = "https://github.com/microsoft/ntttcp-for-linux"
|
||||
|
||||
@property
|
||||
def command(self) -> str:
|
||||
return "make"
|
||||
|
||||
@property
|
||||
def can_install(self) -> bool:
|
||||
return True
|
||||
|
||||
def _install(self) -> bool:
|
||||
linux_os: Linux = cast(Linux, self.node.os)
|
||||
linux_os.install_packages([self, Gcc])
|
||||
return self._check_exists()
|
||||
|
||||
def make_and_install(self, cwd: PurePath) -> None:
|
||||
self.run("&& sudo make install", shell=True, cwd=cwd)
|
|
@ -1,7 +1,7 @@
|
|||
from typing import List, Type
|
||||
|
||||
from lisa.executable import Tool
|
||||
from lisa.tools import Git
|
||||
from lisa.tools import Git, Make
|
||||
from lisa.util.process import ExecutableResult
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@ class Ntttcp(Tool):
|
|||
|
||||
@property
|
||||
def dependencies(self) -> List[Type[Tool]]:
|
||||
return [Git]
|
||||
return [Git, Make]
|
||||
|
||||
@property
|
||||
def command(self) -> str:
|
||||
|
@ -25,8 +25,9 @@ class Ntttcp(Tool):
|
|||
self.node.shell.mkdir(tool_path, exist_ok=True)
|
||||
git = self.node.tools[Git]
|
||||
git.clone(self.repo, tool_path)
|
||||
make = self.node.tools[Make]
|
||||
code_path = tool_path.joinpath("ntttcp-for-linux/src")
|
||||
self.node.execute("make && sudo make install", shell=True, cwd=code_path)
|
||||
make.make_and_install(cwd=code_path)
|
||||
return self._check_exists()
|
||||
|
||||
def help(self) -> ExecutableResult:
|
||||
|
|
|
@ -95,7 +95,7 @@ class LogWriter(object):
|
|||
|
||||
def flush(self) -> None:
|
||||
if len(self._buffer) > 0:
|
||||
self._log.log(self._level, self._buffer.strip("\r\n"))
|
||||
self._log.lines(self._level, self._buffer.strip("\r\n"))
|
||||
self._buffer = ""
|
||||
|
||||
def close(self) -> None:
|
||||
|
|
|
@ -18,8 +18,11 @@ class Timer:
|
|||
self._elapsed = timer() - self.start
|
||||
return self._elapsed
|
||||
|
||||
def elapsed_text(self, stop: bool = True) -> str:
|
||||
return f"{self.elapsed(stop):.3f} sec"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.elapsed():.3f} sec"
|
||||
return f"{self.elapsed_text()}"
|
||||
|
||||
|
||||
def create_timer() -> Timer:
|
||||
|
|
|
@ -30,16 +30,12 @@ class ExecutableResult:
|
|||
|
||||
class Process:
|
||||
def __init__(
|
||||
self,
|
||||
id_: str,
|
||||
shell: Shell,
|
||||
parent_logger: Optional[Logger] = None,
|
||||
is_linux: bool = True,
|
||||
self, id_: str, shell: Shell, parent_logger: Optional[Logger] = None,
|
||||
) -> None:
|
||||
# the shell can be LocalShell or SshShell
|
||||
self._shell = shell
|
||||
self._id_ = id_
|
||||
self._is_linux = is_linux
|
||||
self._is_linux = shell.is_linux
|
||||
self._running: bool = False
|
||||
self._log = get_logger("cmd", id_, parent=parent_logger)
|
||||
|
||||
|
|
|
@ -121,6 +121,7 @@ class SshShell(InitializableMixin):
|
|||
except Exception as identifier:
|
||||
raise LisaException(f"connect to server failed: {identifier}")
|
||||
_, stdout, _ = paramiko_client.exec_command("cmd")
|
||||
paramiko_client.close()
|
||||
|
||||
spur_kwargs = {
|
||||
"hostname": self._connection_info.address,
|
||||
|
|
Загрузка…
Ссылка в новой задаче