summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container_api.go5
-rw-r--r--libpod/container_internal_linux.go19
-rw-r--r--libpod/oci.go29
-rw-r--r--libpod/options.go16
-rw-r--r--libpod/runtime.go15
-rw-r--r--libpod/runtime_ctr.go5
-rw-r--r--libpod/volume.go18
7 files changed, 80 insertions, 27 deletions
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 09d7f220d..6bef3c47d 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -203,9 +203,8 @@ func (c *Container) Kill(signal uint) error {
}
// Exec starts a new process inside the container
-// TODO allow specifying streams to attach to
// TODO investigate allowing exec without attaching
-func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir string) error {
+func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir string, streams *AttachStreams) error {
var capList []string
locked := false
@@ -267,7 +266,7 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir
logrus.Debugf("Creating new exec session in container %s with session id %s", c.ID(), sessionID)
- execCmd, err := c.runtime.ociRuntime.execContainer(c, cmd, capList, env, tty, workDir, hostUser, sessionID)
+ execCmd, err := c.runtime.ociRuntime.execContainer(c, cmd, capList, env, tty, workDir, hostUser, sessionID, streams)
if err != nil {
return errors.Wrapf(err, "error exec %s", c.ID())
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index b074efa3a..0e9a5124e 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -472,10 +472,19 @@ func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr
return nil
}
-func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointOptions) (err error) {
-
+func (c *Container) checkpointRestoreSupported() (err error) {
if !criu.CheckForCriu() {
- return errors.Errorf("checkpointing a container requires at least CRIU %d", criu.MinCriuVersion)
+ return errors.Errorf("Checkpoint/Restore requires at least CRIU %d", criu.MinCriuVersion)
+ }
+ if !c.runtime.ociRuntime.featureCheckCheckpointing() {
+ return errors.Errorf("Configured runtime does not support checkpoint/restore")
+ }
+ return nil
+}
+
+func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointOptions) (err error) {
+ if err := c.checkpointRestoreSupported(); err != nil {
+ return err
}
if c.state.State != ContainerStateRunning {
@@ -532,8 +541,8 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
func (c *Container) restore(ctx context.Context, options ContainerCheckpointOptions) (err error) {
- if !criu.CheckForCriu() {
- return errors.Errorf("restoring a container requires at least CRIU %d", criu.MinCriuVersion)
+ if err := c.checkpointRestoreSupported(); err != nil {
+ return err
}
if (c.state.State != ContainerStateConfigured) && (c.state.State != ContainerStateExited) {
diff --git a/libpod/oci.go b/libpod/oci.go
index 26d2c6ef1..2b3cc5db5 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -733,7 +733,7 @@ func (r *OCIRuntime) unpauseContainer(ctr *Container) error {
// TODO: Add --detach support
// TODO: Convert to use conmon
// TODO: add --pid-file and use that to generate exec session tracking
-func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty bool, cwd, user, sessionID string) (*exec.Cmd, error) {
+func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty bool, cwd, user, sessionID string, streams *AttachStreams) (*exec.Cmd, error) {
if len(cmd) == 0 {
return nil, errors.Wrapf(ErrInvalidArg, "must provide a command to execute")
}
@@ -789,9 +789,17 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty
logrus.Debugf("Starting runtime %s with following arguments: %v", r.path, args)
execCmd := exec.Command(r.path, args...)
- execCmd.Stdout = os.Stdout
- execCmd.Stderr = os.Stderr
- execCmd.Stdin = os.Stdin
+
+ if streams.AttachOutput {
+ execCmd.Stdout = streams.OutputStream
+ }
+ if streams.AttachInput {
+ execCmd.Stdin = streams.InputStream
+ }
+ if streams.AttachError {
+ execCmd.Stderr = streams.ErrorStream
+ }
+
execCmd.Env = append(execCmd.Env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir))
if err := execCmd.Start(); err != nil {
@@ -890,3 +898,16 @@ func (r *OCIRuntime) checkpointContainer(ctr *Container, options ContainerCheckp
args = append(args, ctr.ID())
return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, args...)
}
+
+func (r *OCIRuntime) featureCheckCheckpointing() bool {
+ // Check if the runtime implements checkpointing. Currently only
+ // runc's checkpoint/restore implementation is supported.
+ cmd := exec.Command(r.path, "checkpoint", "-h")
+ if err := cmd.Start(); err != nil {
+ return false
+ }
+ if err := cmd.Wait(); err == nil {
+ return true
+ }
+ return false
+}
diff --git a/libpod/options.go b/libpod/options.go
index 184d5d59f..1e8592a25 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1248,6 +1248,22 @@ func WithVolumeOptions(options map[string]string) VolumeCreateOption {
}
}
+// withSetCtrSpecific sets a bool notifying libpod that a volume was created
+// specifically for a container.
+// These volumes will be removed when the container is removed and volumes are
+// also specified for removal.
+func withSetCtrSpecific() VolumeCreateOption {
+ return func(volume *Volume) error {
+ if volume.valid {
+ return ErrVolumeFinalized
+ }
+
+ volume.config.IsCtrSpecific = true
+
+ return nil
+ }
+}
+
// Pod Creation Options
// WithPodName sets the name of the pod.
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 827c22f5b..f53cdd8b8 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -331,16 +331,13 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
deepcopier.Copy(defaultRuntimeConfig).To(runtime.config)
runtime.config.TmpDir = tmpDir
- if rootless.IsRootless() {
- // If we're rootless, override the default storage config
- storageConf, volumePath, err := util.GetDefaultStoreOptions()
- if err != nil {
- return nil, errors.Wrapf(err, "error retrieving rootless storage config")
- }
- runtime.config.StorageConfig = storageConf
- runtime.config.StaticDir = filepath.Join(storageConf.GraphRoot, "libpod")
- runtime.config.VolumePath = volumePath
+ storageConf, err := util.GetDefaultStoreOptions()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error retrieving rootless storage config")
}
+ runtime.config.StorageConfig = storageConf
+ runtime.config.StaticDir = filepath.Join(storageConf.GraphRoot, "libpod")
+ runtime.config.VolumePath = filepath.Join(storageConf.GraphRoot, "volumes")
configPath := ConfigPath
foundConfig := true
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 2ec8d0795..cfa4f9654 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -180,7 +180,7 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
if vol.Source[0] != '/' && isNamedVolume(vol.Source) {
volInfo, err := r.state.Volume(vol.Source)
if err != nil {
- newVol, err := r.newVolume(ctx, WithVolumeName(vol.Source))
+ newVol, err := r.newVolume(ctx, WithVolumeName(vol.Source), withSetCtrSpecific())
if err != nil {
return nil, errors.Wrapf(err, "error creating named volume %q", vol.Source)
}
@@ -421,6 +421,9 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
for _, v := range volumes {
if volume, err := runtime.state.Volume(v); err == nil {
+ if !volume.IsCtrSpecific() {
+ continue
+ }
if err := runtime.removeVolume(ctx, volume, false); err != nil && err != ErrNoSuchVolume && err != ErrVolumeBeingUsed {
logrus.Errorf("cleanup volume (%s): %v", v, err)
}
diff --git a/libpod/volume.go b/libpod/volume.go
index 74878b6a4..0c7618841 100644
--- a/libpod/volume.go
+++ b/libpod/volume.go
@@ -15,11 +15,12 @@ type VolumeConfig struct {
// Name of the volume
Name string `json:"name"`
- Labels map[string]string `json:"labels"`
- MountPoint string `json:"mountPoint"`
- Driver string `json:"driver"`
- Options map[string]string `json:"options"`
- Scope string `json:"scope"`
+ Labels map[string]string `json:"labels"`
+ MountPoint string `json:"mountPoint"`
+ Driver string `json:"driver"`
+ Options map[string]string `json:"options"`
+ Scope string `json:"scope"`
+ IsCtrSpecific bool `json:"ctrSpecific"`
}
// Name retrieves the volume's name
@@ -60,3 +61,10 @@ func (v *Volume) Options() map[string]string {
func (v *Volume) Scope() string {
return v.config.Scope
}
+
+// IsCtrSpecific returns whether this volume was created specifically for a
+// given container. Images with this set to true will be removed when the
+// container is removed with the Volumes parameter set to true.
+func (v *Volume) IsCtrSpecific() bool {
+ return v.config.IsCtrSpecific
+}