Simplify namespaces with only nsinit
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
This commit is contained in:
parent
c1f8606d50
commit
e25ebdd06c
6 changed files with 23 additions and 278 deletions
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
|
@ -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
|
|
@ -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 {
|
||||||
|
if container.LogFile != "" {
|
||||||
f, err := os.OpenFile(container.LogFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0655)
|
f, err := os.OpenFile(container.LogFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0655)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.SetOutput(f)
|
log.SetOutput(f)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
Loading…
Reference in a new issue