diff options
author | Matthew Heon <matthew.heon@gmail.com> | 2017-12-07 13:15:34 -0500 |
---|---|---|
committer | Matthew Heon <matthew.heon@gmail.com> | 2017-12-07 13:15:34 -0500 |
commit | b71cde19c8b511c054ee42084113ce97ed6d5b62 (patch) | |
tree | c69fc6b6a6ad1d931c059ad2325ca7778b8ba4e8 /libpod | |
parent | b66287689a0c8c9f2f8c01cdca065fb1f6e8d872 (diff) | |
download | podman-b71cde19c8b511c054ee42084113ce97ed6d5b62.tar.gz podman-b71cde19c8b511c054ee42084113ce97ed6d5b62.tar.bz2 podman-b71cde19c8b511c054ee42084113ce97ed6d5b62.zip |
Add ability to refresh state in DB
Also, ensure we always recreate runtime spec so our net namespace
paths will be correct
Signed-off-by: Matthew Heon <matthew.heon@gmail.com>
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/container.go | 57 | ||||
-rw-r--r-- | libpod/in_memory_state.go | 6 | ||||
-rw-r--r-- | libpod/runtime.go | 8 | ||||
-rw-r--r-- | libpod/sql_state.go | 46 | ||||
-rw-r--r-- | libpod/state.go | 3 |
5 files changed, 88 insertions, 32 deletions
diff --git a/libpod/container.go b/libpod/container.go index adc52d85f..ce4d6ea84 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -424,16 +424,6 @@ func (c *Container) refresh() error { } c.state.RunDir = dir - // The container is no longer mounted - c.state.Mounted = false - c.state.Mountpoint = "" - - // The container is no longer running - c.state.PID = 0 - - // The container no longer exists in runc - 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()) } @@ -458,35 +448,40 @@ func (c *Container) Init() (err error) { return err } - // Save the OCI spec to disk + // If the OCI spec already exists, we need to replace it + // Cannot guarantee some things, e.g. network namespaces, have the same + // paths jsonPath := filepath.Join(c.bundlePath(), "config.json") if _, err := os.Stat(jsonPath); err != nil { if !os.IsNotExist(err) { return errors.Wrapf(err, "error doing stat on container %s spec", c.ID()) } - - // The spec does not exist, needs to be created - g := generate.NewFromSpec(c.config.Spec) - // Mount ShmDir from host into container - g.AddBindMount(c.config.ShmDir, "/dev/shm", []string{"rw"}) - c.runningSpec = g.Spec() - c.runningSpec.Root.Path = c.state.Mountpoint - c.runningSpec.Annotations[crioAnnotations.Created] = c.config.CreatedTime.Format(time.RFC3339Nano) - c.runningSpec.Annotations["org.opencontainers.image.stopSignal"] = fmt.Sprintf("%d", c.config.StopSignal) - - fileJSON, err := json.Marshal(c.runningSpec) - if err != nil { - return errors.Wrapf(err, "error exporting runtime spec for container %s to JSON", c.ID()) - } - if err := ioutil.WriteFile(jsonPath, fileJSON, 0644); err != nil { - return errors.Wrapf(err, "error writing runtime spec JSON to file for container %s", c.ID()) + // The spec does not exist, we're fine + } else { + // The spec exists, need to remove it + if err := os.Remove(jsonPath); err != nil { + return errors.Wrapf(err, "error replacing runtime spec for container %s", c.ID()) } + } - logrus.Debugf("Created OCI spec for container %s at %s", c.ID(), jsonPath) - } else { - // The spec exists - logrus.Debugf("Using existing OCI spec for container %s at %s", c.ID(), jsonPath) + // Save OCI spec to disk + g := generate.NewFromSpec(c.config.Spec) + // Mount ShmDir from host into container + g.AddBindMount(c.config.ShmDir, "/dev/shm", []string{"rw"}) + c.runningSpec = g.Spec() + c.runningSpec.Root.Path = c.state.Mountpoint + c.runningSpec.Annotations[crioAnnotations.Created] = c.config.CreatedTime.Format(time.RFC3339Nano) + c.runningSpec.Annotations["org.opencontainers.image.stopSignal"] = fmt.Sprintf("%d", c.config.StopSignal) + + fileJSON, err := json.Marshal(c.runningSpec) + if err != nil { + return errors.Wrapf(err, "error exporting runtime spec for container %s to JSON", c.ID()) } + if err := ioutil.WriteFile(jsonPath, fileJSON, 0644); err != nil { + return errors.Wrapf(err, "error writing runtime spec JSON to file for container %s", c.ID()) + } + + logrus.Debugf("Created OCI spec for container %s at %s", c.ID(), jsonPath) c.state.ConfigPath = jsonPath diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go index 5d03e62e6..4e4cbb664 100644 --- a/libpod/in_memory_state.go +++ b/libpod/in_memory_state.go @@ -38,6 +38,12 @@ func (s *InMemoryState) Close() error { return nil } +// Refresh clears container and pod stats after a reboot +// In-memory state won't survive a reboot so this is a no-op +func (s *InMemoryState) Refresh() error { + return nil +} + // Container retrieves a container from its full ID func (s *InMemoryState) Container(id string) (*Container, error) { if id == "" { diff --git a/libpod/runtime.go b/libpod/runtime.go index 103faf3f8..36225bf69 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -273,7 +273,13 @@ func (r *Runtime) Shutdown(force bool) error { // Refreshes the state, recreating temporary files // Does not check validity as the runtime is not valid until after this has run func (r *Runtime) refresh(alivePath string) error { - // We need to refresh the state of all containers + // First clear the state in the database + if err := r.state.Refresh(); err != nil { + return err + } + + // Next refresh the state of all containers to recreate dirs and + // namespaces ctrs, err := r.state.AllContainers() if err != nil { return errors.Wrapf(err, "error retrieving all containers from state") diff --git a/libpod/sql_state.go b/libpod/sql_state.go index fb6be85d7..bba697d18 100644 --- a/libpod/sql_state.go +++ b/libpod/sql_state.go @@ -103,6 +103,52 @@ func (s *SQLState) Close() error { return nil } +// Refresh clears the state after a reboot +// Resets mountpoint, PID, state for all containers +func (s *SQLState) Refresh() (err error) { + const refresh = `UPDATE containerState SET + State=?, + Mountpoint=?, + Pid=?;` + + s.lock.Lock() + defer s.lock.Unlock() + + if !s.valid { + return ErrDBClosed + } + + tx, err := s.db.Begin() + if err != nil { + return errors.Wrapf(err, "error beginning database transaction") + } + defer func() { + if err != nil { + if err2 := tx.Rollback(); err2 != nil { + logrus.Errorf("Error rolling back transaction to refresh state: %v", err2) + } + } + }() + + // Refresh container state + // The constants could be moved into the SQL, but keeping them here + // will keep us in sync in case ContainerStateConfigured ever changes in + // the container state + _, err = tx.Exec(refresh, + ContainerStateConfigured, + "", + 0) + if err != nil { + return errors.Wrapf(err, "error refreshing database state") + } + + if err := tx.Commit(); err != nil { + return errors.Wrapf(err, "error committing transaction to refresh database") + } + + return nil +} + // Container retrieves a container from its full ID func (s *SQLState) Container(id string) (*Container, error) { const query = `SELECT containers.*, diff --git a/libpod/state.go b/libpod/state.go index 4093f14f1..4a79b8d2d 100644 --- a/libpod/state.go +++ b/libpod/state.go @@ -6,6 +6,9 @@ type State interface { // connections) that may be required Close() error + // Refresh clears container and pod states after a reboot + Refresh() error + // Accepts full ID of container Container(id string) (*Container, error) // Accepts full or partial IDs (as long as they are unique) and names |