From 998ada530301a9e4414016a27eac34e4b41d9644 Mon Sep 17 00:00:00 2001 From: Nathan LeClaire Date: Wed, 7 Oct 2015 20:33:19 -0700 Subject: [PATCH] Fix Windows SSH issues Signed-off-by: Nathan LeClaire --- commands/ssh.go | 21 ++++-------- libmachine/host/host.go | 9 ----- libmachine/ssh/client.go | 37 ++++++++++---------- libmachine/ssh/client_test.go | 45 +++++++++++++++++++++++++ test/integration/core/ssh-backends.bats | 2 +- 5 files changed, 71 insertions(+), 43 deletions(-) create mode 100644 libmachine/ssh/client_test.go diff --git a/commands/ssh.go b/commands/ssh.go index 6d9eb38b76..cf357afd7a 100644 --- a/commands/ssh.go +++ b/commands/ssh.go @@ -1,9 +1,6 @@ package commands import ( - "fmt" - "strings" - "github.com/docker/machine/libmachine/log" "github.com/docker/machine/libmachine/state" @@ -33,18 +30,12 @@ func cmdSsh(c *cli.Context) { log.Fatalf("Error: Cannot run SSH command: Host %q is not running", host.Name) } - if len(c.Args()) == 1 { - err := host.CreateSSHShell() - if err != nil { - log.Fatal(err) - } - } else { - output, err := host.RunSSHCommand(strings.Join(c.Args().Tail(), " ")) - if err != nil { - log.Fatal(err) - } - - fmt.Print(output) + client, err := host.CreateSSHClient() + if err != nil { + log.Fatal(err) } + if err := client.Shell(c.Args().Tail()...); err != nil { + log.Fatal(err) + } } diff --git a/libmachine/host/host.go b/libmachine/host/host.go index 521cc759d5..b93f332678 100644 --- a/libmachine/host/host.go +++ b/libmachine/host/host.go @@ -74,15 +74,6 @@ func (h *Host) CreateSSHClient() (ssh.Client, error) { return ssh.NewClient(h.Driver.GetSSHUsername(), addr, port, auth) } -func (h *Host) CreateSSHShell() error { - client, err := h.CreateSSHClient() - if err != nil { - return err - } - - return client.Shell() -} - func (h *Host) runActionForState(action func() error, desiredState state.State) error { if drivers.MachineInState(h.Driver, desiredState)() { return fmt.Errorf("Machine %q is already %s.", h.Name, strings.ToLower(desiredState.String())) diff --git a/libmachine/ssh/client.go b/libmachine/ssh/client.go index 88aab1698d..9c1585b897 100644 --- a/libmachine/ssh/client.go +++ b/libmachine/ssh/client.go @@ -16,7 +16,7 @@ import ( type Client interface { Output(command string) (string, error) - Shell() error + Shell(args ...string) error } type ExternalClient struct { @@ -195,7 +195,7 @@ func (client NativeClient) OutputWithPty(command string) (string, error) { return string(output), err } -func (client NativeClient) Shell() error { +func (client NativeClient) Shell(args ...string) error { var ( termWidth, termHeight int ) @@ -243,12 +243,15 @@ func (client NativeClient) Shell() error { return err } - if err := session.Shell(); err != nil { - return err + if len(args) == 0 { + if err := session.Shell(); err != nil { + return err + } + session.Wait() + } else { + session.Run(strings.Join(args, " ")) } - session.Wait() - return nil } @@ -272,23 +275,21 @@ func NewExternalClient(sshBinaryPath, user, host string, port int, auth *Auth) ( return client, nil } +func getSSHCmd(binaryPath string, args ...string) *exec.Cmd { + return exec.Command(binaryPath, args...) +} + func (client ExternalClient) Output(command string) (string, error) { - // TODO: Ugh, gross hack. Replace with all instances using variadic - // syntax - args := append(client.BaseArgs, strings.Split(command, " ")...) - - cmd := exec.Command(client.BinaryPath, args...) - log.Debug(cmd) - - // Allow piping of local things to remote commands. - cmd.Stdin = os.Stdin - + args := append(client.BaseArgs, command) + cmd := getSSHCmd(client.BinaryPath, args...) output, err := cmd.CombinedOutput() return string(output), err } -func (client ExternalClient) Shell() error { - cmd := exec.Command(client.BinaryPath, client.BaseArgs...) +func (client ExternalClient) Shell(args ...string) error { + args = append(client.BaseArgs, args...) + cmd := getSSHCmd(client.BinaryPath, args...) + log.Debug(cmd) cmd.Stdin = os.Stdin diff --git a/libmachine/ssh/client_test.go b/libmachine/ssh/client_test.go new file mode 100644 index 0000000000..65d35becd9 --- /dev/null +++ b/libmachine/ssh/client_test.go @@ -0,0 +1,45 @@ +package ssh + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetSSHCmdArgs(t *testing.T) { + cases := []struct { + binaryPath string + args []string + expectedArgs []string + }{ + { + binaryPath: "/usr/local/bin/ssh", + args: []string{ + "docker@localhost", + "apt-get install -y htop", + }, + expectedArgs: []string{ + "/usr/local/bin/ssh", + "docker@localhost", + "apt-get install -y htop", + }, + }, + { + binaryPath: "C:\\Program Files\\Git\\bin\\ssh.exe", + args: []string{ + "docker@localhost", + "sudo /usr/bin/sethostname foobar && echo 'foobar' | sudo tee /var/lib/boot2docker/etc/hostname", + }, + expectedArgs: []string{ + "C:\\Program Files\\Git\\bin\\ssh.exe", + "docker@localhost", + "sudo /usr/bin/sethostname foobar && echo 'foobar' | sudo tee /var/lib/boot2docker/etc/hostname", + }, + }, + } + + for _, c := range cases { + cmd := getSSHCmd(c.binaryPath, c.args...) + assert.Equal(t, cmd.Args, c.expectedArgs) + } +} diff --git a/test/integration/core/ssh-backends.bats b/test/integration/core/ssh-backends.bats index cea6dc7c18..7fc1fba0d9 100644 --- a/test/integration/core/ssh-backends.bats +++ b/test/integration/core/ssh-backends.bats @@ -26,7 +26,7 @@ load ${BASE_TEST_DIR}/helpers.bash @test "$DRIVER: test command did what it purported to -- native ssh" { run machine --native-ssh ssh $NAME echo foo - [[ "$output" == "foo" ]] + [[ "$output" =~ "foo" ]] } @test "$DRIVER: ensure that ssh extra arguments work" {