diff options
-rw-r--r-- | cmd/podman/start.go | 24 | ||||
-rw-r--r-- | libpod/container.go | 2 | ||||
-rw-r--r-- | libpod/container_api.go | 36 | ||||
-rw-r--r-- | libpod/container_internal.go | 59 | ||||
-rw-r--r-- | libpod/pod.go | 8 |
5 files changed, 101 insertions, 28 deletions
diff --git a/cmd/podman/start.go b/cmd/podman/start.go index 18e8f7766..243fe71e2 100644 --- a/cmd/podman/start.go +++ b/cmd/podman/start.go @@ -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 } diff --git a/libpod/container.go b/libpod/container.go index 648dc821e..98810ea94 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -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 { diff --git a/libpod/container_api.go b/libpod/container_api.go index 7e2197614..499cf826f 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -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() } diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 85c4283b3..6b375ef6f 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -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 { diff --git a/libpod/pod.go b/libpod/pod.go index 560277578..bd02efdae 100644 --- a/libpod/pod.go +++ b/libpod/pod.go @@ -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 |