// resetContainer resets the container's IO and ensures that the command is able to be executed again // by copying the data into a new struct // if lock is true, then container locked during reset func (m *containerMonitor) resetContainer(lock bool) { container := m.container if lock { container.Lock() defer container.Unlock() } if err := container.CloseStreams(); err != nil { logrus.Errorf("%s: %s", container.ID, err) } if container.Command != nil && container.Command.ProcessConfig.Terminal != nil { if err := container.Command.ProcessConfig.Terminal.Close(); err != nil { logrus.Errorf("%s: Error closing terminal: %s", container.ID, err) } } // Re-create a brand new stdin pipe once the container exited if container.Config.OpenStdin { container.NewInputPipes() } if container.LogDriver != nil { if container.LogCopier != nil { exit := make(chan struct{}) go func() { container.LogCopier.Wait() close(exit) }() select { case <-time.After(loggerCloseTimeout): logrus.Warnf("Logger didn't exit in time: logs may be truncated") case <-exit: } } container.LogDriver.Close() container.LogCopier = nil container.LogDriver = nil } c := container.Command.ProcessConfig.Cmd container.Command.ProcessConfig.Cmd = exec.Cmd{ Stdin: c.Stdin, Stdout: c.Stdout, Stderr: c.Stderr, Path: c.Path, Env: c.Env, ExtraFiles: c.ExtraFiles, Args: c.Args, Dir: c.Dir, SysProcAttr: c.SysProcAttr, } }
func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) error { if hostConfig == nil { return nil } container, err := daemon.GetContainer(name) if err != nil { return err } restoreConfig := false backupHostConfig := *container.HostConfig defer func() { if restoreConfig { container.Lock() container.HostConfig = &backupHostConfig container.ToDisk() container.Unlock() } }() if container.RemovalInProgress || container.Dead { return errCannotUpdate(container.ID, fmt.Errorf("Container is marked for removal and cannot be \"update\".")) } if err := container.UpdateContainer(hostConfig); err != nil { restoreConfig = true return errCannotUpdate(container.ID, err) } // if Restart Policy changed, we need to update container monitor if hostConfig.RestartPolicy.Name != "" { container.UpdateMonitor(hostConfig.RestartPolicy) } // If container is not running, update hostConfig struct is enough, // resources will be updated when the container is started again. // If container is running (including paused), we need to update configs // to the real world. if container.IsRunning() && !container.IsRestarting() { if err := daemon.containerd.UpdateResources(container.ID, toContainerdResources(hostConfig.Resources)); err != nil { restoreConfig = true return errCannotUpdate(container.ID, err) } } daemon.LogContainerEvent(container, "update") return nil }