// register makes a container object usable by the daemon as <container.ID> func (daemon *Daemon) register(container *Container, updateSuffixarray bool) error { if container.daemon != nil || daemon.Exists(container.ID) { return fmt.Errorf("Container is already loaded") } if err := validateID(container.ID); err != nil { return err } if err := daemon.ensureName(container); err != nil { return err } container.daemon = daemon // Attach to stdout and stderr container.stderr = broadcastwriter.New() container.stdout = broadcastwriter.New() // Attach to stdin if container.Config.OpenStdin { container.stdin, container.stdinPipe = io.Pipe() } else { container.stdinPipe = ioutils.NopWriteCloser(ioutil.Discard) // Silently drop stdin } // done daemon.containers.Add(container.ID, container) // don't update the Suffixarray if we're starting up // we'll waste time if we update it for every container daemon.idIndex.Add(container.ID) // FIXME: if the container is supposed to be running but is not, auto restart it? // if so, then we need to restart monitor and init a new lock // If the container is supposed to be running, make sure of it if container.IsRunning() { log.Debugf("killing old running container %s", container.ID) existingPid := container.Pid container.SetStopped(&execdriver.ExitStatus{ExitCode: 0}) // We only have to handle this for lxc because the other drivers will ensure that // no processes are left when docker dies if container.ExecDriver == "" || strings.Contains(container.ExecDriver, "lxc") { lxc.KillLxc(container.ID, 9) } else { // use the current driver and ensure that the container is dead x.x cmd := &execdriver.Command{ ID: container.ID, } var err error cmd.ProcessConfig.Process, err = os.FindProcess(existingPid) if err != nil { log.Debugf("cannot find existing process for %d", existingPid) } daemon.execDriver.Terminate(cmd) } if err := container.Unmount(); err != nil { log.Debugf("unmount error %s", err) } if err := container.ToDisk(); err != nil { log.Debugf("saving stopped state to disk %s", err) } info := daemon.execDriver.Info(container.ID) if !info.IsRunning() { log.Debugf("Container %s was supposed to be running but is not.", container.ID) log.Debugf("Marking as stopped") container.SetStopped(&execdriver.ExitStatus{ExitCode: -127}) if err := container.ToDisk(); err != nil { return err } } } return nil }
// register makes a container object usable by the daemon as <container.ID> func (daemon *Daemon) register(container *Container, updateSuffixarray bool) error { if container.daemon != nil || daemon.Exists(container.ID) { return fmt.Errorf("Container is already loaded") } if err := validateID(container.ID); err != nil { return err } if err := daemon.ensureName(container); err != nil { return err } container.daemon = daemon // Attach to stdout and stderr container.stderr = broadcastwriter.New() container.stdout = broadcastwriter.New() // Attach to stdin if container.Config.OpenStdin { container.stdin, container.stdinPipe = io.Pipe() } else { container.stdinPipe = ioutils.NopWriteCloser(ioutil.Discard) // Silently drop stdin } // done daemon.containers.Add(container.ID, container) // don't update the Suffixarray if we're starting up // we'll waste time if we update it for every container daemon.idIndex.Add(container.ID) // FIXME: if the container is supposed to be running but is not, auto restart it? // if so, then we need to restart monitor and init a new lock // If the container is supposed to be running, make sure of it if container.IsRunning() { if container.MonitorDriver == MonitorBuiltin { log.Debugf("killing old running container %s", container.ID) existingPid := container.Pid container.SetStopped(0) // We only have to handle this for lxc because the other drivers will ensure that // no processes are left when docker dies if container.ExecDriver == "" || strings.Contains(container.ExecDriver, "lxc") { lxc.KillLxc(container.ID, 9) } else { // use the current driver and ensure that the container is dead x.x cmd := &execdriver.Command{ ID: container.ID, } var err error cmd.ProcessConfig.Process, err = os.FindProcess(existingPid) if err != nil { log.Debugf("cannot find existing process for %d", existingPid) } daemon.execDriver.Terminate(cmd) } if err := container.Unmount(); err != nil { log.Debugf("unmount error %s", err) } if err := container.ToDisk(); err != nil { log.Debugf("saving stopped state to disk %s", err) } info := daemon.execDriver.Info(container.ID) if !info.IsRunning() { log.Debugf("Container %s was supposed to be running but is not.", container.ID) log.Debugf("Marking as stopped") container.SetStopped(-127) if err := container.ToDisk(); err != nil { return err } } } else { // restore external container log.Debugf("restore external container: %s", container.ID) _, err := container.daemon.callMonitorAPI(container, "GET", "_ping") if err != nil { log.Errorf("Call monitor _ping API failed: %v, mark container %s stopped", err, container.ID) // Think monitor is down, mark container is down container.SetStopped(-125) if err := container.ToDisk(); err != nil { return err } } else { obj, err := container.daemon.callMonitorAPI(container, "GET", "state") if err != nil { log.Errorf("Call monitor state API failed: %v", err) return err } m := make(map[string]*WatchState) if err = json.Unmarshal(obj, &m); err != nil { log.Errorf("Decode WatchState error: %v", err) return err } ws := m["WatchState"] log.Debugf("WatchState %v", ws) if !ws.Running { log.Errorf("Container %s is supposed be running, but not running in monitor, mark it stopped", container.ID) container.SetStopped(-125) if err = container.ToDisk(); err != nil { return err } // kill monitor server if err = syscall.Kill(container.monitorState.Pid, syscall.SIGTERM); err != nil { log.Errorf("kill monitor server with pid %v error: %v", container.monitorState.Pid, err) return err } // write monitor state container.monitorState.SetStopped(0) if err = container.WriteMonitorState(); err != nil { log.Errorf("write monitor state error: %v", err) return err } } else { // external container is running // register to graph driver if err := container.daemon.driver.Register(container.ID); err != nil { log.Errorf("register container to graph driver error: %v", err) } monitor := NewMonitorProxy(container, false) container.exMonitor = monitor if err := monitor.RunStatePoller(); err != nil { log.Errorf("Container %s run StatePoll failed: %v", container.ID, err) return err } } } } } return nil }