Machine: docker-machine scp should quote the path to the scp executable on windows

Created on 7 Apr 2018  路  14Comments  路  Source: docker/machine

SCP fails for me as the path to the executable contains a space character ("C:\Program Files...") and it seems machine does not properly quote the path when calling the executable.
Here is some sample output:

$ docker-machine --debug scp default:/var/lib/docker/myFolder/test.txt .
Docker Machine Version:  0.14.0, build 89b8332
Found binary path at C:\Program Files\Docker Toolbox\docker-machine.exe
Launching plugin server for driver virtualbox
Plugin server listening at address 127.0.0.1:53890
() Calling .GetVersion
Using API Version  1
() Calling .SetConfigRaw
() Calling .GetMachineName
(default) Calling .GetSSHPort
(default) Calling .GetSSHKeyPath
(default) Calling .GetSSHKeyPath
(default) Calling .GetSSHKeyPath
(default) Calling .GetSSHHostname
(default) Calling .GetSSHUsername
{C:\Program Files\Git\usr\bin\scp.exe [C:\Program Files\Git\usr\bin\scp.exe -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=quiet -3 -o IdentitiesOnly=yes -o Port=52587 -o IdentityFile="C:\\Users\\Cotto\\.docker\\machine\\machines\\default\\id_rsa" [email protected]:/var/lib/docker/myFolder/test.txt .] []  <nil> <nil> <nil> [] <nil> <nil> <nil> <nil> <nil> false [] [] [] [] <nil> <nil>}
cp: cannot stat 'Files\Git\usr\bin\scp.exe': No such file or directory
ssh: Could not resolve hostname c: Name or service not known
cp: cannot stat 'Files\Git\usr\bin\scp.exe': No such file or directory
cp: cannot stat '-o': No such file or directory
cp: cannot stat 'StrictHostKeyChecking=no': No such file or directory
cp: cannot stat '-o': No such file or directory
cp: cannot stat 'UserKnownHostsFile=/dev/null': No such file or directory
cp: cannot stat '-o': No such file or directory
cp: cannot stat 'LogLevel=quiet': No such file or directory
cp: cannot stat '-3': No such file or directory
cp: cannot stat '-o': No such file or directory
cp: cannot stat 'IdentitiesOnly=yes': No such file or directory
cp: cannot stat '-o': No such file or directory
cp: cannot stat 'Port=52587': No such file or directory
cp: cannot stat '-o': No such file or directory
ssh: Could not resolve hostname identityfile=c: Name or service not known
ssh: connect to host 127.0.0.1 port 22: Connection refused
exit status 1

When I use the mentioned command and quote the path it works:

$ "C:\Program Files\Git\usr\bin\scp.exe" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=quiet -3 -o IdentitiesOnly=yes -o Po
rt=52587 -o IdentityFile="C:\\Users\\Cotto\\.docker\\machine\\machines\\default\\id_rsa" [email protected]:/var/lib/docker/myFolder/test.txt .
test.txt                                                                                                            100%    5     0.0KB/s   00:00

I am using Docker Toolbox Quickstart Terminal on Win7.

aressh kinbug

Most helpful comment

@princemaple Feel free to submit a PR! :)

All 14 comments

I have the same issue. I solve it by downgrading to 0.12.2:
curl -L "https://github.com/docker/machine/releases/download/v0.12.2/docker-machine-Windows-x86_64.exe" > "/c/Program Files/Docker/Docker/Resources/bin/docker-machine.exe"

Same problem on Windows10 with Docker for Windows.

@shin- this should be an easy fix? this problem has been there since 0.14 if not 0.13

Same problem on windows 10 too.

Still an issue in 0.16.0

Is this related to #4302?

not exactly. In #4302 there is no space character in the path to the scp.exe whereas here it is.

Related go issue: https://github.com/golang/go/issues/17149

Relevant code line where maybe quoting has to be done or adding quotation marks: https://github.com/docker/machine/blob/77e027b1e847a7dac97fc9a2a9b4cef4aea93ce3/commands/scp.go#L128

@princemaple Feel free to submit a PR! :)

@shin- Seems that your commit broke the windows docker-machine SCP. Removing your code from scp_windows.go:

cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.CmdLine = fmt.Sprintf("'%s' %s", cmd.Path, strings.Join(cmd.Args, " "))

fixes the issue in question. I would fix it myself but I'm not a Go developer and having a some trouble understanding what you were trying to achieve. Either way, I ask you to please and fix this issue or revert your changes in the master branch.

For people waiting for fix, here is how to generate a fixed executable:

  1. Remove code lines I mentioned & unnecessary imports ("fmt", "strings" & "syscall").
  2. Add to Dockerfile: RUN TARGET_OS=windows TARGET_ARCH="amd64" make build-x.
  3. Run dockerfile
  4. Extract generated executable from container via docker cp: $ docker cp <container-name>:/go/src/github.com/docker/machine/bin/docker-machine-Windows-x86_64.exe <host-destination-folder>

Best regards,
Gon莽alo Santos.

I made a pull request to fix it, by the way single quotes don't work but double quotes does: https://github.com/docker/machine/pull/4707

Here is a little example to reproduce the issue (I'm very new to Go so I had to build it to understand what was going on):

package main

import (
    "fmt"
    "os"
    "os/exec"
    "strings"
    "syscall"
)

func runCmdWithStdIo(cmd exec.Cmd) error {
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr

    return cmd.Run()
}

func main() {

    cmdPath, _ := exec.LookPath("scp")

    baseSSHArgs := []string{
        "-o", "StrictHostKeyChecking=no",
        "-o", "UserKnownHostsFile=/dev/null",
        "-o", "LogLevel=quiet",
        "-3", "-r", "-q",
        "-o", "IdentitiesOnly=yes",
        "-o", "Port=22",
        "-o", "IdentityFile=\"C:\\\\Users\\\\xxx\\\\.docker\\\\machine\\\\machines\\\\dev\\\\id_rsa\"",
        "fileName",
        "docker@dev:~/"}

    cmd := exec.Command(cmdPath, baseSSHArgs...)
    //displayed in debug by docker-machine scp:
    fmt.Println(*cmd)

    cmd.SysProcAttr = &syscall.SysProcAttr{}
        //currenlty checked in:
    //cmd.SysProcAttr.CmdLine = fmt.Sprintf("%s %s", cmd.Path, strings.Join(cmd.Args, " "))     
        //fix
    cmd.SysProcAttr.CmdLine = fmt.Sprintf("\"%s\" %s", cmd.Path, strings.Join(cmd.Args[1:], " "))
    fmt.Printf("****\ncmd.SysProcAttr.CmdLine: %s\n", cmd.SysProcAttr.CmdLine)

    runCmdWithStdIo(*cmd)

    fmt.Println("Done.")
}
Was this page helpful?
0 / 5 - 0 ratings