Simplify namespaces with only nsinit

Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
This commit is contained in:
Michael Crosby 2014-02-19 14:55:34 -08:00
parent c1f8606d50
commit e25ebdd06c
6 changed files with 23 additions and 278 deletions

View file

@ -1,203 +0,0 @@
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/namespaces/nsinit"
"github.com/dotcloud/docker/pkg/libcontainer/network"
"github.com/dotcloud/docker/pkg/libcontainer/utils"
"os"
exec_ "os/exec"
"path"
"path/filepath"
)
var (
displayPid bool
newCommand string
usrNet bool
masterFd int
console string
)
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.IntVar(&masterFd, "master", 0, "master fd")
flag.StringVar(&console, "console", "", "console path")
flag.Parse()
}
func nsinitFunc(container *libcontainer.Container) error {
container.Master = uintptr(masterFd)
container.Console = console
container.LogFile = "/root/logs"
return nsinit.InitNamespace(container)
}
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()
}
self, err := exec_.LookPath(os.Args[0])
if err != nil {
return err
}
if output, err := exec_.Command("cp", self, path.Join(container.RootFs, ".nsinit")).CombinedOutput(); err != nil {
return fmt.Errorf("Error exec cp: %s, (%s)", err, output)
} else {
println(self, container.RootFs)
fmt.Printf("-----> %s\n", output)
}
println("----")
pid, err := namespaces.ExecContainer(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() {
cliCmd := flag.Arg(0)
config, err := filepath.Abs(flag.Arg(1))
if err != nil {
printErr(err)
}
println("cli:", cliCmd, "config:", config)
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 "init":
err = nsinitFunc(container)
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)
}
}

View file

@ -1,48 +0,0 @@
package namespaces
import (
"fmt"
"github.com/dotcloud/docker/pkg/libcontainer"
"os"
"path/filepath"
"strconv"
"strings"
)
func addEnvIfNotSet(container *libcontainer.Container, key, value string) {
jv := fmt.Sprintf("%s=%s", key, value)
if len(container.Command.Env) == 0 {
container.Command.Env = []string{jv}
return
}
for _, v := range container.Command.Env {
parts := strings.Split(v, "=")
if parts[0] == key {
return
}
}
container.Command.Env = append(container.Command.Env, jv)
}
// getNsFd returns the fd for a specific pid and namespace option
func getNsFd(pid int, ns string) (uintptr, error) {
nspath := filepath.Join("/proc", strconv.Itoa(pid), "ns", ns)
// OpenFile adds closOnExec
f, err := os.OpenFile(nspath, os.O_RDONLY, 0666)
if err != nil {
return 0, err
}
return f.Fd(), nil
}
// setupEnvironment adds additional environment variables to the container's
// Command such as USER, LOGNAME, container, and TERM
func setupEnvironment(container *libcontainer.Container) {
addEnvIfNotSet(container, "container", "docker")
// TODO: check if pty
addEnvIfNotSet(container, "TERM", "xterm")
// TODO: get username from container
addEnvIfNotSet(container, "USER", "root")
addEnvIfNotSet(container, "LOGNAME", "root")
}

View file

@ -1,4 +1,4 @@
package namespaces package main
import ( import (
"github.com/dotcloud/docker/pkg/libcontainer" "github.com/dotcloud/docker/pkg/libcontainer"
@ -11,15 +11,7 @@ import (
"syscall" "syscall"
) )
// ExecContainer will spawn new namespaces with the specified Container configuration func execCommand(container *libcontainer.Container) (pid int, err error) {
// in the RootFs path and return the pid of the new containerized process.
//
// If an existing network namespace is specified the container
// will join that namespace. If an existing network namespace is not specified but CLONE_NEWNET is,
// the container will be spawned with a new network namespace with no configuration. Omiting an
// existing network namespace and the CLONE_NEWNET option in the container configuration will allow
// the container to the the host's networking options and configuration.
func ExecContainer(container *libcontainer.Container) (pid int, err error) {
master, console, err := createMasterAndConsole() master, console, err := createMasterAndConsole()
if err != nil { if err != nil {
return -1, err return -1, err
@ -50,7 +42,19 @@ func ExecContainer(container *libcontainer.Container) (pid int, err error) {
} }
}() }()
term.SetRawTerminal(os.Stdin.Fd()) ws, err := term.GetWinsize(os.Stdin.Fd())
if err != nil {
return -1, err
}
if err := term.SetWinsize(master.Fd(), ws); err != nil {
return -1, err
}
state, err := term.SetRawTerminal(os.Stdin.Fd())
if err != nil {
command.Process.Kill()
return -1, err
}
defer term.RestoreTerminal(os.Stdin.Fd(), state)
if err := command.Wait(); err != nil { if err := command.Wait(); err != nil {
return pid, err return pid, err

View file

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"github.com/dotcloud/docker/pkg/libcontainer" "github.com/dotcloud/docker/pkg/libcontainer"
"github.com/dotcloud/docker/pkg/libcontainer/capabilities" "github.com/dotcloud/docker/pkg/libcontainer/capabilities"
"github.com/dotcloud/docker/pkg/libcontainer/namespaces"
"github.com/dotcloud/docker/pkg/system" "github.com/dotcloud/docker/pkg/system"
"log" "log"
"os" "os"
@ -34,7 +33,7 @@ func main() {
} }
if os.Args[1] == "exec" { if os.Args[1] == "exec" {
_, err := namespaces.ExecContainer(container) _, err := execCommand(container)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -157,11 +156,13 @@ func openTerminal(name string, flag int) (*os.File, error) {
} }
func setLogFile(container *libcontainer.Container) error { func setLogFile(container *libcontainer.Container) error {
f, err := os.OpenFile(container.LogFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0655) if container.LogFile != "" {
if err != nil { f, err := os.OpenFile(container.LogFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0655)
return err if err != nil {
return err
}
log.SetOutput(f)
} }
log.SetOutput(f)
return nil return nil
} }

View file

@ -1,4 +1,4 @@
package namespaces package main
import ( import (
"github.com/dotcloud/docker/pkg/libcontainer" "github.com/dotcloud/docker/pkg/libcontainer"
@ -25,15 +25,6 @@ var namespaceMap = map[libcontainer.Namespace]int{
libcontainer.CLONE_NEWNET: CLONE_NEWNET, libcontainer.CLONE_NEWNET: CLONE_NEWNET,
} }
var namespaceFileMap = map[libcontainer.Namespace]string{
libcontainer.CLONE_NEWNS: "mnt",
libcontainer.CLONE_NEWUTS: "uts",
libcontainer.CLONE_NEWIPC: "ipc",
libcontainer.CLONE_NEWUSER: "user",
libcontainer.CLONE_NEWPID: "pid",
libcontainer.CLONE_NEWNET: "net",
}
// getNamespaceFlags parses the container's Namespaces options to set the correct // getNamespaceFlags parses the container's Namespaces options to set the correct
// flags on clone, unshare, and setns // flags on clone, unshare, and setns
func getNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) { func getNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) {