diff --git a/components/engine/commands.go b/components/engine/commands.go index 85daeb6b8f..b2f49a080a 100644 --- a/components/engine/commands.go +++ b/components/engine/commands.go @@ -836,6 +836,10 @@ func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout rcli.DockerConn, args . return fmt.Errorf("No such container: %s", name) } + if container.State.Ghost { + return fmt.Errorf("Impossible to attach to a ghost container") + } + if container.Config.Tty { stdout.SetOptionRawTerminal() } diff --git a/components/engine/container.go b/components/engine/container.go index c2c6fddd40..bac0951da4 100644 --- a/components/engine/container.go +++ b/components/engine/container.go @@ -530,16 +530,42 @@ func (container *Container) releaseNetwork() { container.NetworkSettings = &NetworkSettings{} } +// FIXME: replace this with a control socket within docker-init +func (container *Container) waitLxc() error { + for { + if output, err := exec.Command("lxc-info", "-n", container.Id).CombinedOutput(); err != nil { + return err + } else { + if !strings.Contains(string(output), "RUNNING") { + return nil + } + } + time.Sleep(500 * time.Millisecond) + } + return nil +} + func (container *Container) monitor() { // Wait for the program to exit Debugf("Waiting for process") - if err := container.cmd.Wait(); err != nil { - // Discard the error as any signals or non 0 returns will generate an error - Debugf("%s: Process: %s", container.Id, err) + + // If the command does not exists, try to wait via lxc + if container.cmd == nil { + if err := container.waitLxc(); err != nil { + Debugf("%s: Process: %s", container.Id, err) + } + } else { + if err := container.cmd.Wait(); err != nil { + // Discard the error as any signals or non 0 returns will generate an error + Debugf("%s: Process: %s", container.Id, err) + } } Debugf("Process finished") - exitCode := container.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() + var exitCode int = -1 + if container.cmd != nil { + exitCode = container.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() + } // Cleanup container.releaseNetwork() @@ -588,7 +614,7 @@ func (container *Container) monitor() { } func (container *Container) kill() error { - if !container.State.Running || container.cmd == nil { + if !container.State.Running { return nil } @@ -600,6 +626,9 @@ 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.cmd == nil { + return fmt.Errorf("lxc-kill failed, impossible to kill the container %s", container.Id) + } log.Printf("Container %s failed to exit within 10 seconds of lxc SIGKILL - trying direct SIGKILL", container.Id) if err := container.cmd.Process.Kill(); err != nil { return err @@ -617,9 +646,6 @@ func (container *Container) Kill() error { if !container.State.Running { return nil } - if container.State.Ghost { - return fmt.Errorf("Can't kill ghost container") - } return container.kill() } @@ -629,9 +655,6 @@ func (container *Container) Stop(seconds int) error { if !container.State.Running { return nil } - if container.State.Ghost { - return fmt.Errorf("Can't stop ghost container") - } // 1. Send a SIGTERM if output, err := exec.Command("lxc-kill", "-n", container.Id, "15").CombinedOutput(); err != nil { diff --git a/components/engine/runtime.go b/components/engine/runtime.go index 1dfc22d632..d6eb0f3c91 100644 --- a/components/engine/runtime.go +++ b/components/engine/runtime.go @@ -184,12 +184,6 @@ func (runtime *Runtime) Register(container *Container) error { } } - // If the container is not running or just has been flagged not running - // then close the wait lock chan (will be reset upon start) - if !container.State.Running { - close(container.waitLock) - } - // Even if not running, we init the lock (prevents races in start/stop/kill) container.State.initLock() @@ -207,6 +201,15 @@ func (runtime *Runtime) Register(container *Container) error { // done runtime.containers.PushBack(container) runtime.idIndex.Add(container.Id) + + // If the container is not running or just has been flagged not running + // then close the wait lock chan (will be reset upon start) + if !container.State.Running { + close(container.waitLock) + } else { + container.allocateNetwork() + go container.monitor() + } return nil }