summaryrefslogtreecommitdiff
path: root/libpod/container_internal.go
diff options
context:
space:
mode:
Diffstat (limited to 'libpod/container_internal.go')
-rw-r--r--libpod/container_internal.go170
1 files changed, 107 insertions, 63 deletions
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index fcd6a990a..c409da96a 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -156,7 +156,7 @@ func (c *Container) waitForExitFileAndSync() error {
// Reset our state
c.state.ExitCode = -1
c.state.FinishedTime = time.Now()
- c.state.State = ContainerStateStopped
+ c.state.State = define.ContainerStateStopped
if err2 := c.save(); err2 != nil {
logrus.Errorf("Error saving container %s state: %v", c.ID(), err2)
@@ -241,9 +241,9 @@ func (c *Container) handleRestartPolicy(ctx context.Context) (restarted bool, er
// Is the container running again?
// If so, we don't have to do anything
- if c.state.State == ContainerStateRunning || c.state.State == ContainerStatePaused {
+ if c.state.State == define.ContainerStateRunning || c.state.State == define.ContainerStatePaused {
return false, nil
- } else if c.state.State == ContainerStateUnknown {
+ } else if c.state.State == define.ContainerStateUnknown {
return false, errors.Wrapf(define.ErrInternal, "invalid container state encountered in restart attempt!")
}
@@ -267,13 +267,13 @@ func (c *Container) handleRestartPolicy(ctx context.Context) (restarted bool, er
return false, err
}
- if c.state.State == ContainerStateStopped {
+ if c.state.State == define.ContainerStateStopped {
// Reinitialize the container if we need to
if err := c.reinit(ctx, true); err != nil {
return false, err
}
- } else if c.state.State == ContainerStateConfigured ||
- c.state.State == ContainerStateExited {
+ } else if c.state.State == define.ContainerStateConfigured ||
+ c.state.State == define.ContainerStateExited {
// Initialize the container
if err := c.init(ctx, true); err != nil {
return false, err
@@ -295,9 +295,9 @@ func (c *Container) syncContainer() error {
}
// If runtime knows about the container, update its status in runtime
// And then save back to disk
- if (c.state.State != ContainerStateUnknown) &&
- (c.state.State != ContainerStateConfigured) &&
- (c.state.State != ContainerStateExited) {
+ if (c.state.State != define.ContainerStateUnknown) &&
+ (c.state.State != define.ContainerStateConfigured) &&
+ (c.state.State != define.ContainerStateExited) {
oldState := c.state.State
// TODO: optionally replace this with a stat for the exit file
if err := c.ociRuntime.updateContainerStatus(c, false); err != nil {
@@ -307,8 +307,8 @@ func (c *Container) syncContainer() error {
if c.state.State != oldState {
// Check for a restart policy match
if c.config.RestartPolicy != RestartPolicyNone && c.config.RestartPolicy != RestartPolicyNo &&
- (oldState == ContainerStateRunning || oldState == ContainerStatePaused) &&
- (c.state.State == ContainerStateStopped || c.state.State == ContainerStateExited) &&
+ (oldState == define.ContainerStateRunning || oldState == define.ContainerStatePaused) &&
+ (c.state.State == define.ContainerStateStopped || c.state.State == define.ContainerStateExited) &&
!c.state.StoppedByUser {
c.state.RestartPolicyMatch = true
}
@@ -336,7 +336,7 @@ func (c *Container) setupStorage(ctx context.Context) error {
return errors.Wrapf(define.ErrCtrRemoved, "container %s is not valid", c.ID())
}
- if c.state.State != ContainerStateConfigured {
+ if c.state.State != define.ContainerStateConfigured {
return errors.Wrapf(define.ErrCtrStateInvalid, "container %s must be in Configured state to have storage set up", c.ID())
}
@@ -352,6 +352,16 @@ func (c *Container) setupStorage(ctx context.Context) error {
},
LabelOpts: c.config.LabelOpts,
}
+ if c.restoreFromCheckpoint {
+ // If restoring from a checkpoint, the root file-system
+ // needs to be mounted with the same SELinux labels as
+ // it was mounted previously.
+ if options.Flags == nil {
+ options.Flags = make(map[string]interface{})
+ }
+ options.Flags["ProcessLabel"] = c.config.ProcessLabel
+ options.Flags["MountLabel"] = c.config.MountLabel
+ }
if c.config.Privileged {
privOpt := func(opt string) bool {
for _, privopt := range []string{"nodev", "nosuid", "noexec"} {
@@ -418,7 +428,7 @@ func (c *Container) setupStorage(ctx context.Context) error {
// Tear down a container's storage prior to removal
func (c *Container) teardownStorage() error {
- if c.state.State == ContainerStateRunning || c.state.State == ContainerStatePaused {
+ if c.state.State == define.ContainerStateRunning || c.state.State == define.ContainerStatePaused {
return errors.Wrapf(define.ErrCtrStateInvalid, "cannot remove storage for container %s as it is running or paused", c.ID())
}
@@ -452,10 +462,11 @@ func (c *Container) teardownStorage() error {
// It does not save the results - assumes the database will do that for us
func resetState(state *ContainerState) error {
state.PID = 0
+ state.ConmonPID = 0
state.Mountpoint = ""
state.Mounted = false
- if state.State != ContainerStateExited {
- state.State = ContainerStateConfigured
+ if state.State != define.ContainerStateExited {
+ state.State = define.ContainerStateConfigured
}
state.ExecSessions = make(map[string]*ExecSession)
state.NetworkStatus = nil
@@ -554,7 +565,7 @@ func (c *Container) removeConmonFiles() error {
if !os.IsNotExist(err) {
return errors.Wrapf(err, "error running stat on container %s exit file", c.ID())
}
- } else if err == nil {
+ } else {
// Rename should replace the old exit file (if it exists)
if err := os.Rename(exitFile, oldExitFile); err != nil {
return errors.Wrapf(err, "error renaming container %s exit file", c.ID())
@@ -567,11 +578,11 @@ func (c *Container) removeConmonFiles() error {
func (c *Container) export(path string) error {
mountPoint := c.state.Mountpoint
if !c.state.Mounted {
- mount, err := c.runtime.store.Mount(c.ID(), c.config.MountLabel)
+ containerMount, err := c.runtime.store.Mount(c.ID(), c.config.MountLabel)
if err != nil {
return errors.Wrapf(err, "error mounting container %q", c.ID())
}
- mountPoint = mount
+ mountPoint = containerMount
defer func() {
if _, err := c.runtime.store.Unmount(c.ID(), false); err != nil {
logrus.Errorf("error unmounting container %q: %v", c.ID(), err)
@@ -609,7 +620,7 @@ func (c *Container) isStopped() (bool, error) {
if err != nil {
return true, err
}
- return (c.state.State != ContainerStateRunning && c.state.State != ContainerStatePaused), nil
+ return c.state.State != define.ContainerStateRunning && c.state.State != define.ContainerStatePaused, nil
}
// save container state to the database
@@ -625,10 +636,10 @@ func (c *Container) save() error {
// Otherwise, this function will return with error if there are dependencies of this container that aren't running.
func (c *Container) prepareToStart(ctx context.Context, recursive bool) (err error) {
// Container must be created or stopped to be started
- if !(c.state.State == ContainerStateConfigured ||
- c.state.State == ContainerStateCreated ||
- c.state.State == ContainerStateStopped ||
- c.state.State == ContainerStateExited) {
+ if !(c.state.State == define.ContainerStateConfigured ||
+ c.state.State == define.ContainerStateCreated ||
+ c.state.State == define.ContainerStateStopped ||
+ c.state.State == define.ContainerStateExited) {
return errors.Wrapf(define.ErrCtrStateInvalid, "container %s must be in Created or Stopped state to be started", c.ID())
}
@@ -654,13 +665,13 @@ func (c *Container) prepareToStart(ctx context.Context, recursive bool) (err err
return err
}
- if c.state.State == ContainerStateStopped {
+ if c.state.State == define.ContainerStateStopped {
// Reinitialize the container if we need to
if err := c.reinit(ctx, false); err != nil {
return err
}
- } else if c.state.State == ContainerStateConfigured ||
- c.state.State == ContainerStateExited {
+ } else if c.state.State == define.ContainerStateConfigured ||
+ c.state.State == define.ContainerStateExited {
// Or initialize it if necessary
if err := c.init(ctx, false); err != nil {
return err
@@ -763,7 +774,7 @@ func (c *Container) getAllDependencies(visited map[string]*Container) error {
}
// if the dependency is already running, we can assume its dependencies are also running
// so no need to add them to those we need to start
- if status != ContainerStateRunning {
+ if status != define.ContainerStateRunning {
visited[depID] = dep
if err := dep.getAllDependencies(visited); err != nil {
return err
@@ -795,7 +806,7 @@ func (c *Container) checkDependenciesRunning() ([]string, error) {
if err != nil {
return nil, errors.Wrapf(err, "error retrieving state of dependency %s of container %s", dep, c.ID())
}
- if state != ContainerStateRunning {
+ if state != define.ContainerStateRunning {
notRunning = append(notRunning, dep)
}
depCtrs[dep] = depCtr
@@ -824,7 +835,7 @@ func (c *Container) checkDependenciesRunningLocked(depCtrs map[string]*Container
return nil, err
}
- if depCtr.state.State != ContainerStateRunning {
+ if depCtr.state.State != define.ContainerStateRunning {
notRunning = append(notRunning, dep)
}
}
@@ -855,18 +866,18 @@ func (c *Container) init(ctx context.Context, retainRetries bool) error {
span.SetTag("struct", "container")
defer span.Finish()
- // Generate the OCI spec
- spec, err := c.generateSpec(ctx)
+ // Generate the OCI newSpec
+ newSpec, err := c.generateSpec(ctx)
if err != nil {
return err
}
- // Save the OCI spec to disk
- if err := c.saveSpec(spec); err != nil {
+ // Save the OCI newSpec to disk
+ if err := c.saveSpec(newSpec); err != nil {
return err
}
- // With the spec complete, do an OCI create
+ // With the newSpec complete, do an OCI create
if err := c.ociRuntime.createContainer(c, c.config.CgroupParent, nil); err != nil {
return err
}
@@ -875,7 +886,7 @@ func (c *Container) init(ctx context.Context, retainRetries bool) error {
c.state.ExitCode = 0
c.state.Exited = false
- c.state.State = ContainerStateCreated
+ c.state.State = define.ContainerStateCreated
c.state.StoppedByUser = false
c.state.RestartPolicyMatch = false
@@ -906,7 +917,7 @@ func (c *Container) cleanupRuntime(ctx context.Context) error {
// If the container is not ContainerStateStopped or
// ContainerStateCreated, do nothing.
- if c.state.State != ContainerStateStopped && c.state.State != ContainerStateCreated {
+ if c.state.State != define.ContainerStateStopped && c.state.State != define.ContainerStateCreated {
return nil
}
@@ -922,10 +933,10 @@ func (c *Container) cleanupRuntime(ctx context.Context) error {
// If we were Stopped, we are now Exited, as we've removed ourself
// from the runtime.
// If we were Created, we are now Configured.
- if c.state.State == ContainerStateStopped {
- c.state.State = ContainerStateExited
- } else if c.state.State == ContainerStateCreated {
- c.state.State = ContainerStateConfigured
+ if c.state.State == define.ContainerStateStopped {
+ c.state.State = define.ContainerStateExited
+ } else if c.state.State == define.ContainerStateCreated {
+ c.state.State = define.ContainerStateConfigured
}
if c.valid {
@@ -964,16 +975,16 @@ func (c *Container) reinit(ctx context.Context, retainRetries bool) error {
// Does not lock or check validity
func (c *Container) initAndStart(ctx context.Context) (err error) {
// If we are ContainerStateUnknown, throw an error
- if c.state.State == ContainerStateUnknown {
+ if c.state.State == define.ContainerStateUnknown {
return errors.Wrapf(define.ErrCtrStateInvalid, "container %s is in an unknown state", c.ID())
}
// If we are running, do nothing
- if c.state.State == ContainerStateRunning {
+ if c.state.State == define.ContainerStateRunning {
return nil
}
// If we are paused, throw an error
- if c.state.State == ContainerStatePaused {
+ if c.state.State == define.ContainerStatePaused {
return errors.Wrapf(define.ErrCtrStateInvalid, "cannot start paused container %s", c.ID())
}
@@ -991,14 +1002,14 @@ func (c *Container) initAndStart(ctx context.Context) (err error) {
// If we are ContainerStateStopped we need to remove from runtime
// And reset to ContainerStateConfigured
- if c.state.State == ContainerStateStopped {
+ if c.state.State == define.ContainerStateStopped {
logrus.Debugf("Recreating container %s in OCI runtime", c.ID())
if err := c.reinit(ctx, false); err != nil {
return err
}
- } else if c.state.State == ContainerStateConfigured ||
- c.state.State == ContainerStateExited {
+ } else if c.state.State == define.ContainerStateConfigured ||
+ c.state.State == define.ContainerStateExited {
if err := c.init(ctx, false); err != nil {
return err
}
@@ -1019,7 +1030,7 @@ func (c *Container) start() error {
}
logrus.Debugf("Started container %s", c.ID())
- c.state.State = ContainerStateRunning
+ c.state.State = define.ContainerStateRunning
if c.config.HealthCheckConfig != nil {
if err := c.updateHealthStatus(HealthCheckStarting); err != nil {
@@ -1043,6 +1054,8 @@ func (c *Container) stop(timeout uint) error {
return err
}
+ c.state.PID = 0
+ c.state.ConmonPID = 0
c.state.StoppedByUser = true
if err := c.save(); err != nil {
return errors.Wrapf(err, "error saving container %s state after stopping", c.ID())
@@ -1060,7 +1073,7 @@ func (c *Container) pause() error {
logrus.Debugf("Paused container %s", c.ID())
- c.state.State = ContainerStatePaused
+ c.state.State = define.ContainerStatePaused
return c.save()
}
@@ -1073,20 +1086,20 @@ func (c *Container) unpause() error {
logrus.Debugf("Unpaused container %s", c.ID())
- c.state.State = ContainerStateRunning
+ c.state.State = define.ContainerStateRunning
return c.save()
}
// Internal, non-locking function to restart a container
func (c *Container) restartWithTimeout(ctx context.Context, timeout uint) (err error) {
- if c.state.State == ContainerStateUnknown || c.state.State == ContainerStatePaused {
+ if c.state.State == define.ContainerStateUnknown || c.state.State == define.ContainerStatePaused {
return errors.Wrapf(define.ErrCtrStateInvalid, "unable to restart a container in a paused or unknown state")
}
c.newContainerEvent(events.Restart)
- if c.state.State == ContainerStateRunning {
+ if c.state.State == define.ContainerStateRunning {
if err := c.stop(timeout); err != nil {
return err
}
@@ -1102,13 +1115,13 @@ func (c *Container) restartWithTimeout(ctx context.Context, timeout uint) (err e
return err
}
- if c.state.State == ContainerStateStopped {
+ if c.state.State == define.ContainerStateStopped {
// Reinitialize the container if we need to
if err := c.reinit(ctx, false); err != nil {
return err
}
- } else if c.state.State == ContainerStateConfigured ||
- c.state.State == ContainerStateExited {
+ } else if c.state.State == define.ContainerStateConfigured ||
+ c.state.State == define.ContainerStateExited {
// Initialize the container
if err := c.init(ctx, false); err != nil {
return err
@@ -1164,8 +1177,8 @@ func (c *Container) cleanupStorage() error {
return nil
}
- for _, mount := range c.config.Mounts {
- if err := c.unmountSHM(mount); err != nil {
+ for _, containerMount := range c.config.Mounts {
+ if err := c.unmountSHM(containerMount); err != nil {
return err
}
}
@@ -1396,14 +1409,14 @@ func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (exten
}
return nil, err
}
- hooks, err := manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0)
+ ociHooks, err := manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0)
if err != nil {
return nil, err
}
- if len(hooks) > 0 || config.Hooks != nil {
- logrus.Warnf("implicit hook directories are deprecated; set --hooks-dir=%q explicitly to continue to load hooks from this directory", hDir)
+ if len(ociHooks) > 0 || config.Hooks != nil {
+ logrus.Warnf("implicit hook directories are deprecated; set --ociHooks-dir=%q explicitly to continue to load ociHooks from this directory", hDir)
}
- for i, hook := range hooks {
+ for i, hook := range ociHooks {
allHooks[i] = hook
}
}
@@ -1482,12 +1495,12 @@ func (c *Container) copyWithTarFromImage(src, dest string) error {
// If it is, we'll remove the container anyways.
// Returns nil if safe to remove, or an error describing why it's unsafe if not.
func (c *Container) checkReadyForRemoval() error {
- if c.state.State == ContainerStateUnknown {
+ if c.state.State == define.ContainerStateUnknown {
return errors.Wrapf(define.ErrCtrStateInvalid, "container %s is in invalid state", c.ID())
}
- if c.state.State == ContainerStateRunning ||
- c.state.State == ContainerStatePaused {
+ if c.state.State == define.ContainerStateRunning ||
+ c.state.State == define.ContainerStatePaused {
return errors.Wrapf(define.ErrCtrStateInvalid, "cannot remove container %s as it is %s - running or paused containers cannot be removed", c.ID(), c.state.State.String())
}
@@ -1534,3 +1547,34 @@ func (c *Container) prepareCheckpointExport() (err error) {
return nil
}
+
+// sortUserVolumes sorts the volumes specified for a container
+// between named and normal volumes
+func (c *Container) sortUserVolumes(ctrSpec *spec.Spec) ([]*ContainerNamedVolume, []spec.Mount) {
+ namedUserVolumes := []*ContainerNamedVolume{}
+ userMounts := []spec.Mount{}
+
+ // We need to parse all named volumes and mounts into maps, so we don't
+ // end up with repeated lookups for each user volume.
+ // Map destination to struct, as destination is what is stored in
+ // UserVolumes.
+ namedVolumes := make(map[string]*ContainerNamedVolume)
+ mounts := make(map[string]spec.Mount)
+ for _, namedVol := range c.config.NamedVolumes {
+ namedVolumes[namedVol.Dest] = namedVol
+ }
+ for _, mount := range ctrSpec.Mounts {
+ mounts[mount.Destination] = mount
+ }
+
+ for _, vol := range c.config.UserVolumes {
+ if volume, ok := namedVolumes[vol]; ok {
+ namedUserVolumes = append(namedUserVolumes, volume)
+ } else if mount, ok := mounts[vol]; ok {
+ userMounts = append(userMounts, mount)
+ } else {
+ logrus.Warnf("Could not find mount at destination %q when parsing user volumes for container %s", vol, c.ID())
+ }
+ }
+ return namedUserVolumes, userMounts
+}