diff --git a/container.go b/container.go index f43341843..a0b4abea6 100644 --- a/container.go +++ b/container.go @@ -17,7 +17,6 @@ import ( "net" "os" "path" - "strconv" "strings" "sync" "syscall" @@ -563,34 +562,6 @@ func (container *Container) Start() (err error) { return err } - var lxcStart string = "lxc-start" - if container.hostConfig.Privileged && container.runtime.capabilities.AppArmor { - lxcStart = path.Join(container.runtime.config.Root, "lxc-start-unconfined") - } - - params := []string{ - lxcStart, - "-n", container.ID, - "-f", container.lxcConfigPath(), - "--", - "/.dockerinit", - } - - // Networking - if !container.Config.NetworkDisabled { - network := container.NetworkSettings - params = append(params, - "-g", network.Gateway, - "-i", fmt.Sprintf("%s/%d", network.IPAddress, network.IPPrefixLen), - "-mtu", strconv.Itoa(container.runtime.config.Mtu), - ) - } - - // User - if container.Config.User != "" { - params = append(params, "-u", container.Config.User) - } - // Setup environment env := []string{ "HOME=/", @@ -602,10 +573,6 @@ func (container *Container) Start() (err error) { env = append(env, "TERM=xterm") } - if container.hostConfig.Privileged { - params = append(params, "-privileged") - } - // Init any links between the parent and children runtime := container.runtime @@ -661,31 +628,25 @@ func (container *Container) Start() (err error) { if err := os.MkdirAll(path.Join(container.RootfsPath(), workingDir), 0755); err != nil { return nil } - - params = append(params, - "-w", workingDir, - ) } - // Program - params = append(params, "--", container.Path) - params = append(params, container.Args...) + /* + if RootIsShared() { + // lxc-start really needs / to be non-shared, or all kinds of stuff break + // when lxc-start unmount things and those unmounts propagate to the main + // mount namespace. + // What we really want is to clone into a new namespace and then + // mount / MS_REC|MS_SLAVE, but since we can't really clone or fork + // without exec in go we have to do this horrible shell hack... + shellString := + "mount --make-rslave /; exec " + + utils.ShellQuoteArguments(params) - if RootIsShared() { - // lxc-start really needs / to be non-shared, or all kinds of stuff break - // when lxc-start unmount things and those unmounts propagate to the main - // mount namespace. - // What we really want is to clone into a new namespace and then - // mount / MS_REC|MS_SLAVE, but since we can't really clone or fork - // without exec in go we have to do this horrible shell hack... - shellString := - "mount --make-rslave /; exec " + - utils.ShellQuoteArguments(params) - - params = []string{ - "unshare", "-m", "--", "/bin/sh", "-c", shellString, + params = []string{ + "unshare", "-m", "--", "/bin/sh", "-c", shellString, + } } - } + */ root := container.RootfsPath() envPath, err := container.EnvConfigPath() diff --git a/execdriver/driver.go b/execdriver/driver.go index 94905a7b0..a7d095bda 100644 --- a/execdriver/driver.go +++ b/execdriver/driver.go @@ -10,6 +10,7 @@ type Driver interface { Start(c *Process) error Kill(c *Process, sig int) error Wait(id string, duration time.Duration) error // Wait on an out of process option - lxc ghosts + Version() string } // Network settings of the container diff --git a/execdriver/lxc/driver.go b/execdriver/lxc/driver.go index 62b60deb6..8a10c77a4 100644 --- a/execdriver/lxc/driver.go +++ b/execdriver/lxc/driver.go @@ -4,7 +4,9 @@ import ( "errors" "fmt" "github.com/dotcloud/docker/execdriver" + "os" "os/exec" + "path" "strconv" "strings" "time" @@ -17,21 +19,21 @@ const ( var ( ErrNotRunning = errors.New("Process could not be started") ErrWaitTimeoutReached = errors.New("Wait timeout reached") - Debug bool ) -func init() { - // Register driver -} - type driver struct { - root string // root path for the driver to use + root string // root path for the driver to use + apparmor bool } -func NewDriver(root string) (execdriver.Driver, error) { +func NewDriver(root string, apparmor bool) (execdriver.Driver, error) { // setup unconfined symlink + if err := linkLxcStart(root); err != nil { + return nil, err + } return &driver{ - root: root, + apparmor: apparmor, + root: root, }, nil } @@ -57,6 +59,10 @@ func (d *driver) Start(c *execdriver.Process) error { } if c.Privileged { + if d.apparmor { + params[0] = path.Join(d.root, "lxc-start-unconfined") + + } params = append(params, "-privileged") } @@ -120,6 +126,17 @@ func (d *driver) Wait(id string, duration time.Duration) error { return nil } +func (d *driver) Version() string { + version := "" + if output, err := exec.Command("lxc-version").CombinedOutput(); err == nil { + outputStr := string(output) + if len(strings.SplitN(outputStr, ":", 2)) == 2 { + version = strings.TrimSpace(strings.SplitN(outputStr, ":", 2)[1]) + } + } + return version +} + func (d *driver) kill(c *execdriver.Process, sig int) error { output, err := exec.Command("lxc-kill", "-n", c.ID, strconv.Itoa(sig)).CombinedOutput() if err != nil { @@ -184,3 +201,20 @@ func (d *driver) waitLxc(id string, kill *bool) <-chan error { func (d *driver) getInfo(c *execdriver.Process) ([]byte, error) { return exec.Command("lxc-info", "-s", "-n", c.ID).CombinedOutput() } + +func linkLxcStart(root string) error { + sourcePath, err := exec.LookPath("lxc-start") + if err != nil { + return err + } + targetPath := path.Join(root, "lxc-start-unconfined") + + if _, err := os.Lstat(targetPath); err != nil && !os.IsNotExist(err) { + return err + } else if err == nil { + if err := os.Remove(targetPath); err != nil { + return err + } + } + return os.Symlink(sourcePath, targetPath) +} diff --git a/integration/utils_test.go b/integration/utils_test.go index 4ab1c96cc..63ac3a44b 100644 --- a/integration/utils_test.go +++ b/integration/utils_test.go @@ -38,7 +38,6 @@ func mkRuntime(f utils.Fataler) *docker.Runtime { if err != nil { f.Fatal(err) } - r.UpdateCapabilities(true) return r } diff --git a/runtime.go b/runtime.go index 432e28ea0..b1644b985 100644 --- a/runtime.go +++ b/runtime.go @@ -334,8 +334,8 @@ func (runtime *Runtime) restore() error { return nil } -// FIXME: comment please! -func (runtime *Runtime) UpdateCapabilities(quiet bool) { +func NewRuntimeCapabilities(quiet bool) *Capabilities { + capabilities := &Capabilities{} if cgroupMemoryMountpoint, err := cgroups.FindCgroupMountpoint("memory"); err != nil { if !quiet { log.Printf("WARNING: %s\n", err) @@ -343,32 +343,33 @@ func (runtime *Runtime) UpdateCapabilities(quiet bool) { } else { _, err1 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.limit_in_bytes")) _, err2 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.soft_limit_in_bytes")) - runtime.capabilities.MemoryLimit = err1 == nil && err2 == nil - if !runtime.capabilities.MemoryLimit && !quiet { + capabilities.MemoryLimit = err1 == nil && err2 == nil + if !capabilities.MemoryLimit && !quiet { log.Printf("WARNING: Your kernel does not support cgroup memory limit.") } _, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.memsw.limit_in_bytes")) - runtime.capabilities.SwapLimit = err == nil - if !runtime.capabilities.SwapLimit && !quiet { + capabilities.SwapLimit = err == nil + if !capabilities.SwapLimit && !quiet { log.Printf("WARNING: Your kernel does not support cgroup swap limit.") } } content, err3 := ioutil.ReadFile("/proc/sys/net/ipv4/ip_forward") - runtime.capabilities.IPv4ForwardingDisabled = err3 != nil || len(content) == 0 || content[0] != '1' - if runtime.capabilities.IPv4ForwardingDisabled && !quiet { + capabilities.IPv4ForwardingDisabled = err3 != nil || len(content) == 0 || content[0] != '1' + if capabilities.IPv4ForwardingDisabled && !quiet { log.Printf("WARNING: IPv4 forwarding is disabled.") } // Check if AppArmor seems to be enabled on this system. if _, err := os.Stat("/sys/kernel/security/apparmor"); os.IsNotExist(err) { utils.Debugf("/sys/kernel/security/apparmor not found; assuming AppArmor is not enabled.") - runtime.capabilities.AppArmor = false + capabilities.AppArmor = false } else { utils.Debugf("/sys/kernel/security/apparmor found; assuming AppArmor is enabled.") - runtime.capabilities.AppArmor = true + capabilities.AppArmor = true } + return capabilities } // Create creates a new container from the given configuration with a given name. @@ -649,7 +650,6 @@ func NewRuntime(config *DaemonConfig) (*Runtime, error) { if err != nil { return nil, err } - runtime.UpdateCapabilities(false) return runtime, nil } @@ -678,10 +678,6 @@ func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) { } } - utils.Debugf("Escaping AppArmor confinement") - if err := linkLxcStart(config.Root); err != nil { - return nil, err - } utils.Debugf("Creating images graph") g, err := NewGraph(path.Join(config.Root, "graph"), driver) if err != nil { @@ -738,7 +734,8 @@ func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) { sysInitPath = localCopy } - ed, err := lxc.NewDriver("") + capabilities := NewRuntimeCapabilities(false) + ed, err := lxc.NewDriver(config.Root, capabilities.AppArmor) if err != nil { return nil, err } @@ -750,7 +747,7 @@ func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) { graph: g, repositories: repositories, idIndex: utils.NewTruncIndex(), - capabilities: &Capabilities{}, + capabilities: capabilities, volumes: volumes, config: config, containerGraph: graph, @@ -869,23 +866,6 @@ func (runtime *Runtime) Nuke() error { return os.RemoveAll(runtime.config.Root) } -func linkLxcStart(root string) error { - sourcePath, err := exec.LookPath("lxc-start") - if err != nil { - return err - } - targetPath := path.Join(root, "lxc-start-unconfined") - - if _, err := os.Lstat(targetPath); err != nil && !os.IsNotExist(err) { - return err - } else if err == nil { - if err := os.Remove(targetPath); err != nil { - return err - } - } - return os.Symlink(sourcePath, targetPath) -} - // FIXME: this is a convenience function for integration tests // which need direct access to runtime.graph. // Once the tests switch to using engine and jobs, this method diff --git a/server.go b/server.go index 3892ba70e..a9c83575e 100644 --- a/server.go +++ b/server.go @@ -661,13 +661,6 @@ func (srv *Server) DockerInfo(job *engine.Job) engine.Status { } else { imgcount = len(images) } - lxcVersion := "" - if output, err := exec.Command("lxc-version").CombinedOutput(); err == nil { - outputStr := string(output) - if len(strings.SplitN(outputStr, ":", 2)) == 2 { - lxcVersion = strings.TrimSpace(strings.SplitN(string(output), ":", 2)[1]) - } - } kernelVersion := "" if kv, err := utils.GetKernelVersion(); err == nil { kernelVersion = kv.String() @@ -691,7 +684,7 @@ func (srv *Server) DockerInfo(job *engine.Job) engine.Status { v.SetBool("Debug", os.Getenv("DEBUG") != "") v.SetInt("NFd", utils.GetTotalUsedFds()) v.SetInt("NGoroutines", runtime.NumGoroutine()) - v.Set("LXCVersion", lxcVersion) + v.Set("LXCVersion", srv.runtime.execDriver.Version()) v.SetInt("NEventsListener", len(srv.events)) v.Set("KernelVersion", kernelVersion) v.Set("IndexServerAddress", auth.IndexServerAddress())