mirror of
https://github.com/containers/podman.git
synced 2025-08-06 11:32:07 +08:00
Implement container restarting
Signed-off-by: Matthew Heon <matthew.heon@gmail.com> Closes: #482 Approved by: baude
This commit is contained in:
@ -104,8 +104,18 @@ func startCmd(c *cli.Context) error {
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to parse annotations in %s", ctr.ID())
|
||||
}
|
||||
err = ctr.Start()
|
||||
if err != nil {
|
||||
if lastError != nil {
|
||||
fmt.Fprintln(os.Stderr, lastError)
|
||||
}
|
||||
lastError = errors.Wrapf(err, "unable to start %s", container)
|
||||
continue
|
||||
}
|
||||
// We only get a terminal session if both a tty was specified in the spec and
|
||||
// -a on the command-line was given.
|
||||
// Must be done after Start() because we might be restarting
|
||||
// If so, the attach socket might be removed & recreated
|
||||
if attach && tty {
|
||||
// We increment the wg counter because we need to do the attach
|
||||
wg.Add(1)
|
||||
@ -121,14 +131,6 @@ func startCmd(c *cli.Context) error {
|
||||
return errors.Errorf("unable to attach to container %s", ctr.ID())
|
||||
}
|
||||
}
|
||||
err = ctr.Start()
|
||||
if err != nil {
|
||||
if lastError != nil {
|
||||
fmt.Fprintln(os.Stderr, lastError)
|
||||
}
|
||||
lastError = errors.Wrapf(err, "unable to start %s", container)
|
||||
continue
|
||||
}
|
||||
if !attach {
|
||||
fmt.Println(ctr.ID())
|
||||
}
|
||||
@ -141,7 +143,11 @@ func startCmd(c *cli.Context) error {
|
||||
if lastError != nil {
|
||||
fmt.Fprintln(os.Stderr, lastError)
|
||||
}
|
||||
lastError = ctr.Cleanup()
|
||||
// We can only do this if we attached
|
||||
// Otherwise the container is probably still running
|
||||
if attach && tty {
|
||||
lastError = ctr.Cleanup()
|
||||
}
|
||||
}
|
||||
return lastError
|
||||
}
|
||||
|
@ -106,8 +106,6 @@ type Container struct {
|
||||
runtime *Runtime
|
||||
}
|
||||
|
||||
// TODO fetch IP and Subnet Mask from networks once we have updated OCICNI
|
||||
|
||||
// containerState contains the current state of the container
|
||||
// It is stored on disk in a tmpfs and recreated on reboot
|
||||
type containerState struct {
|
||||
|
@ -63,6 +63,9 @@ func (c *Container) Init() (err error) {
|
||||
}
|
||||
|
||||
// Start starts a container
|
||||
// Start can start created or stopped containers
|
||||
// Stopped containers will be deleted and re-created in runc, undergoing a fresh
|
||||
// Init()
|
||||
func (c *Container) Start() (err error) {
|
||||
if !c.locked {
|
||||
c.lock.Lock()
|
||||
@ -78,11 +81,6 @@ func (c *Container) Start() (err error) {
|
||||
return errors.Wrapf(ErrCtrStateInvalid, "container %s must be in Created or Stopped state to be started", c.ID())
|
||||
}
|
||||
|
||||
// TODO remove this when we patch conmon to support restarting containers
|
||||
if c.state.State == ContainerStateStopped {
|
||||
return errors.Wrapf(ErrNotImplemented, "restarting a stopped container is not yet supported")
|
||||
}
|
||||
|
||||
// Mount storage for the container if necessary
|
||||
if err := c.mountStorage(); err != nil {
|
||||
return err
|
||||
@ -109,6 +107,34 @@ func (c *Container) Start() (err error) {
|
||||
}
|
||||
}()
|
||||
|
||||
// Reinitialize the container if we need to
|
||||
if c.state.State == ContainerStateStopped {
|
||||
// If necessary, delete attach and ctl files
|
||||
if err := c.removeConmonFiles(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete the container in the runtime
|
||||
if err := c.runtime.ociRuntime.deleteContainer(c); err != nil {
|
||||
return errors.Wrapf(err, "error removing container %s from runtime", c.ID())
|
||||
}
|
||||
|
||||
// Our state is now Configured, as we've removed ourself from
|
||||
// the runtime
|
||||
// Set and save now to make sure that, if the init() below fails
|
||||
// we still have a valid state
|
||||
c.state.State = ContainerStateConfigured
|
||||
if err := c.save(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Reinitialize the container
|
||||
if err := c.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Start the container
|
||||
return c.start()
|
||||
}
|
||||
|
||||
|
@ -255,6 +255,38 @@ func (c *Container) refresh() error {
|
||||
return errors.Wrapf(err, "error refreshing state for container %s", c.ID())
|
||||
}
|
||||
|
||||
// Remove ctl and attach files, which may persist across reboot
|
||||
if err := c.removeConmonFiles(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove conmon attach socket and terminal resize FIFO
|
||||
// This is necessary for restarting containers
|
||||
func (c *Container) removeConmonFiles() error {
|
||||
// Files are allowed to not exist, so ignore ENOENT
|
||||
attachFile := filepath.Join(c.bundlePath(), "attach")
|
||||
if err := os.Remove(attachFile); err != nil && !os.IsNotExist(err) {
|
||||
return errors.Wrapf(err, "error removing container %s attach file", c.ID())
|
||||
}
|
||||
|
||||
ctlFile := filepath.Join(c.bundlePath(), "ctl")
|
||||
if err := os.Remove(ctlFile); err != nil && !os.IsNotExist(err) {
|
||||
return errors.Wrapf(err, "error removing container %s ctl file", c.ID())
|
||||
}
|
||||
|
||||
oomFile := filepath.Join(c.bundlePath(), "oom")
|
||||
if err := os.Remove(oomFile); err != nil && !os.IsNotExist(err) {
|
||||
return errors.Wrapf(err, "error removing container %s OOM file", c.ID())
|
||||
}
|
||||
|
||||
exitFile := filepath.Join(c.runtime.ociRuntime.exitsDir, c.ID())
|
||||
if err := os.Remove(exitFile); err != nil && !os.IsNotExist(err) {
|
||||
return errors.Wrapf(err, "error removing container %s exit file", c.ID())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -360,10 +392,6 @@ func (c *Container) initAndStart() (err error) {
|
||||
if c.state.State == ContainerStatePaused {
|
||||
return errors.Wrapf(ErrCtrStateInvalid, "cannot start paused container %s", c.ID())
|
||||
}
|
||||
// TODO remove this once we can restart containers
|
||||
if c.state.State == ContainerStateStopped {
|
||||
return errors.Wrapf(ErrNotImplemented, "restarting containers is not yet implemented")
|
||||
}
|
||||
|
||||
// Mount if necessary
|
||||
if err := c.mountStorage(); err != nil {
|
||||
@ -391,6 +419,29 @@ func (c *Container) initAndStart() (err error) {
|
||||
}
|
||||
}()
|
||||
|
||||
// If we are ContainerStateStopped we need to remove from runtime
|
||||
// And reset to ContainerStateConfigured
|
||||
if c.state.State == ContainerStateStopped {
|
||||
// If necessary, delete attach and ctl files
|
||||
if err := c.removeConmonFiles(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete the container in the runtime
|
||||
if err := c.runtime.ociRuntime.deleteContainer(c); err != nil {
|
||||
return errors.Wrapf(err, "error removing container %s from runtime", c.ID())
|
||||
}
|
||||
|
||||
// Our state is now Configured, as we've removed ourself from
|
||||
// the runtime
|
||||
// Set and save now to make sure that, if the init() below fails
|
||||
// we still have a valid state
|
||||
c.state.State = ContainerStateConfigured
|
||||
if err := c.save(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If we are ContainerStateConfigured we need to init()
|
||||
if c.state.State == ContainerStateConfigured {
|
||||
if err := c.init(); err != nil {
|
||||
|
@ -130,14 +130,6 @@ func (p *Pod) Start() (map[string]error, error) {
|
||||
for len(ctrsToStart) > 0 {
|
||||
// Loop through all containers, attempting to start them
|
||||
for id, ctr := range ctrsToStart {
|
||||
// TODO remove this when we support restarting containers
|
||||
if ctr.state.State == ContainerStateStopped {
|
||||
ctrErrors[id] = errors.Wrapf(ErrNotImplemented, "starting stopped containers is not yet supported")
|
||||
|
||||
delete(ctrsToStart, id)
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO should we only do a dependencies check if we are not ContainerStateCreated?
|
||||
depsOK := true
|
||||
var depErr error
|
||||
|
Reference in New Issue
Block a user