Execute bash commands: multiple writes to stdin of exec.Command - Docker

1,651 views
Skip to first unread message

piotrch...@gmail.com

unread,
Oct 4, 2013, 11:43:15 AM10/4/13
to golan...@googlegroups.com
Hi there!

I should point out that I am starting to learn Go and my knowledge of go is very limited. I am struggling with the following problem for more than a week now without success...please help! 

Basically I am trying to write an app in go that will execute a number of bash commands. The problem is that some of those commands, like setting up mountpoints on a remote machine using sshfs, require user input (adding to the list of known hosts, password to the host, etc). I am redirecting the cmd stdin and stdout to os.Stdin and os.Stdout but after typing the first input string the whole process freezes(or looks like it hangs) ,

Enough taking let the code speak for itself!:

package main

import (
  "fmt"
  "io"
  "os"
  "os/exec"
)

func main() {
  cmd := exec.Command("sudo", "docker", "run", "-i", "-t", "-privileged", "-dns=[172.25.0.10]", "-w=/home/foo/", "orobix/itk_sshfs", "/bin/bash", "-c", "sshfs -o idmap=user pi...@172.17.42.1:/home/piotr/helloworld /mnt/", "touch /mnt/CraneFile") //works when executed using unix terminal

  stdin, err := cmd.StdinPipe()
  exitOnErr("IN PIPE!", err)

  stderr, err := cmd.StderrPipe()
  exitOnErr("ERR PIPE!", err)

  stdout, err := cmd.StdoutPipe()
  exitOnErr("OUT PIPE!", err)

  err = cmd.Start()         
  exitOnErr("START ERROR!", err)

  defer cmd.Wait()

go io.Copy(os.Stdout, stdout)
  go io.Copy(stdin, os.Stdin)
  go io.Copy(os.Stderr, stderr)
}

func exitOnErr(message string, err error) {
  if err != nil {
    fmt.Println(message, err)
    os.Exit(1)
  }

The sshfs command should mount a host directory inside a remote machine (docker container)  and if that was successful it would create an example file on host. But the file is not created because the process looks like it is hanging after typing in password. Should I close some streams?

In order to run it you need to install docker (really really coll technology - http://www.docker.io/) but apart that it should compile nicely on your machine.

Any input is appreciated!


Konstantin Khomoutov

unread,
Oct 4, 2013, 12:49:46 PM10/4/13
to piotrch...@gmail.com, golan...@googlegroups.com
On Fri, 4 Oct 2013 08:43:15 -0700 (PDT)
piotrch...@gmail.com wrote:

> I should point out that I am starting to learn Go and my knowledge of
> go is very limited. I am struggling with the following problem for
> more than a week now without success...please help!
>
> Basically I am trying to write an app in go that will execute a
> number of bash commands. The problem is that some of those commands,
> like setting up mountpoints on a remote machine using sshfs, require
> user input (adding to the list of known hosts, password to the host,
> etc). I am redirecting the cmd stdin and stdout to os.Stdin and
> os.Stdout but after typing the first input string the whole process
> freezes(or looks like it hangs) ,
[...]

I reckon the problem here is that SSH, being a secure tool, when
requesting the user's password, makes sure it's connected to a
terminal, and does not just read it from its standard input stream.

You have basically two ways to deal with it.

The first one (IMHO, the better one) is to switch to using pubkey-based
authentication (supposedly using otherwise well-protected unencrypted
keys).

The second one is dancing around SSH making sure it's connected to a
terminal -- a pseudo terminal is OK. That's what sshpass [1] does, but
you supposedly should turn to using the pty Go package [2] ([3] lists
more than one, actually).

[...]
> In order to run it you need to install docker (really really coll
> technology - http://www.docker.io/) but apart that it should compile
> nicely on your machine.

The fun stuff is that according to godoc.org, the pty package is
imported by the Docker code.

1. http://sourceforge.net/projects/sshpass/
2. https://github.com/kr/pty
3. http://godoc.org/?q=pty

Piotr Chudzik

unread,
Oct 10, 2013, 5:09:29 AM10/10/13
to golan...@googlegroups.com, piotrch...@gmail.com
Thanks for the reply Konstantin!

I was following your advise and I was trying to upload my public key into the remote machine(Docker container) with the command:

scp -P <port number> <path/to/public/key/on/host> <path to remote machine authorized keys>

When I execute it using terminal commands everything works ok: id_rsa.pub is copied inside the container and I can login to it without a password.

However when I am trying to accomplish the same thing using Go app it hangs... after asking for root password(needed to do copying), I type the passsword and enter and it hangs..

I was trying to use pty as you recommended but it still fails:

package main

import (
  "io"
  "os"
  "os/exec"
)

func main() {

  c := exec.Command("scp", "-P", "49160", "~/.ssh/id_rsa.pub", "ro...@172.17.42.1:/root/.ssh/authorized_keys")
  f, err := pty.Start(c)

  if err != nil {
    panic(err)
  }
  //terminal

  f.Write([]byte("password\n"))//either way with write of without it will ask for user input ans wait for it

  io.Copy(os.Stdout, f)
}

The docker container is demonized and has a sshd listening for connection
I think you are right that the problem is ssh, but I can't neither upload my public key nor using pty seems to fix it. Sshfs and ssh are essential to my project so I have a big problem...

Btw I don't exactly understand how this pty works... I expected that I will get another terminal or at least a new prompt in the existing terminal but all I get is the empty screen I can write to and I don't know if my commands are executed or not.

Is it possible to use pty to execute a list of unix commands (this is something I am trying to achieve as well)?
 

Reply all
Reply to author
Forward
0 new messages