Skip to content

Commit 89ab698

Browse files
committed
Silence rsync pull failures for absent remote sources
1 parent f6f4215 commit 89ab698

5 files changed

Lines changed: 62 additions & 49 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Reduce Treadmill ``testplan.log`` noise: Tolerated (``check=False``) non-zero exits from remote setup commands are now logged at debug as ``(non-fatal)`` rather than as failures.

testplan/common/remote/remote_resource.py

Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@
2626
pwd,
2727
rebase_path,
2828
)
29-
from testplan.common.utils.process import (
30-
execute_cmd,
31-
)
29+
from testplan.common.utils.process import execute_cmd
3230
from testplan.common.utils.remote import (
3331
IS_WIN,
3432
copy_cmd,
@@ -734,23 +732,19 @@ def _fetch_results(self) -> None:
734732
self.logger.error(
735733
"%s not properly set up, skip fetch results stage", self
736734
)
735+
return
737736
self.logger.debug("Fetch results stage - %s", self.ssh_cfg["host"])
738-
try:
739-
self._transfer_data(
740-
source=self._remote_resource_runpath,
741-
remote_source=True,
742-
target=cast(Entity, self.parent).runpath,
743-
exclude=self.cfg.fetch_runpath_exclude,
744-
)
745-
if self.cfg.pull:
746-
self._pull_files()
747-
except Exception as exc:
748-
self._error_exec.append(exc)
749-
self.logger.warning(
750-
"While fetching result from remote resource [%s]: %s",
751-
self,
752-
exc,
753-
)
737+
# check=False: a fetch failure (e.g. a source absent on the remote) is
738+
# tolerated and logged as (non-fatal), it does not abort teardown.
739+
self._transfer_data(
740+
source=self._remote_resource_runpath,
741+
remote_source=True,
742+
target=cast(Entity, self.parent).runpath,
743+
exclude=self.cfg.fetch_runpath_exclude,
744+
check=False,
745+
)
746+
if self.cfg.pull:
747+
self._pull_files()
754748

755749
def _clean_remote(self) -> None:
756750
if self.cfg.clean_remote:
@@ -787,20 +781,13 @@ def _pull_files(self) -> None:
787781
makedirs(pull_dst)
788782

789783
for entry in self.cfg.pull:
790-
try:
791-
self._transfer_data(
792-
source=entry,
793-
remote_source=True,
794-
target=pull_dst,
795-
exclude=self.cfg.pull_exclude,
796-
)
797-
except Exception as exc:
798-
self._error_exec.append(exc)
799-
self.logger.warning(
800-
"While fetching result from remote resource [%s]: %s",
801-
self,
802-
exc,
803-
)
784+
self._transfer_data(
785+
source=entry,
786+
remote_source=True,
787+
target=pull_dst,
788+
exclude=self.cfg.pull_exclude,
789+
check=False,
790+
)
804791

805792
def _remote_sys_path(self) -> List[str]:
806793
sys_path: List[str] = [cast(str, self._testplan_import_path.remote)]
@@ -853,8 +840,9 @@ def _transfer_data(
853840
target: str,
854841
remote_source: bool = False,
855842
remote_target: bool = False,
843+
check: bool = True,
856844
**copy_args: Any,
857-
) -> None:
845+
) -> Tuple[int, Optional[str], Optional[str]]:
858846
if remote_source:
859847
source = self._remote_copy_path(source)
860848
if remote_target:
@@ -864,11 +852,12 @@ def _transfer_data(
864852
source, target, port=self.ssh_cfg["port"], **copy_args
865853
)
866854
with open(os.devnull, "w") as devnull:
867-
execute_cmd(
855+
return execute_cmd(
868856
cmd,
869857
"transfer data [..{}]".format(os.path.basename(source)),
870858
stdout=devnull, # type: ignore[arg-type]
871859
logger=self.logger,
860+
check=check,
872861
)
873862

874863
def _check_remote_os(self) -> None:

testplan/common/remote/ssh_client.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -171,18 +171,31 @@ def exec_command(
171171
stderr_str = stderr.read().decode("utf-8").strip()
172172

173173
if exit_code != 0:
174-
self.logger.warning(
175-
"Failed executing command [%s] after %.2f sec.", label, elapsed
176-
)
177-
if stdout_str:
178-
self.logger.warning("Stdout:\n%s", stdout_str)
179-
if stderr_str:
180-
self.logger.warning("Stderr:\n%s", stderr_str)
181174
if check:
175+
self.logger.warning(
176+
"Failed executing command [%s] after %.2f sec.",
177+
label,
178+
elapsed,
179+
)
180+
if stdout_str:
181+
self.logger.warning("Stdout:\n%s", stdout_str)
182+
if stderr_str:
183+
self.logger.warning("Stderr:\n%s", stderr_str)
182184
raise RuntimeError(
183185
f"Command '{cmd_string}' failed with exit code {exit_code}.\n"
184186
f"Stdout:\n{stdout_str}\nStderr:\n{stderr_str}"
185187
)
188+
# check=False => log it as non-fatal
189+
self.logger.debug(
190+
"Command [%s] returned exit code %d in %.2f sec (non-fatal)",
191+
label,
192+
exit_code,
193+
elapsed,
194+
)
195+
if stdout_str:
196+
self.logger.debug("Stdout:\n%s", stdout_str)
197+
if stderr_str:
198+
self.logger.debug("Stderr:\n%s", stderr_str)
186199
else:
187200
self.logger.debug(
188201
"Command [%s] executed successfully in %.2f sec.",

testplan/common/utils/process.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -355,10 +355,10 @@ def execute_cmd(
355355
:param stderr: Optional file-like object to redirect stderr to.
356356
:param logger: Optional logger object as logging destination.
357357
:param env: Optional dict object as environment variables.
358-
:param detailed_log: Enum to determine when stdout and stderr outputs should
359-
be logged.
358+
:param detailed_log: Enum to determine what is logged when the command runs.
360359
LOG_ALWAYS - Outputs are logged on success and failure.
361-
LOG_ON_ERROR - Outputs are logged on failure.
360+
LOG_ON_ERROR - stdout/stderr logged on failure; a non-zero exit is a
361+
failure warning when ``check`` is True, else logged plainly at debug.
362362
NEVER_LOG - Outputs are never logged.
363363
:return: Return code of the command.
364364
"""
@@ -400,12 +400,23 @@ def execute_cmd(
400400
elapsed = time.time() - start_time
401401

402402
if handler.returncode != 0:
403-
logger.warning(
404-
"Failed executing command [%s] after %.2f sec.", label, elapsed
405-
)
406403
output_s = output if output is not None else ""
407404
error_s = error if error is not None else ""
408405
if detailed_log is not LogDetailsOption.NEVER_LOG:
406+
if check:
407+
logger.warning(
408+
"Failed executing command [%s] after %.2f sec.",
409+
label,
410+
elapsed,
411+
)
412+
else:
413+
# check=False => log it as non-fatal
414+
logger.debug(
415+
"Command [%s] returned exit code %d in %.2f sec (non-fatal)",
416+
label,
417+
handler.returncode,
418+
elapsed,
419+
)
409420
_log_subprocess_output(logger, output_s, error_s)
410421
if check:
411422
raise RuntimeError(

tests/unit/testplan/common/remote/test_remote_resource.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import os
33
import shutil
44
import tempfile
5-
65
import pytest
76

87
from testplan import TestplanMock

0 commit comments

Comments
 (0)