Skip to content

Commit 9cfcccd

Browse files
wxtimMetRonnie
andauthored
attempt to handle rose rsync can_pull errors better (#2892)
* attempt to handle rose rsync can_pull errors better * handle no file error with useful error message * Improved comments Co-authored-by: Ronnie Dutta <[email protected]>
1 parent 6ae075b commit 9cfcccd

File tree

5 files changed

+86
-3
lines changed

5 files changed

+86
-3
lines changed

changes.d/2892.fix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Give the user more information about rsync file handler failure.

metomi/rose/config_processors/fileinstall.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -891,12 +891,15 @@ def parse(self, loc, conf_tree):
891891
if handler is None:
892892
raise ValueError(f"don't support scheme {loc.scheme}")
893893
else:
894-
# Scheme not specified in the configuration.
894+
# Try to get the scheme by parsing loc name, e.g. git:some-url
895895
scheme = urlparse(loc.name).scheme
896896
if scheme:
897897
handler = self.get_handler(scheme)
898898
if handler is None:
899+
# Try to guess the scheme using the ``can_handle`` method
900+
# from each handler in turn:
899901
handler = self.guess_handler(loc)
902+
900903
if handler is None:
901904
raise ValueError(f"don't know how to process {loc.name}")
902905
else:

metomi/rose/loc_handlers/rsync.py

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
# -----------------------------------------------------------------------------
1717
"""A handler of locations on remote hosts."""
1818

19+
from io import TextIOWrapper
20+
from textwrap import indent
1921
from time import sleep, time
2022

2123
from metomi.rose.loc_handlers.rsync_remote_check import (
@@ -24,6 +26,73 @@
2426
from metomi.rose.popen import RosePopenError
2527

2628

29+
class PreRsyncCheckError(Exception):
30+
"""Error to raise if we:
31+
* Can't work out which loc handler to use.
32+
* Fall back to assuming that the loc is for use with rsync.
33+
* Attempting to use it as an rsync loc fails.
34+
35+
"""
36+
37+
BASE_MESSAGE = (
38+
'Rose tried all other file install handlers and'
39+
' decided this must be an Rsync handler.\n\t'
40+
)
41+
42+
def __init__(self, dict_, cmd=None, loc=None):
43+
for key, value in dict_.items():
44+
if isinstance(value, TextIOWrapper):
45+
setattr(self, key, value.read())
46+
else:
47+
setattr(self, key, value)
48+
49+
# Convert command into something the debugger can try:
50+
try:
51+
self.cmd = ' '.join(cmd)
52+
except TypeError:
53+
self.cmd = cmd
54+
55+
# Handle ``test -e nonexistant`` where no useful error is
56+
# provided:
57+
message = ''
58+
for used_by in loc.used_by_names:
59+
message += (
60+
f'file:{used_by}={loc.action_key}={loc.name}'
61+
': don\'t know how to process this file location.\n'
62+
)
63+
if (
64+
self.returncode == 1
65+
and self.stderr == ''
66+
and self.stdout == ''
67+
):
68+
self.stderr = f'File "{cmd[-1]}" does not exist.'
69+
70+
if self.returncode == 255:
71+
host = dict_['args'][dict_['args'].index('-n') + 1]
72+
self.mod_msg = (
73+
message
74+
+ self.BASE_MESSAGE
75+
+ 'If it is then host'
76+
f' "{host}"'
77+
' is uncontactable (ssh 255 error).'
78+
)
79+
else:
80+
self.mod_msg = (
81+
message
82+
+ self.BASE_MESSAGE
83+
+ f'`{self.cmd}` failed with:'
84+
+ indent(
85+
f'\nreturncode: {self.returncode}'
86+
f'\nstdout: {self.stdout}'
87+
f'\nstderr: {self.stderr}',
88+
prefix=' ',
89+
)
90+
)
91+
92+
def __str__(self):
93+
return self.mod_msg
94+
95+
2796
class RsyncLocHandler:
2897
"""Handler of locations on remote hosts."""
2998

@@ -53,7 +122,10 @@ def can_pull(self, loc):
53122
except RosePopenError:
54123
return False
55124
else:
56-
return proc.wait() == 0
125+
if proc.wait() == 0:
126+
return True
127+
else:
128+
raise PreRsyncCheckError(proc.__dict__, cmd=cmd, loc=loc)
57129

58130
def parse(self, loc, _):
59131
"""Set loc.scheme, loc.loc_type, loc.paths."""

metomi/rose/scheme_handler.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ def __init__(
9797
if handler is None:
9898
handler = class_(*args, **kwargs)
9999
self.handlers[scheme] = handler
100+
101+
if 'rsync' in self.handlers:
102+
# rsync handler should always be at the end of the list:
103+
self.handlers['rsync'] = self.handlers.pop('rsync')
104+
100105
finally:
101106
os.chdir(cwd)
102107
sys.path.pop(0)

t/rose-app-run/05-file.t

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ run_fail "$TEST_KEY" rose app-run --config=../config -q \
7070
--define='[file:hello4]source=stuff:ing'
7171
file_cmp "$TEST_KEY.out" "$TEST_KEY.out" </dev/null
7272
file_cmp "$TEST_KEY.err" "$TEST_KEY.err" <<'__CONTENT__'
73-
[FAIL] file:hello4=source=stuff:ing: don't know how to process stuff:ing
73+
[FAIL] file:hello4=source=stuff:ing: don't know how to process this file location.
74+
[FAIL] Rose tried all other file install handlers and decided this must be an Rsync handler.
75+
[FAIL] If it is then host "stuff" is uncontactable (ssh 255 error).
7476
__CONTENT__
7577
test_teardown
7678
#-------------------------------------------------------------------------------

0 commit comments

Comments
 (0)