Executing docker command using golang exec fails - go

I am using cmd.go (see below) to execute a docker command but it fails. I do the following steps to execute and get the following error.
go build
sudo ./cmd
Output:
docker run -v ~/exp/a.out:/a.out ubuntu:14.04 /a.out -m 10m
2014/10/16 14:32:12 exit status 1
On the other hand running directly as
sudo docker run -v ~/exp/a.out:/a.out ubuntu:14.04 /a.out -m 10m
results in the correct output of a.out.
Hello World
This is the code of cmd.go. How can I get it to work? Thanks!
package main
import (
"fmt"
"log"
"os/exec"
"strings"
)
func ExampleCmd_Output() {
//out, err := exec.Command("date", "--version").Output() // This works
//out, err := exec.Command("docker", "--version").Output() // This works
//out, err := exec.Command(cmd, "images").Output() // Even docker images command works!
cmd := "docker"
cmdArgs := []string{"run", "-v", "~/exp/a.out:/a.out", "ubuntu:14.04", "/a.out", "-m", "10m"}
fmt.Println(cmd + " " + strings.Join(cmdArgs, " "))
out, err := exec.Command(cmd, cmdArgs...).Output()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", out)
}
func main() {
ExampleCmd_Output()
}
EDIT: After a comment, I tried executing the command "docker images". It works if I run the executable with sudo. That is, I am using the following line in the code now.
out, err := exec.Command(cmd, "images").Output()
After doing go build and running "sudo ./cmd", I get the output of docker images command. However, without sudo, I still get exit status 1. But with docker run command above even with sudo, I don't get an output.

Thanks to Os Exec Sudo Command in Go, I am now able to do what I want.
func main() {
cmdStr := "sudo docker run -v ~/exp/a.out:/a.out ubuntu:14.04 /a.out -m 10m"
out, _ := exec.Command("/bin/sh", "-c", cmdStr).Output()
fmt.Printf("%s", out)
}
Output:
Hello World

Related

Run a docker container inside a Go server

I am trying to run a docker container in a Go server with using exec.Command.
Here is my code to run:
entrypoint := "/bin/bash"
run := fmt.Sprintf("docker run -a stdout -a stderr --rm %s %s %s", env, image, args)
cmd := exec.Command(entrypoint, "-c", run)
if err := cmd.Start(); err != nil {
return err
}
where env is something like:
-e KEY=VALUE
However, I get an error such as:
/bin/bash: docker run ... : No such file or directory
Then, I added double-quotes to the beginning and the end of docker command:
cmd := exec.Command(entrypoint, "-c", "\""+run+"\"")
This time, I can run command /bin/bash -c "docker run ..." in my Zsh terminal. However Go still throws the same error.
What should I do?
You are passing the docker run command and all its arguments as a single argument. Instead, try this:
cmd := exec.Command(entrypoint, "-c", "docker", "run", "-a", "stdout", "-a", "stderr", "--rm", <break up env>, image, args)

Complex command in exec.Command()

I want to exec this command:
docker exec -it demoContainer bash -c "pip freeze" > "requirements.txt"
But don't find any example of this kind of complex commands with pipes, and output writes.
I tryed this:
cmd := exec.Command("docker", "exec -it demoContainer bash -c \"pip freeze\" > \"requirements.txt\"")
_, err = cmd.CombinedOutput()
And:
cmd := exec.Command("docker", "exec", "-it", "demoContainer", "bash", "-c", "pip freeze", ">", "scheduleDeploy/requirements.txt")
_, err = cmd.CombinedOutput()
But always crash with the following output:
Error: Exit status 1
Edit
Updates with answers ideas:
err = exec.Command("sh", "-c","'docker exec -it demoContainer bash -c 'pip freeze' > 'requirements.txt''").Run()
Output:
Exit error status 2
You don't have to use the shell for redirection, you can just let Go do it:
package main
import (
"os"
"os/exec"
)
func main() {
f, e := os.Create("requirements.txt")
if e != nil {
panic(e)
}
defer f.Close()
c := exec.Command(
"docker", "exec", "-it", "demoContainer", "bash", "-c", "pip freeze",
)
c.Stdout = f
c.Run()
}
The > redirection is a "shell" thing, not an "exec" thing. You will need to do one of "run bash, with the command you want executed" or "open a file, set the resulting os.File as the Stdout of the exec.Command, before starting it".
Either would probably solve the issue you are facing.
To use the "bash -c" version, something like:
exec.Command("bash", "-c", `docker exec -it demoContainer bash -c "pip freeze" > requirements.txt`)

Using Go to spawn a shell with a TTY from "nc -e /bin/bash"

I want to escape a restricted shell spawning a bash shell via Go. In other words, I want to do this but using Go:
python -c 'import pty; pty.spawn("/bin/bash")'
I am totally new to Go. I have tried this (following the answer in this question Go: How to spawn a bash shell) but nothing happens:
package main
import "os"
import "os/exec"
func main() {
shell := exec.Command("/bin/bash")
shell.Stdout = os.Stdout
shell.Stdin = os.Stdin
shell.Stderr = os.Stderr
shell.Run()
}
Also if I add the fmt.Println("hello") line at the end of the main function nothing is printed
UPDATE
Maybe I did not expalined well. What I am trying to achieve it's to spawn a shell gotten a restricted shell. This is what I did:
Listener:
nc.traditional -l -p 8080 -e /bin/bash
Connects to listener: And I exec the code here
nc.traditional localhost 8080 -v
Your program works fine for me. I put some error checking in and an extra print statement which should make what is happening clearer. You are getting an interactive shell, it just looks exactly like your previous shell.
$ go run Go/shell.go
$ # whoa another shell
$ exit
exit
exiting
$ # back again
$
Here is the revised program
package main
import (
"fmt"
"log"
"os"
"os/exec"
)
func main() {
shell := exec.Command("/bin/bash")
shell.Stdout = os.Stdout
shell.Stdin = os.Stdin
shell.Stderr = os.Stderr
err := shell.Run()
if err != nil {
log.Fatalf("command failed: %v", err)
}
fmt.Printf("exiting\n")
}

go execute ssh command and can't kill the command on the remote server

I use go exec ssh to execute "tail -f" on the remote server. Then I kill the process, but the "tail -f " still runs on the remote server.
What can I do to kill the "tail -f" process on the remote server?
My code is as follows:
package main
import (
"os/exec"
"github.com/astaxie/beego"
"time"
)
func main() {
var cmd = exec.Command("ssh","-t", "-p", "9122","deploy#123.com" ,"tail -f /log.out")
var err error
cmd.Start()
time.Sleep(time.Second*5)
err = cmd.Process.Kill() // when I kill this process, the remote server deploy#123.com still has 'tail -f /log.out' running
beego.Error(err)
}
Just add one more "-t" in the arguments.
var cmd = exec.Command("ssh","-t", "-t", "-p", "9122","deploy#123.com" ,"tail -f /log.out")
For more information, refer this link
You can try to send Control-C
w, err := cmd.StdinPipe()
ctlC, err := hex.DecodeString(`\x03`) //CtlC on most machines
w.Write(ctlC)
before killing ssh
err = cmd.Process.Kill()
this works in my setup

os.Exec and /bin/sh: executing multiple commands

I've run into an issue with the os/exec library. I want to run a shell and pass it multiple commands to run, but it's failing when I do. Here's my test code:
package main
import (
"fmt"
"os/exec"
)
func main() {
fmt.Printf("-- Test 1 --\n`")
command1 := fmt.Sprintf("\"%s\"", "pwd") // this one succeeds
fmt.Printf("Running: %s\n", command1)
cmd1 := exec.Command("/bin/sh", "-c", command1)
output1,err1 := cmd1.CombinedOutput()
if err1 != nil {
fmt.Printf("error: %v\n", err1)
return
}
fmt.Printf(string(output1))
fmt.Printf("-- Test 2 --\n")
command2 := fmt.Sprintf("\"%s\"", "pwd && pwd") // this one fails
fmt.Printf("Running: %s\n", command2)
cmd2 := exec.Command("/bin/sh", "-c", command2)
output2,err2 := cmd2.CombinedOutput()
if err2 != nil {
fmt.Printf("error: %v\n", err2)
return
}
fmt.Printf(string(output2))
}
When running this I get an error 127 on the second example. It seems like it's looking for a literal "pwd && pwd" command instead of evaluating it as a script.
If I do the same thing from the command line it works just fine.
$ /bin/sh -c "pwd && pwd"
I'm using Go 1.4 on OS X 10.10.2.
the quotes are for your shell where you typed the command line, they should not be included when programatically launching an app
just make this change and it will work:
command2 := "pwd && pwd" // you don't want the extra quotes

Resources