-
Notifications
You must be signed in to change notification settings - Fork 623
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 flag option to copy files using rsync #3143
base: master
Are you sure you want to change the base?
add rsync flag option to copy files using rsync #3143
Conversation
a508328
to
4b57bc6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have rsync in the guest in all cases? Minimal vm images do not have rsync.
Also adding options is bad both for users and for testing. If it is better to copy with rsync, we should detect if rsync is available in the guest and host, and use it without adding new option. Otherwise fall back to scp.
If we always have rsync, better to use it instead of scp and minimize the testing matrix.
cmd/limactl/copy.go
Outdated
@@ -34,6 +34,7 @@ func newCopyCommand() *cobra.Command { | |||
|
|||
copyCommand.Flags().BoolP("recursive", "r", false, "copy directories recursively") | |||
copyCommand.Flags().BoolP("verbose", "v", false, "enable verbose output") | |||
copyCommand.Flags().BoolP("rsync", "", false, "use rsync for copying instead of scp") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not flexible enough. What if we want to another tool later? If we add an option, adding a "tool" or "backend" option will be better, with possible values "scp", "rsync".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the tool option will default to rsync
right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we add an option rsync sounds like a better default. But this is trivial to change if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's just remove the flag and only support rsync, unless there is a use case where scp
is preferable over rsync
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rsync
isn't available by default on Alpine, Arch Linux, and Debian (see here for pipeline logs). A potential fix for this is to ssh into the guest vm and check if rsync
is installed. @jandubois suggested running a command like this within the guest VM:
rsync --rsh="ssh" remote_user@remote_host rsync --version
.
However, implementing this approach introduces a limitation: rsync won’t work in scenarios where the instance name is unavailable, as the instance name is needed to fetch the hostname using store.Inspect(instName)
.
For example, this command would fail since it doesn’t provide the instance name:
limactl copy -r /etc/config /tmp
On the other hand, this would work because it includes the instance name:
limactl copy -r default:/etc/config /tmp
@nirs @AkihiroSuda @jandubois @afbjorklund I’d like to hear your thoughts on this approach and any potential alternatives. Would love to know if there's a better way to handle this while ensuring rsync works reliably.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rsync
isn't available by default on Alpine, Arch Linux, and Debian (see here for pipeline logs).
So to support these distros with required rsync, the templates will have to install rsync. Can you check what is the cost in time and space?
A potential fix for this
This is not a fix, but the way to deal with missing rsync.
is to ssh into the guest vm and check if
rsync
is installed. @jandubois suggested running a command like this within the guest VM:rsync --rsh="ssh" remote_user@remote_host rsync --version
.
We can also use ssh user@vm-ip command -v rsync
. We already use ssh to preform the initial connection so it should be easier to use it to detect guest capabilities.
However, implementing this approach introduces a limitation: rsync won’t work in scenarios where the instance name is unavailable, as the instance name is needed to fetch the hostname using
store.Inspect(instName)
.For example, this command would fail since it doesn’t provide the instance name:
limactl copy -r /etc/config /tmp
The online help instructs to prefix the file name with the instance name. It cannot work without this regardless of the tool use to copy.
So the issue about missing instance name does not exist.
On the other hand, this would work because it includes the instance name:
limactl copy -r default:/etc/config /tmp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this it the code checking for initial ssh connection. If you run limactl --debug start ...
you wll see the ssh commands used to detect if the guest is accessible.
Also, do we have tests for code modified in this PR? if not we should not change it before adding tests. The new rsync flow should also have tests. |
@olamilekan000 I've asked before to please test your changes locally instead of force-pushing an update every 10 minutes for 2 hours, triggering potentially costly CI runs all the time. |
I'd appreciate it if you can help with steps to run locally. I did try but It didn't work as expected. |
Yes, rsync is always available on macOS and most Linux distros. |
@olamilekan000, Can you describe how did you try to test and why it did not work well? You can also join the #lima slack channel to get quicker help from other developers. |
4b57bc6
to
aa5cf22
Compare
@nirs I have joined and shared my error logs on the channel. |
aa5cf22
to
4c95f10
Compare
cmd/limactl/copy.go
Outdated
sshArgs := sshutil.SSHArgsFromOpts(sshOpts) | ||
|
||
sshCmd := exec.Command(arg0, append(sshArgs, scpArgs...)...) | ||
sshCmd := exec.Command(arg0, createArgs(sshArgs, copyToolArgs, defaultTool)...) | ||
sshCmd.Stdin = cmd.InOrStdin() | ||
sshCmd.Stdout = cmd.OutOrStdout() | ||
sshCmd.Stderr = cmd.ErrOrStderr() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We run rsync via ssh? it does not make sense.
Can you share the complete the scp and rsync commands that you want to run?
The commands can be tested from the shell without lima, using the instance ip. limactl just make this easier for the user by building the right command and running it transparently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for scp
scp -F ~/.lima/deb/ssh.config "myfile.txt" olalekanodukoya@lima-deb:/dump
myfile.txt 100% 7 2.1KB/s 00:00
for rsync
rsync -a -e "ssh -i ~/.lima/deb/ssh.config -p 50337" myfile.txt [email protected]:/dump/
73fcc08
to
a9bade5
Compare
path := strings.Split(arg, ":") | ||
switch len(path) { | ||
case 1: | ||
inst, ok := instances[instName] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How this will work? instances is an empty map created in this function.
I think we have only one case - instance:path
, and it is common to both scp and rsync, so this check should be done first before we consider the copy tool. Input validation must always be done first.
} | ||
sshStr = fmt.Sprintf("ssh -p %s -i %s", fmt.Sprintf("%d", inst.SSHLocalPort), "~/.lima/_config/user") | ||
rsyncArgs = append(rsyncArgs, "-avz", "-e", sshStr, path[1]) | ||
instances[instName] = inst |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, you add the instance to the map so the next iteration will find it. This is very complicated and hard to follow way to handle the arguments.
We should instead process the argument first, and convert them to internal structure that will be used to construct the command. This should be common to scp and rsync, so it should be done before we consider the tool.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should instead process the argument first, and convert them to internal structure that will be used to construct the command. This should be common to scp and rsync, so it should be done before we consider the tool.
The argument processing for scp and rsync is quite different, so combining them into a single function could make it complex and harder to maintain. II think it’s better to keep them separate and focus on consistent output structures instead.
pkg/hostagent/hostagent.go
Outdated
@@ -424,6 +424,41 @@ func (a *HostAgent) Info(_ context.Context) (*hostagentapi.Info, error) { | |||
return info, nil | |||
} | |||
|
|||
func (a *HostAgent) installPackage() error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would not install the package here. If we depend on rsync in the guest, we can install the package using cloud-init.
In our user-data (part of cidata.iso), we can add:
packages:
- rsync
This will install rsync using cloud-init when the instance is provisioned. For distros that do not support this, the provision part of the yaml can install rsync manually.
pkg/hostagent/hostagent.go
Outdated
sudo pacman -S --noconfirm rsync | ||
else | ||
echo "Unsupported Linux distribution. Please install rsync manually." | ||
fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like you are reinventing cloudinit :-)
I think we can do this:
@AkihiroSuda what do you think? |
1d17b78
to
7c55a22
Compare
hack/test-templates.sh
Outdated
@@ -192,7 +192,7 @@ if [ "$got" != "$expected" ]; then | |||
fi | |||
|
|||
INFO "Testing limactl copy command" | |||
tmpfile="$HOME/lima-hostname" | |||
tmpfile="/var/tmp/lima-hostname" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not using $HOME/lima-hostname is a very good change - running tests locally should not create files in your home directory.
But this name may clash with another test, or a file created by someone else.
Best to use a temporary directory that can never clash with anything:
% mktemp -d /var/tmp/lima-test-templates.XXXXXX
/var/tmp/lima-test-templates.vuRmiE
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! but it seems that this is the only test for limactl copy.
I opened #3170 for improving limactl copy tests. I hope we can improve test coverage before we change the code to avoid regressions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. That can be done after #3163 gets merged.
SGTM |
Signed-off-by: olalekan odukoya <[email protected]>
7c55a22
to
54e7507
Compare
issue #2198