81d2c67492
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
171 lines
3.3 KiB
Go
171 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"github.com/dotcloud/docker/pkg/libcontainer"
|
|
"github.com/dotcloud/docker/pkg/libcontainer/namespaces"
|
|
"github.com/dotcloud/docker/pkg/libcontainer/network"
|
|
"github.com/dotcloud/docker/pkg/libcontainer/utils"
|
|
"os"
|
|
)
|
|
|
|
var (
|
|
displayPid bool
|
|
newCommand string
|
|
usrNet bool
|
|
)
|
|
|
|
func init() {
|
|
flag.BoolVar(&displayPid, "pid", false, "display the pid before waiting")
|
|
flag.StringVar(&newCommand, "cmd", "/bin/bash", "command to run in the existing namespace")
|
|
flag.BoolVar(&usrNet, "net", false, "user a net namespace")
|
|
flag.Parse()
|
|
}
|
|
|
|
func exec(container *libcontainer.Container) error {
|
|
var (
|
|
netFile *os.File
|
|
err error
|
|
)
|
|
container.NetNsFd = 0
|
|
|
|
if usrNet {
|
|
netFile, err = os.Open("/root/nsroot/test")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
container.NetNsFd = netFile.Fd()
|
|
}
|
|
|
|
pid, err := namespaces.Exec(container)
|
|
if err != nil {
|
|
return fmt.Errorf("error exec container %s", err)
|
|
}
|
|
|
|
if displayPid {
|
|
fmt.Println(pid)
|
|
}
|
|
|
|
exitcode, err := utils.WaitOnPid(pid)
|
|
if err != nil {
|
|
return fmt.Errorf("error waiting on child %s", err)
|
|
}
|
|
fmt.Println(exitcode)
|
|
if usrNet {
|
|
netFile.Close()
|
|
if err := network.DeleteNetworkNamespace("/root/nsroot/test"); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
os.Exit(exitcode)
|
|
return nil
|
|
}
|
|
|
|
func execIn(container *libcontainer.Container) error {
|
|
f, err := os.Open("/root/nsroot/test")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
container.NetNsFd = f.Fd()
|
|
pid, err := namespaces.ExecIn(container, &libcontainer.Command{
|
|
Env: container.Command.Env,
|
|
Args: []string{
|
|
newCommand,
|
|
},
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("error exexin container %s", err)
|
|
}
|
|
exitcode, err := utils.WaitOnPid(pid)
|
|
if err != nil {
|
|
return fmt.Errorf("error waiting on child %s", err)
|
|
}
|
|
os.Exit(exitcode)
|
|
return nil
|
|
}
|
|
|
|
func createNet(config *libcontainer.Network) error {
|
|
root := "/root/nsroot"
|
|
if err := network.SetupNamespaceMountDir(root); err != nil {
|
|
return err
|
|
}
|
|
|
|
nspath := root + "/test"
|
|
if err := network.CreateNetworkNamespace(nspath); err != nil {
|
|
return nil
|
|
}
|
|
if err := network.CreateVethPair("veth0", config.TempVethName); err != nil {
|
|
return err
|
|
}
|
|
if err := network.SetInterfaceMaster("veth0", config.Bridge); err != nil {
|
|
return err
|
|
}
|
|
if err := network.InterfaceUp("veth0"); err != nil {
|
|
return err
|
|
}
|
|
|
|
f, err := os.Open(nspath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
if err := network.SetInterfaceInNamespaceFd("veth1", int(f.Fd())); err != nil {
|
|
return err
|
|
}
|
|
|
|
/*
|
|
if err := network.SetupVethInsideNamespace(f.Fd(), config); err != nil {
|
|
return err
|
|
}
|
|
*/
|
|
return nil
|
|
}
|
|
|
|
func printErr(err error) {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
func main() {
|
|
var (
|
|
err error
|
|
cliCmd = flag.Arg(0)
|
|
config = flag.Arg(1)
|
|
)
|
|
f, err := os.Open(config)
|
|
if err != nil {
|
|
printErr(err)
|
|
}
|
|
|
|
dec := json.NewDecoder(f)
|
|
var container *libcontainer.Container
|
|
|
|
if err := dec.Decode(&container); err != nil {
|
|
printErr(err)
|
|
}
|
|
f.Close()
|
|
|
|
switch cliCmd {
|
|
case "exec":
|
|
err = exec(container)
|
|
case "execin":
|
|
err = execIn(container)
|
|
case "net":
|
|
err = createNet(&libcontainer.Network{
|
|
TempVethName: "veth1",
|
|
IP: "172.17.0.100/16",
|
|
Gateway: "172.17.42.1",
|
|
Mtu: 1500,
|
|
Bridge: "docker0",
|
|
})
|
|
default:
|
|
err = fmt.Errorf("command not supported: %s", cliCmd)
|
|
}
|
|
|
|
if err != nil {
|
|
printErr(err)
|
|
}
|
|
}
|