mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +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 {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "unable to parse annotations in %s", ctr.ID())
|
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
|
// We only get a terminal session if both a tty was specified in the spec and
|
||||||
// -a on the command-line was given.
|
// -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 {
|
if attach && tty {
|
||||||
// We increment the wg counter because we need to do the attach
|
// We increment the wg counter because we need to do the attach
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
@ -121,14 +131,6 @@ func startCmd(c *cli.Context) error {
|
|||||||
return errors.Errorf("unable to attach to container %s", ctr.ID())
|
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 {
|
if !attach {
|
||||||
fmt.Println(ctr.ID())
|
fmt.Println(ctr.ID())
|
||||||
}
|
}
|
||||||
@ -141,7 +143,11 @@ func startCmd(c *cli.Context) error {
|
|||||||
if lastError != nil {
|
if lastError != nil {
|
||||||
fmt.Fprintln(os.Stderr, lastError)
|
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
|
return lastError
|
||||||
}
|
}
|
||||||
|
@ -106,8 +106,6 @@ type Container struct {
|
|||||||
runtime *Runtime
|
runtime *Runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO fetch IP and Subnet Mask from networks once we have updated OCICNI
|
|
||||||
|
|
||||||
// containerState contains the current state of the container
|
// containerState contains the current state of the container
|
||||||
// It is stored on disk in a tmpfs and recreated on reboot
|
// It is stored on disk in a tmpfs and recreated on reboot
|
||||||
type containerState struct {
|
type containerState struct {
|
||||||
|
@ -63,6 +63,9 @@ func (c *Container) Init() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start starts a container
|
// 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) {
|
func (c *Container) Start() (err error) {
|
||||||
if !c.locked {
|
if !c.locked {
|
||||||
c.lock.Lock()
|
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())
|
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
|
// Mount storage for the container if necessary
|
||||||
if err := c.mountStorage(); err != nil {
|
if err := c.mountStorage(); err != nil {
|
||||||
return err
|
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()
|
return c.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,6 +255,38 @@ func (c *Container) refresh() error {
|
|||||||
return errors.Wrapf(err, "error refreshing state for container %s", c.ID())
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,10 +392,6 @@ func (c *Container) initAndStart() (err error) {
|
|||||||
if c.state.State == ContainerStatePaused {
|
if c.state.State == ContainerStatePaused {
|
||||||
return errors.Wrapf(ErrCtrStateInvalid, "cannot start paused container %s", c.ID())
|
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
|
// Mount if necessary
|
||||||
if err := c.mountStorage(); err != nil {
|
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 we are ContainerStateConfigured we need to init()
|
||||||
if c.state.State == ContainerStateConfigured {
|
if c.state.State == ContainerStateConfigured {
|
||||||
if err := c.init(); err != nil {
|
if err := c.init(); err != nil {
|
||||||
|
@ -130,14 +130,6 @@ func (p *Pod) Start() (map[string]error, error) {
|
|||||||
for len(ctrsToStart) > 0 {
|
for len(ctrsToStart) > 0 {
|
||||||
// Loop through all containers, attempting to start them
|
// Loop through all containers, attempting to start them
|
||||||
for id, ctr := range ctrsToStart {
|
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?
|
// TODO should we only do a dependencies check if we are not ContainerStateCreated?
|
||||||
depsOK := true
|
depsOK := true
|
||||||
var depErr error
|
var depErr error
|
||||||
|
Reference in New Issue
Block a user