[#137] Ability to control remote processes id and reports for load
Signed-off-by: Andrey Berezin <a.berezin@yadro.com>
This commit is contained in:
parent
e65fc359fe
commit
81dfc723da
5 changed files with 159 additions and 63 deletions
|
@ -15,21 +15,33 @@ from frostfs_testlib.shell.interfaces import CommandInspector, CommandOptions
|
|||
|
||||
|
||||
class RemoteProcess:
|
||||
def __init__(self, cmd: str, process_dir: str, shell: Shell, cmd_inspector: Optional[CommandInspector]):
|
||||
def __init__(
|
||||
self, cmd: str, process_dir: str, shell: Shell, cmd_inspector: Optional[CommandInspector], proc_id: str
|
||||
):
|
||||
self.process_dir = process_dir
|
||||
self.cmd = cmd
|
||||
self.stdout_last_line_number = 0
|
||||
self.stderr_last_line_number = 0
|
||||
self.pid: Optional[str] = None
|
||||
self.proc_rc: Optional[int] = None
|
||||
self.proc_start_time: Optional[int] = None
|
||||
self.proc_end_time: Optional[int] = None
|
||||
self.saved_stdout: Optional[str] = None
|
||||
self.saved_stderr: Optional[str] = None
|
||||
self.shell = shell
|
||||
self.proc_id: str = proc_id
|
||||
self.cmd_inspectors: list[CommandInspector] = [cmd_inspector] if cmd_inspector else []
|
||||
|
||||
@classmethod
|
||||
@reporter.step("Create remote process")
|
||||
def create(cls, command: str, shell: Shell, working_dir: str = "/tmp", user: Optional[str] = None) -> RemoteProcess:
|
||||
def create(
|
||||
cls,
|
||||
command: str,
|
||||
shell: Shell,
|
||||
working_dir: str = "/tmp",
|
||||
user: Optional[str] = None,
|
||||
proc_id: Optional[str] = None,
|
||||
) -> RemoteProcess:
|
||||
"""
|
||||
Create a process on a remote host.
|
||||
|
||||
|
@ -40,6 +52,7 @@ class RemoteProcess:
|
|||
stderr: contains script errors
|
||||
stdout: contains script output
|
||||
user: user on behalf whom command will be executed
|
||||
proc_id: process string identificator
|
||||
|
||||
Args:
|
||||
shell: Shell instance
|
||||
|
@ -49,19 +62,31 @@ class RemoteProcess:
|
|||
Returns:
|
||||
RemoteProcess instance for further examination
|
||||
"""
|
||||
if proc_id is None:
|
||||
proc_id = f"{uuid.uuid4()}"
|
||||
|
||||
cmd_inspector = SuInspector(user) if user else None
|
||||
remote_process = cls(
|
||||
cmd=command,
|
||||
process_dir=os.path.join(working_dir, f"proc_{uuid.uuid4()}"),
|
||||
process_dir=os.path.join(working_dir, f"proc_{proc_id}"),
|
||||
shell=shell,
|
||||
cmd_inspector=cmd_inspector,
|
||||
proc_id=proc_id,
|
||||
)
|
||||
remote_process._create_process_dir()
|
||||
remote_process._generate_command_script(command)
|
||||
remote_process._start_process()
|
||||
remote_process.pid = remote_process._get_pid()
|
||||
|
||||
return remote_process
|
||||
|
||||
@reporter.step("Start remote process")
|
||||
def start(self):
|
||||
"""
|
||||
Starts a process on a remote host.
|
||||
"""
|
||||
|
||||
self._create_process_dir()
|
||||
self._generate_command_script()
|
||||
self._start_process()
|
||||
self.pid = self._get_pid()
|
||||
|
||||
@reporter.step("Get process stdout")
|
||||
def stdout(self, full: bool = False) -> str:
|
||||
"""
|
||||
|
@ -130,17 +155,48 @@ class RemoteProcess:
|
|||
if self.proc_rc is not None:
|
||||
return self.proc_rc
|
||||
|
||||
result = self._cat_proc_file("rc")
|
||||
if not result:
|
||||
return None
|
||||
|
||||
self.proc_rc = int(result)
|
||||
return self.proc_rc
|
||||
|
||||
@reporter.step("Get process start time")
|
||||
def start_time(self) -> Optional[int]:
|
||||
if self.proc_start_time is not None:
|
||||
return self.proc_start_time
|
||||
|
||||
result = self._cat_proc_file("start_time")
|
||||
if not result:
|
||||
return None
|
||||
|
||||
self.proc_start_time = int(result)
|
||||
return self.proc_start_time
|
||||
|
||||
@reporter.step("Get process end time")
|
||||
def end_time(self) -> Optional[int]:
|
||||
if self.proc_end_time is not None:
|
||||
return self.proc_end_time
|
||||
|
||||
result = self._cat_proc_file("end_time")
|
||||
if not result:
|
||||
return None
|
||||
|
||||
self.proc_end_time = int(result)
|
||||
return self.proc_end_time
|
||||
|
||||
def _cat_proc_file(self, file: str) -> Optional[str]:
|
||||
terminal = self.shell.exec(
|
||||
f"cat {self.process_dir}/rc",
|
||||
f"cat {self.process_dir}/{file}",
|
||||
CommandOptions(check=False, extra_inspectors=self.cmd_inspectors, no_log=True),
|
||||
)
|
||||
if "No such file or directory" in terminal.stderr:
|
||||
return None
|
||||
elif terminal.stderr or terminal.return_code != 0:
|
||||
raise AssertionError(f"cat process rc was not successful: {terminal.stderr}")
|
||||
raise AssertionError(f"cat process {file} was not successful: {terminal.stderr}")
|
||||
|
||||
self.proc_rc = int(terminal.stdout)
|
||||
return self.proc_rc
|
||||
return terminal.stdout
|
||||
|
||||
@reporter.step("Check if process is running")
|
||||
def running(self) -> bool:
|
||||
|
@ -195,17 +251,19 @@ class RemoteProcess:
|
|||
return terminal.stdout.strip()
|
||||
|
||||
@reporter.step("Generate command script")
|
||||
def _generate_command_script(self, command: str) -> None:
|
||||
command = command.replace('"', '\\"').replace("\\", "\\\\")
|
||||
def _generate_command_script(self) -> None:
|
||||
command = self.cmd.replace('"', '\\"').replace("\\", "\\\\")
|
||||
script = (
|
||||
f"#!/bin/bash\n"
|
||||
f"cd {self.process_dir}\n"
|
||||
f"date +%s > {self.process_dir}/start_time\n"
|
||||
f"{command} &\n"
|
||||
f"pid=\$!\n"
|
||||
f"cd {self.process_dir}\n"
|
||||
f"echo \$pid > {self.process_dir}/pid\n"
|
||||
f"wait \$pid\n"
|
||||
f"echo $? > {self.process_dir}/rc"
|
||||
f"echo $? > {self.process_dir}/rc\n"
|
||||
f"date +%s > {self.process_dir}/end_time\n"
|
||||
)
|
||||
|
||||
self.shell.exec(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue