Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Verify rsync protocol version match prior to proceeding - Rebased on current master. #71

Merged
merged 7 commits into from
Jul 2, 2020

Conversation

stephenwithav
Copy link
Contributor

sync.Version() proceeds with a warning that there may be a version
mismatch if it timesout.

syncCmd.version assumes rsync is present in the path.

wsep integration is currently unverified. Verification is next.

Potentially closes #65.

`sync.Version()` proceeds with a warning that there may be a version
mismatch if it timesout.

`syncCmd.version` assumes rsync is present in the path.

`wsep.RemoteExecer` isn't available publicly on GitHub, so I took a
best guess with it and `wsep.ExitError`.
Passing `s.ReadLine` to `strings.Split` was a mistake since it returns
three values.

Having access to `wsep` helped the compiler find the bugs.
@stephenwithav
Copy link
Contributor Author

This builds locally fine.

The CI bug is inaccessible to me. Any tips, @scsmithr?

Copy link
Contributor

@scsmithr scsmithr left a comment

Choose a reason for hiding this comment

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

I know it's kind of tough to be contributing changes that you don't have a good way of testing, but I think we're close.

And you can ignore the ci failure, it's just failing because there isn't a license for you on that service. Everything compiled fine on my end.

Comment on lines 37 to 39
// See https://lxadm.com/Rsync_exit_codes#List_of_standard_rsync_exit_codes.
var IncompatRsync = errors.New("rsync: exit status 2")
var StreamErrRsync = errors.New("rsync: exit status 12")
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably leftover from a rebase, these were removed in master.

Comment on lines 42 to 65
func (s *syncCmd) version() string {
cmd := exec.Command("rsync", "--version")
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}

if err := cmd.Start(); err != nil {
log.Fatal(err)
}

r := bufio.NewReader(stdout)
if err := cmd.Wait(); err != nil {
log.Fatal(err)
}

firstLine, err := r.ReadString('\n')
if err != nil {
return ""
}

versionString := strings.Split(firstLine, "protocol version ")

return versionString[1]
Copy link
Contributor

Choose a reason for hiding this comment

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

The way this is laid out, version will always return an empty string. Reading from r will always error, because the pipe will be closed before we start reading from the command.

I would suggest replacing reading the output of the command with:

out, err := cmd.CombinedOutput()
if err != nil {
    log.Fatal(err)
}

And I would replace reading the first line with:

firstLine, err := bytes.NewBuffer(out).ReadString('\n')
if err != nil {
    log.Fatal(err)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do.

if err != nil {
return "", err
}
r := bufio.NewReader(process.Stdout())
Copy link
Contributor

Choose a reason for hiding this comment

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

We have the same issue here with the reader never reading anything.

I think the best solution here would be to replace this reader with:

buf := &bytes.Buffer{}
io.Copy(buf, process.Stdout())

And buf can be used down below to read the first line.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do.

Copy link
Contributor Author

@stephenwithav stephenwithav Jul 2, 2020

Choose a reason for hiding this comment

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

@scsmithr Do you want the remote check to log.Fatal fail if we can't retrieve it?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think I prefer the behavior you had, where we just return the error and warn the user.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The remote check still has that.

return "", err
}
buf := &bytes.Buffer{}
go io.Copy(buf, process.Stdout())
Copy link
Contributor

Choose a reason for hiding this comment

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

I would remove the go here. io.Copy will will terminate as expected once the command completes.

Having a goroutine here can be racy, because there's no guarantees that it runs or completes the copy before we start reading from the buffer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Contributor

@scsmithr scsmithr left a comment

Choose a reason for hiding this comment

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

Two very minor issues and we should be good to go.


err = process.Wait()
if code, ok := err.(wsep.ExitError); ok {
return "", fmt.Errorf("Version check exit status: %v", code)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return "", fmt.Errorf("Version check exit status: %v", code)
return "", fmt.Errorf("version check exit status: %v", code)

return "", fmt.Errorf("Version check exit status: %v", code)
}
if err != nil {
return "", fmt.Errorf("Server version mismatch")
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd prefer returning the error here instead.

@stephenwithav stephenwithav force-pushed the add-version-check-locally branch from 7ec1868 to d853066 Compare July 2, 2020 14:56
Comment on lines 290 to 292
if _, ok := err.(wsep.ExitError); ok {
return "", err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We may as well remove this branch.

@@ -29,6 +33,23 @@ func (cmd *syncCmd) RegisterFlags(fl *pflag.FlagSet) {
fl.BoolVarP(&cmd.init, "init", "i", false, "do initial transfer and exit")
}

// Returns local rsync protocol version as a string.
Copy link
Contributor

Choose a reason for hiding this comment

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

Apologies for missing this earlier in the review. These comments should start with the function/method name. So this would be "version returns local rsync protocol version as a string."

(And same for the other Version method)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No problem. I appreciate you teaching me the style you prefer prior to the interview next week so if I get the job, I'm already style trained.

Copy link
Contributor

@scsmithr scsmithr left a comment

Choose a reason for hiding this comment

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

Nice work, appreciate the contribution.

@scsmithr scsmithr merged commit c8cec8e into coder:master Jul 2, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Check that rsync protocol versions match before initiating transfer
2 participants