summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@gmail.com>2018-03-13 11:49:24 -0400
committerAtomic Bot <atomic-devel@projectatomic.io>2018-03-15 17:45:11 +0000
commit02a26c2934eea13799ae950827df54ec995312bc (patch)
tree6b98d4cb0ef0668c03b6ec2b78b45b771c7a81d7
parentff091cf731cb28e5d38ff843781115d352ea1530 (diff)
downloadpodman-02a26c2934eea13799ae950827df54ec995312bc.tar.gz
podman-02a26c2934eea13799ae950827df54ec995312bc.tar.bz2
podman-02a26c2934eea13799ae950827df54ec995312bc.zip
Implement container restarting
Signed-off-by: Matthew Heon <matthew.heon@gmail.com> Closes: #482 Approved by: baude
-rw-r--r--cmd/podman/start.go24
-rw-r--r--libpod/container.go2
-rw-r--r--libpod/container_api.go36
-rw-r--r--libpod/container_internal.go59
-rw-r--r--libpod/pod.go8
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