Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rsync client for remote copy operations #144

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

pevogam
Copy link
Contributor

@pevogam pevogam commented Feb 26, 2025

This commit adds support for a new rsync client for remote copy operations which is especially important now that the SCP protocol is being deprecated.

@pevogam pevogam force-pushed the remote-copy-rsync branch 4 times, most recently from 3f905fb to 72d71d4 Compare February 28, 2025 09:55
command = f"{command} -r"
command += (f" -avz -e 'ssh -p {port} -o UserKnownHostsFile=/dev/null "
f"-o StrictHostKeyChecking=no' {limit} "
f"{username}@{host}:{quote_path(remote_path)} {shlex.quote(local_path)}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is common to all three methods. How about splitting it into common part and then remote definition and share the common code that way?

I mean something like:

def rsync_from_remote(...):
    command = _get_rsync_cmd(...)
    command += _get_rsync_host(...)
    command += "{shlex.quote(local_path)}"

def rsync_between_remotes(...):
    command = _get_rsync_cmd(...)
    command += _get_rsync_host(...)
    command += _get_rsync_host(...)

note it's not a strong request, I just think the less code one writes the easier is it to maintain it....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future we might end up dropping scp entirely and just leaving rsync rendering such refactoring futile at present so I would keep the changes as additive as possible right now. Let's see after some more use of the remote module if it would make more sense to rather simplify it and maximize reusability.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that seems reasonable

@@ -140,25 +140,29 @@ class SCPError(TransferError):
"""Remote error related to transfer using SCP."""


class SCPAuthenticationError(SCPError):
class RsyncError(TransferError):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is user-facing change as people might be relying on those. How about adding the generic exceptions and inherit the SCP ones out of them to keep compatibility for scp group of commands?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried this first (separate rsync and scp hierarchies derived from the same base exceptions) but a lot of the refactored code which is nearly identical would have to be split into multiple versions for the only reason of raising a different exception type without much additional meaning (e.g. structure of the exception). So I ended up opting for using a simpler set of exceptions just like the "copy" instead of "SCP or rsync" in the above logging message.

Copy link
Contributor Author

@pevogam pevogam Mar 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the point rather in the rafactoring and not as much in breaking changes. As you correctly observe above though, we could also break but improve the argument order regarding the directory (recursive copy) value, so let's do that too to at least make all of this somewhat nicer.

Copy link
Contributor

@ldoktor ldoktor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello Plamen, I provided some suggestions but there is no real blocker. The renamed exceptions might bring some difficulties to users, but I'm not sure how many rely on this so I leave it on your consideration. The same with the argument order as even the scp methods exhaust all the system arguments before the directory one so it is consistent as is (while not that user-friendly :D).

All in all, let me know what do you think about the exceptions and if you say it's fine I'm ready to merge it as is. But don't say nobody warned you then ;-)

@pevogam pevogam force-pushed the remote-copy-rsync branch from 72d71d4 to 1b0bbf3 Compare March 3, 2025 16:09
This commit adds support for a new rsync client for remote copy
operations which is especially important now that the SCP protocol
is being deprecated.

Signed-off-by: Plamen Dimitrov <[email protected]>
@pevogam pevogam force-pushed the remote-copy-rsync branch 2 times, most recently from b764f30 to 57230e1 Compare March 3, 2025 16:14
@pevogam
Copy link
Contributor Author

pevogam commented Mar 3, 2025

Hi @ldoktor let's see how many people will rather thell me they warned me about changing the order of the directory argument which I did in a separate commit (as it is not directly related to the rsync extention). Other than that I hope I have addressed most if not all of your comments.

The directory argument in copy operations is a lot more important
than most of the arguments before it and seems was historically
added last. Despite this being a breaking change it will make the
functions a lot more readable for the future so we decided to go
on with it.

Signed-off-by: Plamen Dimitrov <[email protected]>
@pevogam pevogam force-pushed the remote-copy-rsync branch from 57230e1 to a06bcb2 Compare March 4, 2025 08:55
)
self.assertEqual(
mock_remote_copy.call_args[0][0].command,
r"rsync -r -avz -e 'ssh -p 22 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' src_user@src_host:/src/path dst_user@dst_host:/dst/path"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

>>> remote.rsync_between_remotes("127.0.0.1", "localhost", 22, "", "", "medic", "medic", "/tmp/a", "/tmp/b")
Traceback (most recent call last):
  File "/home/medic/Work/Projekty/avocado/aexpect/aexpect/remote.py", line 520, in _remote_copy
    match, text = session.read_until_last_line_matches(
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/medic/Work/Projekty/avocado/aexpect/aexpect/client.py", line 1002, in read_until_last_line_matches
    return self.read_until_output_matches(patterns,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/medic/Work/Projekty/avocado/aexpect/aexpect/client.py", line 940, in read_until_output_matches
    raise ExpectProcessTerminatedError(patterns, self.get_status(),
aexpect.exceptions.ExpectProcessTerminatedError: Process terminated while looking for patterns ['[Aa]re you sure', '[Pp]assword:\\s*$', 'lost connection']    (status: 1,    output: 'The source and destination cannot both be remote.\nrsync error: syntax or usage error (code 1) at main.c(1415) [Receiver=3.4.1]\n')

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/medic/Work/Projekty/avocado/aexpect/aexpect/remote.py", line 857, in rsync_between_remotes
    return remote_copy(command, password_list,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/medic/Work/Projekty/avocado/aexpect/aexpect/remote.py", line 586, in remote_copy
    _remote_copy(session, password_list, transfer_timeout, login_timeout, method)
  File "/home/medic/Work/Projekty/avocado/aexpect/aexpect/remote.py", line 555, in _remote_copy
    raise TransferFailedError(error.status, error.output) from error
aexpect.remote.TransferFailedError: SCP transfer failed    (status: 1,    output: 'The source and destination cannot both be remote.\nrsync error: syntax or usage error (code 1) at main.c(1415) [Receiver=3.4.1]\n')

So it looks like you'll have to deal with this by either relying on scp or ssh to one of those and initiate the rsync from there (which might not cover the scenario where remotes don't have direct connection, then you'd have to tunel it through...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah interesting, in fact I have never used any copying between remotes and simply assumed rsync supports this as much as scp. If you want we can simply remove the support for this functionality then. The scp between remotes will still remain of course. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense to me. Better to be explicit than trying to hack something that might or might not work most of the time...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants