summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@gmail.com>2017-12-01 13:26:58 -0500
committerMatthew Heon <matthew.heon@gmail.com>2017-12-04 14:29:59 -0500
commitae5aac50aaacbdcc20e622e86f40c02136690fe7 (patch)
treecaddca21e19f3bd0db2faa2c5783cff1836577f4 /libpod
parent750fc239b5da8e3f2792ae33f46a671ddf4622e3 (diff)
downloadpodman-ae5aac50aaacbdcc20e622e86f40c02136690fe7.tar.gz
podman-ae5aac50aaacbdcc20e622e86f40c02136690fe7.tar.bz2
podman-ae5aac50aaacbdcc20e622e86f40c02136690fe7.zip
Add handling for system restart in libpod
Signed-off-by: Matthew Heon <matthew.heon@gmail.com>
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container.go66
-rw-r--r--libpod/runtime.go45
2 files changed, 109 insertions, 2 deletions
diff --git a/libpod/container.go b/libpod/container.go
index bd7455147..e1b002548 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -407,8 +407,54 @@ func (c *Container) teardownStorage() error {
return nil
}
+// Refresh refreshes the container's state after a restart
+func (c *Container) refresh() error {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ if !c.valid {
+ return errors.Wrapf(ErrCtrRemoved, "container %s has been removed from the state", c.ID())
+ }
+
+ // We need to get the container's temporary directory from c/storage
+ // It was lost in the reboot and must be recreated
+ dir, err := c.runtime.storageService.GetRunDir(c.ID())
+ if err != nil {
+ return errors.Wrapf(err, "error retrieving temporary directory for container %s", c.ID())
+ }
+ c.state.RunDir = dir
+
+ // The container is no longer mounted
+ c.state.Mounted = false
+ c.state.Mountpoint = ""
+
+ // The container is no longe running
+ c.state.PID = 0
+
+ // Check the container's state. If it's not created in runc yet, we're
+ // done
+ if c.state.State == ContainerStateConfigured {
+ if err := c.runtime.state.SaveContainer(c); err != nil {
+ return errors.Wrapf(err, "error refreshing state for container %s", c.ID())
+ }
+
+ return nil
+ }
+
+ // The container must be recreated in runc
+ if err := c.init(); err != nil {
+ return err
+ }
+
+ if err := c.runtime.state.SaveContainer(c); err != nil {
+ return errors.Wrapf(err, "error refreshing state for container %s", c.ID())
+ }
+
+ return nil
+}
+
// Init creates a container in the OCI runtime
-func (c *Container) Init() (err error) {
+func (c *Container) Init() error {
c.lock.Lock()
defer c.lock.Unlock()
@@ -420,7 +466,12 @@ func (c *Container) Init() (err error) {
return errors.Wrapf(ErrCtrExists, "container %s has already been created in runtime", c.ID())
}
- // Mount storage for the container
+ return c.init()
+}
+
+// Creates container in OCI runtime
+// Internal only - does not lock or check state
+func (c *Container) init() (err error) {
if err := c.mountStorage(); err != nil {
return err
}
@@ -436,6 +487,17 @@ func (c *Container) Init() (err error) {
// Save the OCI spec to disk
jsonPath := filepath.Join(c.bundlePath(), "config.json")
+ // If the OCI spec already exists, replace it
+ if _, err := os.Stat(jsonPath); err != nil {
+ if !os.IsNotExist(err) {
+ return errors.Wrapf(err, "error doing stat on container %s spec", c.ID())
+ }
+ } else {
+ // No error, the spec exists. Remove so we can replace.
+ if err := os.Remove(jsonPath); err != nil {
+ return errors.Wrapf(err, "error replacing spec of container %s", c.ID())
+ }
+ }
fileJSON, err := json.Marshal(c.runningSpec)
if err != nil {
return errors.Wrapf(err, "error exporting runtime spec for container %s to JSON", c.ID())
diff --git a/libpod/runtime.go b/libpod/runtime.go
index b86e06546..7997679e2 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -173,6 +173,24 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
runtime.state = state
}
+ // We now need to see if the system has restarted
+ // We check for the presence of a file in our tmp directory to verify this
+ runtimeAliveFile := filepath.Join(runtime.config.TmpDir, "alive")
+ _, err = os.Stat(runtimeAliveFile)
+ if err != nil {
+ // If the file doesn't exist, we need to refresh the state
+ // This will trigger on first use as well, but refreshing an
+ // empty state only creates a single file
+ // As such, it's not really a performance concern
+ if os.IsNotExist(err) {
+ if err2 := runtime.refresh(runtimeAliveFile); err2 != nil {
+ return nil, err2
+ }
+ } else {
+ return nil, errors.Wrapf(err, "error reading runtime status file %s", runtimeAliveFile)
+ }
+ }
+
// Mark the runtime as valid - ready to be used, cannot be modified
// further
runtime.valid = true
@@ -238,3 +256,30 @@ func (r *Runtime) Shutdown(force bool) error {
return lastError
}
+
+// Reconfigures the runtime after a reboot
+// Refreshes the state, recreating temporary files
+// Does not check validity as the runtime is not valid until after this has run
+// TODO: there's a potential race here, where multiple libpods could be in this
+// function before the runtime ready file is created
+// This probably doesn't matter as the actual container operations are locked
+func (r *Runtime) refresh(alivePath string) error {
+ // We need to refresh the state of all containers
+ ctrs, err := r.state.AllContainers()
+ if err != nil {
+ return errors.Wrapf(err, "error retrieving all containers from state")
+ }
+ for _, ctr := range ctrs {
+ if err := ctr.refresh(); err != nil {
+ return err
+ }
+ }
+
+ file, err := os.OpenFile(alivePath, os.O_RDONLY|os.O_CREATE, 0644)
+ if err != nil {
+ return errors.Wrapf(err, "error creating runtime status file %s", alivePath)
+ }
+ defer file.Close()
+
+ return nil
+}