diff --git a/container.go b/container.go index 8c9863c0a4..6898ada24f 100644 --- a/container.go +++ b/container.go @@ -54,7 +54,7 @@ type Container struct { Name string Driver string - process *execdriver.Process + command *execdriver.Command stdout *utils.WriteBroadcaster stderr *utils.WriteBroadcaster stdin io.ReadCloser @@ -307,8 +307,8 @@ func (container *Container) setupPty() error { return err } container.ptyMaster = ptyMaster - container.process.Stdout = ptySlave - container.process.Stderr = ptySlave + container.command.Stdout = ptySlave + container.command.Stderr = ptySlave // Copy the PTYs to our broadcasters go func() { @@ -320,8 +320,8 @@ func (container *Container) setupPty() error { // stdin if container.Config.OpenStdin { - container.process.Stdin = ptySlave - container.process.SysProcAttr.Setctty = true + container.command.Stdin = ptySlave + container.command.SysProcAttr.Setctty = true go func() { defer container.stdin.Close() utils.Debugf("startPty: begin of stdin pipe") @@ -333,10 +333,10 @@ func (container *Container) setupPty() error { } func (container *Container) setupStd() error { - container.process.Stdout = container.stdout - container.process.Stderr = container.stderr + container.command.Stdout = container.stdout + container.command.Stderr = container.stderr if container.Config.OpenStdin { - stdin, err := container.process.StdinPipe() + stdin, err := container.command.StdinPipe() if err != nil { return err } @@ -494,6 +494,49 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s }) } +func populateCommand(c *Container) { + var ( + en *execdriver.Network + driverConfig []string + ) + if !c.Config.NetworkDisabled { + network := c.NetworkSettings + en = &execdriver.Network{ + Gateway: network.Gateway, + Bridge: network.Bridge, + IPAddress: network.IPAddress, + IPPrefixLen: network.IPPrefixLen, + Mtu: c.runtime.config.Mtu, + } + } + + if lxcConf := c.hostConfig.LxcConf; lxcConf != nil { + for _, pair := range lxcConf { + driverConfig = append(driverConfig, fmt.Sprintf("%s = %s", pair.Key, pair.Value)) + } + } + resources := &execdriver.Resources{ + Memory: c.Config.Memory, + MemorySwap: c.Config.MemorySwap, + CpuShares: c.Config.CpuShares, + } + c.command = &execdriver.Command{ + ID: c.ID, + Privileged: c.hostConfig.Privileged, + Rootfs: c.RootfsPath(), + InitPath: "/.dockerinit", + Entrypoint: c.Path, + Arguments: c.Args, + WorkingDir: c.Config.WorkingDir, + Network: en, + Tty: c.Config.Tty, + User: c.Config.User, + Config: driverConfig, + Resources: resources, + } + c.command.SysProcAttr = &syscall.SysProcAttr{Setsid: true} +} + func (container *Container) Start() (err error) { container.Lock() defer container.Unlock() @@ -605,15 +648,15 @@ func (container *Container) Start() (err error) { return err } - var workingDir string + root := container.RootfsPath() + if container.Config.WorkingDir != "" { - workingDir = path.Clean(container.Config.WorkingDir) - if err := os.MkdirAll(path.Join(container.RootfsPath(), workingDir), 0755); err != nil { + container.Config.WorkingDir = path.Clean(container.Config.WorkingDir) + if err := os.MkdirAll(path.Join(root, container.Config.WorkingDir), 0755); err != nil { return nil } } - root := container.RootfsPath() envPath, err := container.EnvConfigPath() if err != nil { return err @@ -658,48 +701,7 @@ func (container *Container) Start() (err error) { } } - var ( - en *execdriver.Network - driverConfig []string - ) - - if !container.Config.NetworkDisabled { - network := container.NetworkSettings - en = &execdriver.Network{ - Gateway: network.Gateway, - Bridge: network.Bridge, - IPAddress: network.IPAddress, - IPPrefixLen: network.IPPrefixLen, - Mtu: container.runtime.config.Mtu, - } - } - - if lxcConf := container.hostConfig.LxcConf; lxcConf != nil { - for _, pair := range lxcConf { - driverConfig = append(driverConfig, fmt.Sprintf("%s = %s", pair.Key, pair.Value)) - } - } - resources := &execdriver.Resources{ - Memory: container.Config.Memory, - MemorySwap: container.Config.MemorySwap, - CpuShares: container.Config.CpuShares, - } - - container.process = &execdriver.Process{ - ID: container.ID, - Privileged: container.hostConfig.Privileged, - Rootfs: root, - InitPath: "/.dockerinit", - Entrypoint: container.Path, - Arguments: container.Args, - WorkingDir: workingDir, - Network: en, - Tty: container.Config.Tty, - User: container.Config.User, - Config: driverConfig, - Resources: resources, - } - container.process.SysProcAttr = &syscall.SysProcAttr{Setsid: true} + populateCommand(container) // Setup logging of stdout and stderr to disk if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil { @@ -722,13 +724,13 @@ func (container *Container) Start() (err error) { } callbackLock := make(chan struct{}) - callback := func(process *execdriver.Process) { - container.State.SetRunning(process.Pid()) - if process.Tty { + callback := func(command *execdriver.Command) { + container.State.SetRunning(command.Pid()) + if command.Tty { // The callback is called after the process Start() // so we are in the parent process. In TTY mode, stdin/out/err is the PtySlace // which we close here. - if c, ok := process.Stdout.(io.Closer); ok { + if c, ok := command.Stdout.(io.Closer); ok { c.Close() } } @@ -1134,9 +1136,10 @@ func (container *Container) monitor(callback execdriver.StartCallback) error { exitCode int ) - if container.process == nil { + if container.command == nil { // This happends when you have a GHOST container with lxc - err = container.runtime.WaitGhost(container) + populateCommand(container) + err = container.runtime.RestoreCommand(container) } else { exitCode, err = container.runtime.Run(container, callback) } @@ -1228,7 +1231,7 @@ func (container *Container) Kill() error { // 2. Wait for the process to die, in last resort, try to kill the process directly if err := container.WaitTimeout(10 * time.Second); err != nil { - if container.process == nil { + if container.command == nil { return fmt.Errorf("lxc-kill failed, impossible to kill the container %s", utils.TruncateID(container.ID)) } log.Printf("Container %s failed to exit within 10 seconds of lxc-kill %s - trying direct SIGKILL", "SIGKILL", utils.TruncateID(container.ID)) diff --git a/execdriver/chroot/driver.go b/execdriver/chroot/driver.go index 749926edf7..4b2e02904e 100644 --- a/execdriver/chroot/driver.go +++ b/execdriver/chroot/driver.go @@ -36,7 +36,7 @@ func NewDriver() (*driver, error) { return &driver{}, nil } -func (d *driver) Run(c *execdriver.Process, startCallback execdriver.StartCallback) (int, error) { +func (d *driver) Run(c *execdriver.Command, startCallback execdriver.StartCallback) (int, error) { params := []string{ "chroot", c.Rootfs, @@ -70,11 +70,11 @@ func (d *driver) Run(c *execdriver.Process, startCallback execdriver.StartCallba return c.GetExitCode(), err } -func (d *driver) Kill(p *execdriver.Process, sig int) error { +func (d *driver) Kill(p *execdriver.Command, sig int) error { return p.Process.Kill() } -func (d *driver) Wait(id string) error { +func (d *driver) Restore(c *execdriver.Command) error { panic("Not Implemented") } diff --git a/execdriver/driver.go b/execdriver/driver.go index b56404ee41..511e9e80c6 100644 --- a/execdriver/driver.go +++ b/execdriver/driver.go @@ -16,7 +16,7 @@ var ( var dockerInitFcts map[string]InitFunc type ( - StartCallback func(*Process) + StartCallback func(*Command) InitFunc func(i *InitArgs) error ) @@ -59,11 +59,11 @@ type Info interface { } type Driver interface { - Run(c *Process, startCallback StartCallback) (int, error) // Run executes the process and blocks until the process exits and returns the exit code - Kill(c *Process, sig int) error - Wait(id string) error // Wait on an out of process...process - lxc ghosts TODO: Rename to reattach, reconnect - Name() string // Driver name - Info(id string) Info // "temporary" hack (until we move state from core to plugins) + Run(c *Command, startCallback StartCallback) (int, error) // Run executes the process and blocks until the process exits and returns the exit code + Kill(c *Command, sig int) error + Restore(c *Command) error // Wait and try to re-attach on an out of process command + Name() string // Driver name + Info(id string) Info // "temporary" hack (until we move state from core to plugins) } // Network settings of the container @@ -83,8 +83,8 @@ type Resources struct { // Process wrapps an os/exec.Cmd to add more metadata // TODO: Rename to Command -type Process struct { - exec.Cmd +type Command struct { + exec.Cmd `json:"-"` ID string `json:"id"` Privileged bool `json:"privileged"` @@ -103,7 +103,7 @@ type Process struct { // Return the pid of the process // If the process is nil -1 will be returned -func (c *Process) Pid() int { +func (c *Command) Pid() int { if c.Process == nil { return -1 } @@ -112,7 +112,7 @@ func (c *Process) Pid() int { // Return the exit code of the process // if the process has not exited -1 will be returned -func (c *Process) GetExitCode() int { +func (c *Command) GetExitCode() int { if c.ProcessState == nil { return -1 } diff --git a/execdriver/lxc/driver.go b/execdriver/lxc/driver.go index 5999d5bab5..0e64dfd968 100644 --- a/execdriver/lxc/driver.go +++ b/execdriver/lxc/driver.go @@ -30,6 +30,7 @@ func init() { if err := setupCapabilities(args); err != nil { return err } + if err := setupWorkingDirectory(args); err != nil { return err } @@ -37,6 +38,7 @@ func init() { if err := changeUser(args); err != nil { return err } + path, err := exec.LookPath(args.Args[0]) if err != nil { log.Printf("Unable to locate %v", args.Args[0]) @@ -72,7 +74,7 @@ func (d *driver) Name() string { return fmt.Sprintf("%s-%s", DriverName, version) } -func (d *driver) Run(c *execdriver.Process, startCallback execdriver.StartCallback) (int, error) { +func (d *driver) Run(c *execdriver.Command, startCallback execdriver.StartCallback) (int, error) { configPath, err := d.generateLXCConfig(c) if err != nil { return -1, err @@ -170,13 +172,13 @@ func (d *driver) Run(c *execdriver.Process, startCallback execdriver.StartCallba return c.GetExitCode(), waitErr } -func (d *driver) Kill(c *execdriver.Process, sig int) error { +func (d *driver) Kill(c *execdriver.Command, sig int) error { return d.kill(c, sig) } -func (d *driver) Wait(id string) error { +func (d *driver) Restore(c *execdriver.Command) error { for { - output, err := exec.Command("lxc-info", "-n", id).CombinedOutput() + output, err := exec.Command("lxc-info", "-n", c.ID).CombinedOutput() if err != nil { return err } @@ -198,7 +200,7 @@ func (d *driver) version() string { return version } -func (d *driver) kill(c *execdriver.Process, sig int) error { +func (d *driver) kill(c *execdriver.Command, sig int) error { output, err := exec.Command("lxc-kill", "-n", c.ID, strconv.Itoa(sig)).CombinedOutput() if err != nil { return fmt.Errorf("Err: %s Output: %s", err, output) @@ -206,7 +208,7 @@ func (d *driver) kill(c *execdriver.Process, sig int) error { return nil } -func (d *driver) waitForStart(c *execdriver.Process, waitLock chan struct{}) error { +func (d *driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) error { var ( err error output []byte @@ -302,8 +304,8 @@ func rootIsShared() bool { return true } -func (d *driver) generateLXCConfig(p *execdriver.Process) (string, error) { - root := path.Join(d.root, "containers", p.ID, "config.lxc") +func (d *driver) generateLXCConfig(c *execdriver.Command) (string, error) { + root := path.Join(d.root, "containers", c.ID, "config.lxc") fo, err := os.Create(root) if err != nil { return "", err @@ -311,10 +313,10 @@ func (d *driver) generateLXCConfig(p *execdriver.Process) (string, error) { defer fo.Close() if err := LxcTemplateCompiled.Execute(fo, struct { - *execdriver.Process + *execdriver.Command AppArmor bool }{ - Process: p, + Command: c, AppArmor: d.apparmor, }); err != nil { return "", err diff --git a/execdriver/lxc/lxc_template_unit_test.go b/execdriver/lxc/lxc_template_unit_test.go index 0acf9645d2..99d6e636f5 100644 --- a/execdriver/lxc/lxc_template_unit_test.go +++ b/execdriver/lxc/lxc_template_unit_test.go @@ -37,14 +37,14 @@ func TestLXCConfig(t *testing.T) { if err != nil { t.Fatal(err) } - process := &execdriver.Process{ + command := &execdriver.Command{ ID: "1", Resources: &execdriver.Resources{ Memory: int64(mem), CpuShares: int64(cpu), }, } - p, err := driver.generateLXCConfig(process) + p, err := driver.generateLXCConfig(command) if err != nil { t.Fatal(err) } @@ -68,7 +68,7 @@ func TestCustomLxcConfig(t *testing.T) { if err != nil { t.Fatal(err) } - process := &execdriver.Process{ + command := &execdriver.Command{ ID: "1", Privileged: false, Config: []string{ @@ -77,7 +77,7 @@ func TestCustomLxcConfig(t *testing.T) { }, } - p, err := driver.generateLXCConfig(process) + p, err := driver.generateLXCConfig(command) if err != nil { t.Fatal(err) } diff --git a/runtime.go b/runtime.go index 1b17bac973..4eb6f476b0 100644 --- a/runtime.go +++ b/runtime.go @@ -817,15 +817,15 @@ func (runtime *Runtime) Diff(container *Container) (archive.Archive, error) { } func (runtime *Runtime) Run(c *Container, startCallback execdriver.StartCallback) (int, error) { - return runtime.execDriver.Run(c.process, startCallback) + return runtime.execDriver.Run(c.command, startCallback) } func (runtime *Runtime) Kill(c *Container, sig int) error { - return runtime.execDriver.Kill(c.process, sig) + return runtime.execDriver.Kill(c.command, sig) } -func (runtime *Runtime) WaitGhost(c *Container) error { - return runtime.execDriver.Wait(c.ID) +func (runtime *Runtime) RestoreCommand(c *Container) error { + return runtime.execDriver.Restore(c.command) } // Nuke kills all containers then removes all content diff --git a/sysinit/sysinit.go b/sysinit/sysinit.go index af69795cb6..dcf0eddf56 100644 --- a/sysinit/sysinit.go +++ b/sysinit/sysinit.go @@ -50,14 +50,16 @@ func SysInit() { os.Exit(1) } - // Get cmdline arguments - user := flag.String("u", "", "username or uid") - gateway := flag.String("g", "", "gateway address") - ip := flag.String("i", "", "ip address") - workDir := flag.String("w", "", "workdir") - privileged := flag.Bool("privileged", false, "privileged mode") - mtu := flag.Int("mtu", 1500, "interface mtu") - driver := flag.String("driver", "", "exec driver") + var ( + // Get cmdline arguments + user = flag.String("u", "", "username or uid") + gateway = flag.String("g", "", "gateway address") + ip = flag.String("i", "", "ip address") + workDir = flag.String("w", "", "workdir") + privileged = flag.Bool("privileged", false, "privileged mode") + mtu = flag.Int("mtu", 1500, "interface mtu") + driver = flag.String("driver", "", "exec driver") + ) flag.Parse() // Get env