Ver Fonte

Remove command factory and NsInit interface from libcontainer
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)

Michael Crosby há 11 anos atrás
pai
commit
176c49d7a9

+ 0 - 37
pkg/libcontainer/nsinit/command.go

@@ -1,37 +0,0 @@
-package nsinit
-
-import (
-	"os"
-	"os/exec"
-
-	"github.com/dotcloud/docker/pkg/libcontainer"
-	"github.com/dotcloud/docker/pkg/system"
-)
-
-// CommandFactory takes the container's configuration and options passed by the
-// parent processes and creates an *exec.Cmd that will be used to fork/exec the
-// namespaced init process
-type CommandFactory interface {
-	Create(container *libcontainer.Container, console string, syncFd *os.File, args []string) *exec.Cmd
-}
-
-type DefaultCommandFactory struct {
-	Root string
-}
-
-// Create will return an exec.Cmd with the Cloneflags set to the proper namespaces
-// defined on the container's configuration and use the current binary as the init with the
-// args provided
-func (c *DefaultCommandFactory) Create(container *libcontainer.Container, console string, pipe *os.File, args []string) *exec.Cmd {
-	// get our binary name from arg0 so we can always reexec ourself
-	command := exec.Command(os.Args[0], append([]string{
-		"-console", console,
-		"-pipe", "3",
-		"-root", c.Root,
-		"init"}, args...)...)
-
-	system.SetCloneFlags(command, uintptr(GetNamespaceFlags(container.Namespaces)))
-	command.Env = container.Env
-	command.ExtraFiles = []*os.File{pipe}
-	return command
-}

+ 43 - 6
pkg/libcontainer/nsinit/exec.go

@@ -20,7 +20,7 @@ import (
 
 // Exec performes setup outside of a namespace so that a container can be
 // executed.  Exec is a high level function for working with container namespaces.
-func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, pidRoot string, args []string, startCallback func()) (int, error) {
+func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath string, args []string, startCallback func()) (int, error) {
 	var (
 		master  *os.File
 		console string
@@ -42,7 +42,7 @@ func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, pidRoo
 		term.SetMaster(master)
 	}
 
-	command := ns.commandFactory.Create(container, console, syncPipe.child, args)
+	command := CreateCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.child, args)
 	if err := term.Attach(command); err != nil {
 		return -1, err
 	}
@@ -56,11 +56,11 @@ func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, pidRoo
 	if err != nil {
 		return -1, err
 	}
-	if err := WritePid(pidRoot, command.Process.Pid, started); err != nil {
+	if err := WritePid(dataPath, command.Process.Pid, started); err != nil {
 		command.Process.Kill()
 		return -1, err
 	}
-	defer DeletePid(pidRoot)
+	defer DeletePid(dataPath)
 
 	// Do this before syncing with child so that no children
 	// can escape the cgroup
@@ -90,8 +90,45 @@ func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, pidRoo
 			return -1, err
 		}
 	}
-	status := command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
-	return status, err
+	return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
+}
+
+// CreateCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
+// defined on the container's configuration and use the current binary as the init with the
+// args provided
+//
+// console: the /dev/console to setup inside the container
+// init: the progam executed inside the namespaces
+// root: the path to the container json file and information
+// pipe: sync pipe to syncronize the parent and child processes
+// args: the arguemnts to pass to the container to run as the user's program
+func CreateCommand(container *libcontainer.Container, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
+	// get our binary name from arg0 so we can always reexec ourself
+	env := []string{
+		"console=" + console,
+		"pipe=3",
+		"data_path=" + dataPath,
+	}
+
+	/*
+	   TODO: move user and wd into env
+	   if user != "" {
+	       env = append(env, "user="+user)
+	   }
+	   if workingDir != "" {
+	       env = append(env, "wd="+workingDir)
+	   }
+	*/
+
+	command := exec.Command(init, append([]string{"init"}, args...)...)
+	// make sure the process is executed inside the context of the rootfs
+	command.Dir = rootfs
+	command.Env = append(os.Environ(), env...)
+
+	system.SetCloneFlags(command, uintptr(GetNamespaceFlags(container.Namespaces)))
+	command.ExtraFiles = []*os.File{pipe}
+
+	return command
 }
 
 // SetupCgroups applies the cgroup restrictions to the process running in the contaienr based

+ 3 - 3
pkg/libcontainer/nsinit/execin.go

@@ -16,7 +16,7 @@ import (
 )
 
 // ExecIn uses an existing pid and joins the pid's namespaces with the new command.
-func (ns *linuxNs) ExecIn(container *libcontainer.Container, nspid int, args []string) (int, error) {
+func ExecIn(container *libcontainer.Container, nspid int, args []string) (int, error) {
 	for _, nsv := range container.Namespaces {
 		// skip the PID namespace on unshare because it it not supported
 		if nsv.Key != "NEWPID" {
@@ -25,7 +25,7 @@ func (ns *linuxNs) ExecIn(container *libcontainer.Container, nspid int, args []s
 			}
 		}
 	}
-	fds, err := ns.getNsFds(nspid, container)
+	fds, err := getNsFds(nspid, container)
 	closeFds := func() {
 		for _, f := range fds {
 			system.Closefd(f)
@@ -95,7 +95,7 @@ dropAndExec:
 	panic("unreachable")
 }
 
-func (ns *linuxNs) getNsFds(pid int, container *libcontainer.Container) ([]uintptr, error) {
+func getNsFds(pid int, container *libcontainer.Container) ([]uintptr, error) {
 	fds := make([]uintptr, len(container.Namespaces))
 	for i, ns := range container.Namespaces {
 		f, err := os.OpenFile(filepath.Join("/proc/", strconv.Itoa(pid), "ns", ns.File), os.O_RDONLY, 0)

+ 19 - 1
pkg/libcontainer/nsinit/init.go

@@ -6,6 +6,7 @@ import (
 	"fmt"
 	"os"
 	"runtime"
+	"strings"
 	"syscall"
 
 	"github.com/dotcloud/docker/pkg/apparmor"
@@ -22,12 +23,18 @@ import (
 
 // Init is the init process that first runs inside a new namespace to setup mounts, users, networking,
 // and other options required for the new container.
-func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error {
+func Init(container *libcontainer.Container, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error {
 	rootfs, err := utils.ResolveRootfs(uncleanRootfs)
 	if err != nil {
 		return err
 	}
 
+	// clear the current processes env and replace it with the environment
+	// defined on the container
+	if err := LoadContainerEnvironment(container); err != nil {
+		return err
+	}
+
 	// We always read this as it is a way to sync with the parent as well
 	context, err := syncPipe.ReadFromParent()
 	if err != nil {
@@ -132,3 +139,14 @@ func FinalizeNamespace(container *libcontainer.Container) error {
 	}
 	return nil
 }
+
+func LoadContainerEnvironment(container *libcontainer.Container) error {
+	os.Clearenv()
+	for _, pair := range container.Env {
+		p := strings.SplitN(pair, "=", 2)
+		if err := os.Setenv(p[0], p[1]); err != nil {
+			return err
+		}
+	}
+	return nil
+}

+ 0 - 22
pkg/libcontainer/nsinit/nsinit.go

@@ -1,22 +0,0 @@
-package nsinit
-
-import "github.com/dotcloud/docker/pkg/libcontainer"
-
-// NsInit is an interface with the public facing methods to provide high level
-// exec operations on a container
-type NsInit interface {
-	Exec(container *libcontainer.Container, term Terminal, pidRoot string, args []string, startCallback func()) (int, error)
-	ExecIn(container *libcontainer.Container, nspid int, args []string) (int, error)
-	Init(container *libcontainer.Container, uncleanRootfs, console string, syncPipe *SyncPipe, args []string) error
-}
-
-type linuxNs struct {
-	root           string
-	commandFactory CommandFactory
-}
-
-func NewNsInit(command CommandFactory) NsInit {
-	return &linuxNs{
-		commandFactory: command,
-	}
-}

+ 29 - 45
pkg/libcontainer/nsinit/nsinit/main.go

@@ -2,7 +2,6 @@ package main
 
 import (
 	"encoding/json"
-	"flag"
 	"io/ioutil"
 	"log"
 	"os"
@@ -14,76 +13,65 @@ import (
 )
 
 var (
-	root, console, logs string
-	pipeFd              int
+	dataPath  = os.Getenv("data_path")
+	console   = os.Getenv("console")
+	rawPipeFd = os.Getenv("pipe")
 )
 
-func registerFlags() {
-	flag.StringVar(&console, "console", "", "console (pty slave) path")
-	flag.IntVar(&pipeFd, "pipe", 0, "sync pipe fd")
-	flag.StringVar(&root, "root", ".", "root for storing configuration data")
-	flag.StringVar(&logs, "log", "none", "set stderr or a filepath to enable logging")
-
-	flag.Parse()
-}
-
 func main() {
-	registerFlags()
-
-	if flag.NArg() < 1 {
-		log.Fatalf("wrong number of arguments %d", flag.NArg())
-	}
-	container, err := loadContainer()
-	if err != nil {
-		log.Fatalf("Unable to load container: %s", err)
+	if len(os.Args) < 2 {
+		log.Fatalf("invalid number of arguments %d", len(os.Args))
 	}
 
-	ns, err := newNsInit()
+	container, err := loadContainer()
 	if err != nil {
-		log.Fatalf("Unable to initialize nsinit: %s", err)
+		log.Fatalf("unable to load container: %s", err)
 	}
 
-	switch flag.Arg(0) {
+	switch os.Args[1] {
 	case "exec": // this is executed outside of the namespace in the cwd
-		var exitCode int
-		nspid, err := readPid()
-		if err != nil {
-			if !os.IsNotExist(err) {
-				log.Fatalf("Unable to read pid: %s", err)
-			}
+		var nspid, exitCode int
+		if nspid, err = readPid(); err != nil && !os.IsNotExist(err) {
+			log.Fatalf("unable to read pid: %s", err)
 		}
+
 		if nspid > 0 {
-			exitCode, err = ns.ExecIn(container, nspid, flag.Args()[1:])
+			exitCode, err = nsinit.ExecIn(container, nspid, os.Args[2:])
 		} else {
 			term := nsinit.NewTerminal(os.Stdin, os.Stdout, os.Stderr, container.Tty)
-			exitCode, err = ns.Exec(container, term, root, flag.Args()[1:], nil)
+			exitCode, err = nsinit.Exec(container, term, "", dataPath, os.Args[2:], nil)
 		}
+
 		if err != nil {
-			log.Fatalf("Failed to exec: %s", err)
+			log.Fatalf("failed to exec: %s", err)
 		}
 		os.Exit(exitCode)
 	case "init": // this is executed inside of the namespace to setup the container
-		cwd, err := os.Getwd()
+		// by default our current dir is always our rootfs
+		rootfs, err := os.Getwd()
 		if err != nil {
 			log.Fatal(err)
 		}
-		if flag.NArg() < 2 {
-			log.Fatalf("wrong number of arguments %d", flag.NArg())
+
+		pipeFd, err := strconv.Atoi(rawPipeFd)
+		if err != nil {
+			log.Fatal(err)
 		}
 		syncPipe, err := nsinit.NewSyncPipeFromFd(0, uintptr(pipeFd))
 		if err != nil {
-			log.Fatalf("Unable to create sync pipe: %s", err)
+			log.Fatalf("unable to create sync pipe: %s", err)
 		}
-		if err := ns.Init(container, cwd, console, syncPipe, flag.Args()[1:]); err != nil {
-			log.Fatalf("Unable to initialize for container: %s", err)
+
+		if err := nsinit.Init(container, rootfs, console, syncPipe, os.Args[2:]); err != nil {
+			log.Fatalf("unable to initialize for container: %s", err)
 		}
 	default:
-		log.Fatalf("command not supported for nsinit %s", flag.Arg(0))
+		log.Fatalf("command not supported for nsinit %s", os.Args[0])
 	}
 }
 
 func loadContainer() (*libcontainer.Container, error) {
-	f, err := os.Open(filepath.Join(root, "container.json"))
+	f, err := os.Open(filepath.Join(dataPath, "container.json"))
 	if err != nil {
 		return nil, err
 	}
@@ -97,7 +85,7 @@ func loadContainer() (*libcontainer.Container, error) {
 }
 
 func readPid() (int, error) {
-	data, err := ioutil.ReadFile(filepath.Join(root, "pid"))
+	data, err := ioutil.ReadFile(filepath.Join(dataPath, "pid"))
 	if err != nil {
 		return -1, err
 	}
@@ -107,7 +95,3 @@ func readPid() (int, error) {
 	}
 	return pid, nil
 }
-
-func newNsInit() (nsinit.NsInit, error) {
-	return nsinit.NewNsInit(&nsinit.DefaultCommandFactory{root}), nil
-}

+ 0 - 12
pkg/libcontainer/nsinit/unsupported.go

@@ -6,18 +6,6 @@ import (
 	"github.com/dotcloud/docker/pkg/libcontainer"
 )
 
-func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, pidRoot string, args []string, startCallback func()) (int, error) {
-	return -1, libcontainer.ErrUnsupported
-}
-
-func (ns *linuxNs) ExecIn(container *libcontainer.Container, nspid int, args []string) (int, error) {
-	return -1, libcontainer.ErrUnsupported
-}
-
-func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, console string, syncPipe *SyncPipe, args []string) error {
-	return libcontainer.ErrUnsupported
-}
-
 func GetNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) {
 	return 0
 }