summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/boltdb_state_internal.go9
-rw-r--r--libpod/container.go13
-rw-r--r--libpod/container_api.go2
-rw-r--r--libpod/container_config.go2
-rw-r--r--libpod/container_inspect.go15
-rw-r--r--libpod/container_internal.go19
-rw-r--r--libpod/container_internal_linux.go52
-rw-r--r--libpod/container_validate.go10
-rw-r--r--libpod/define/errors.go9
-rw-r--r--libpod/define/podstate.go7
-rw-r--r--libpod/image/utils.go3
-rw-r--r--libpod/options.go19
-rw-r--r--libpod/pod_api.go2
-rw-r--r--libpod/pod_status.go8
-rw-r--r--libpod/runtime_pod_infra_linux.go1
15 files changed, 152 insertions, 19 deletions
diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go
index e195ca314..2f485318c 100644
--- a/libpod/boltdb_state_internal.go
+++ b/libpod/boltdb_state_internal.go
@@ -3,6 +3,7 @@ package libpod
import (
"bytes"
"os"
+ "path/filepath"
"runtime"
"strings"
@@ -104,25 +105,25 @@ func checkRuntimeConfig(db *bolt.DB, rt *Runtime) error {
},
{
"libpod root directory (staticdir)",
- rt.config.Engine.StaticDir,
+ filepath.Clean(rt.config.Engine.StaticDir),
staticDirKey,
"",
},
{
"libpod temporary files directory (tmpdir)",
- rt.config.Engine.TmpDir,
+ filepath.Clean(rt.config.Engine.TmpDir),
tmpDirKey,
"",
},
{
"storage temporary directory (runroot)",
- rt.StorageConfig().RunRoot,
+ filepath.Clean(rt.StorageConfig().RunRoot),
runRootKey,
storeOpts.RunRoot,
},
{
"storage graph root directory (graphroot)",
- rt.StorageConfig().GraphRoot,
+ filepath.Clean(rt.StorageConfig().GraphRoot),
graphRootKey,
storeOpts.GraphRoot,
},
diff --git a/libpod/container.go b/libpod/container.go
index 01419500e..ea5a6e09c 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -235,6 +235,19 @@ type ContainerOverlayVolume struct {
Source string `json:"source,omitempty"`
}
+// ContainerImageVolume is a volume based on a container image. The container
+// image is first mounted on the host and is then bind-mounted into the
+// container.
+type ContainerImageVolume struct {
+ // Source is the source of the image volume. The image can be referred
+ // to by name and by ID.
+ Source string `json:"source"`
+ // Dest is the absolute path of the mount in the container.
+ Dest string `json:"dest"`
+ // ReadWrite sets the volume writable.
+ ReadWrite bool `json:"rw"`
+}
+
// Config accessors
// Unlocked
diff --git a/libpod/container_api.go b/libpod/container_api.go
index aef37dd59..a9808a30e 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -249,7 +249,7 @@ func (c *Container) Attach(streams *define.AttachStreams, keys string, resize <-
// attaching, and I really do not want to do that right now.
// Send a SIGWINCH after attach succeeds so that most programs will
// redraw the screen for the new attach session.
- attachRdy := make(chan bool)
+ attachRdy := make(chan bool, 1)
if c.config.Spec.Process != nil && c.config.Spec.Process.Terminal {
go func() {
<-attachRdy
diff --git a/libpod/container_config.go b/libpod/container_config.go
index e264da4da..0006613bc 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -134,6 +134,8 @@ type ContainerRootFSConfig struct {
NamedVolumes []*ContainerNamedVolume `json:"namedVolumes,omitempty"`
// OverlayVolumes lists the overlay volumes to mount into the container.
OverlayVolumes []*ContainerOverlayVolume `json:"overlayVolumes,omitempty"`
+ // ImageVolumes lists the image volumes to mount into the container.
+ ImageVolumes []*ContainerImageVolume `json:"imageVolumes,omitempty"`
// CreateWorkingDir indicates that Libpod should create the container's
// working directory if it does not exist. Some OCI runtimes do this by
// default, but others do not.
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index b8bce1272..162f70326 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -90,7 +90,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data)
}
namedVolumes, mounts := c.sortUserVolumes(ctrSpec)
- inspectMounts, err := c.getInspectMounts(namedVolumes, mounts)
+ inspectMounts, err := c.getInspectMounts(namedVolumes, c.config.ImageVolumes, mounts)
if err != nil {
return nil, err
}
@@ -192,7 +192,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data)
// Get inspect-formatted mounts list.
// Only includes user-specified mounts. Only includes bind mounts and named
// volumes, not tmpfs volumes.
-func (c *Container) getInspectMounts(namedVolumes []*ContainerNamedVolume, mounts []spec.Mount) ([]define.InspectMount, error) {
+func (c *Container) getInspectMounts(namedVolumes []*ContainerNamedVolume, imageVolumes []*ContainerImageVolume, mounts []spec.Mount) ([]define.InspectMount, error) {
inspectMounts := []define.InspectMount{}
// No mounts, return early
@@ -219,6 +219,17 @@ func (c *Container) getInspectMounts(namedVolumes []*ContainerNamedVolume, mount
inspectMounts = append(inspectMounts, mountStruct)
}
+
+ for _, volume := range imageVolumes {
+ mountStruct := define.InspectMount{}
+ mountStruct.Type = "image"
+ mountStruct.Destination = volume.Dest
+ mountStruct.Source = volume.Source
+ mountStruct.RW = volume.ReadWrite
+
+ inspectMounts = append(inspectMounts, mountStruct)
+ }
+
for _, mount := range mounts {
// It's a mount.
// Is it a tmpfs? If so, discard.
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 4ae571de6..cafe70b80 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1734,6 +1734,25 @@ func (c *Container) cleanup(ctx context.Context) error {
}
}
+ // Unmount image volumes
+ for _, v := range c.config.ImageVolumes {
+ img, err := c.runtime.ImageRuntime().NewFromLocal(v.Source)
+ if err != nil {
+ if lastError == nil {
+ lastError = err
+ continue
+ }
+ logrus.Errorf("error unmounting image volume %q:%q :%v", v.Source, v.Dest, err)
+ }
+ if err := img.Unmount(false); err != nil {
+ if lastError == nil {
+ lastError = err
+ continue
+ }
+ logrus.Errorf("error unmounting image volume %q:%q :%v", v.Source, v.Dest, err)
+ }
+ }
+
return lastError
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index a1b4334fb..043924166 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -39,6 +39,7 @@ import (
"github.com/containers/storage/pkg/idtools"
securejoin "github.com/cyphar/filepath-securejoin"
runcuser "github.com/opencontainers/runc/libcontainer/user"
+ "github.com/opencontainers/runtime-spec/specs-go"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux/label"
@@ -368,6 +369,35 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
g.AddMount(overlayMount)
}
+ // Add image volumes as overlay mounts
+ for _, volume := range c.config.ImageVolumes {
+ // Mount the specified image.
+ img, err := c.runtime.ImageRuntime().NewFromLocal(volume.Source)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error creating image volume %q:%q", volume.Source, volume.Dest)
+ }
+ mountPoint, err := img.Mount(nil, "")
+ if err != nil {
+ return nil, errors.Wrapf(err, "error mounting image volume %q:%q", volume.Source, volume.Dest)
+ }
+
+ contentDir, err := overlay.TempDir(c.config.StaticDir, c.RootUID(), c.RootGID())
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to create TempDir in the %s directory", c.config.StaticDir)
+ }
+
+ var overlayMount specs.Mount
+ if volume.ReadWrite {
+ overlayMount, err = overlay.Mount(contentDir, mountPoint, volume.Dest, c.RootUID(), c.RootGID(), c.runtime.store.GraphOptions())
+ } else {
+ overlayMount, err = overlay.MountReadOnly(contentDir, mountPoint, volume.Dest, c.RootUID(), c.RootGID(), c.runtime.store.GraphOptions())
+ }
+ if err != nil {
+ return nil, errors.Wrapf(err, "creating overlay mount for image %q failed", volume.Source)
+ }
+ g.AddMount(overlayMount)
+ }
+
hasHomeSet := false
for _, s := range c.config.Spec.Process.Env {
if strings.HasPrefix(s, "HOME=") {
@@ -668,11 +698,31 @@ func (c *Container) setupSystemd(mounts []spec.Mount, g generate.Generator) erro
}
g.AddMount(systemdMnt)
} else {
+ mountOptions := []string{"bind", "rprivate"}
+
+ var statfs unix.Statfs_t
+ if err := unix.Statfs("/sys/fs/cgroup/systemd", &statfs); err != nil {
+ mountOptions = append(mountOptions, "nodev", "noexec", "nosuid")
+ } else {
+ if statfs.Flags&unix.MS_NODEV == unix.MS_NODEV {
+ mountOptions = append(mountOptions, "nodev")
+ }
+ if statfs.Flags&unix.MS_NOEXEC == unix.MS_NOEXEC {
+ mountOptions = append(mountOptions, "noexec")
+ }
+ if statfs.Flags&unix.MS_NOSUID == unix.MS_NOSUID {
+ mountOptions = append(mountOptions, "nosuid")
+ }
+ if statfs.Flags&unix.MS_RDONLY == unix.MS_RDONLY {
+ mountOptions = append(mountOptions, "ro")
+ }
+ }
+
systemdMnt := spec.Mount{
Destination: "/sys/fs/cgroup/systemd",
Type: "bind",
Source: "/sys/fs/cgroup/systemd",
- Options: []string{"bind", "nodev", "noexec", "nosuid", "rprivate"},
+ Options: mountOptions,
}
g.AddMount(systemdMnt)
g.AddLinuxMaskedPaths("/sys/fs/cgroup/systemd/release_agent")
diff --git a/libpod/container_validate.go b/libpod/container_validate.go
index b78168cd1..68cc095b7 100644
--- a/libpod/container_validate.go
+++ b/libpod/container_validate.go
@@ -88,7 +88,7 @@ func (c *Container) validate() error {
return errors.Wrapf(define.ErrInvalidArg, "cannot add to /etc/hosts if using image's /etc/hosts")
}
- // Check named volume and overlay volumes destination conflits
+ // Check named volume, overlay volume and image volume destination conflits
destinations := make(map[string]bool)
for _, vol := range c.config.NamedVolumes {
// Don't check if they already exist.
@@ -106,6 +106,14 @@ func (c *Container) validate() error {
}
destinations[vol.Dest] = true
}
+ for _, vol := range c.config.ImageVolumes {
+ // Don't check if they already exist.
+ // If they don't we will automatically create them.
+ if _, ok := destinations[vol.Dest]; ok {
+ return errors.Wrapf(define.ErrInvalidArg, "two volumes found with destination %s", vol.Dest)
+ }
+ destinations[vol.Dest] = true
+ }
return nil
}
diff --git a/libpod/define/errors.go b/libpod/define/errors.go
index 627928ef7..1b21cd1ce 100644
--- a/libpod/define/errors.go
+++ b/libpod/define/errors.go
@@ -14,6 +14,9 @@ var (
// ErrNoSuchImage indicates the requested image does not exist
ErrNoSuchImage = errors.New("no such image")
+ // ErrMultipleImages found multiple name and tag matches
+ ErrMultipleImages = errors.New("found multiple name and tag matches")
+
// ErrNoSuchTag indicates the requested image tag does not exist
ErrNoSuchTag = errors.New("no such tag")
@@ -138,15 +141,15 @@ var (
// ErrOCIRuntimePermissionDenied indicates the OCI runtime attempted to invoke a command that returned
// a permission denied error
- ErrOCIRuntimePermissionDenied = errors.New("OCI runtime permission denied error")
+ ErrOCIRuntimePermissionDenied = errors.New("OCI permission denied")
// ErrOCIRuntimeNotFound indicates the OCI runtime attempted to invoke a command
// that was not found
- ErrOCIRuntimeNotFound = errors.New("OCI runtime command not found error")
+ ErrOCIRuntimeNotFound = errors.New("OCI not found")
// ErrOCIRuntimeUnavailable indicates that the OCI runtime associated to a container
// could not be found in the configuration
- ErrOCIRuntimeUnavailable = errors.New("OCI runtime not available in the current configuration")
+ ErrOCIRuntimeUnavailable = errors.New("OCI unavailable")
// ErrConmonOutdated indicates the version of conmon found (whether via the configuration or $PATH)
// is out of date for the current podman version
diff --git a/libpod/define/podstate.go b/libpod/define/podstate.go
index 2b59aabfb..e02671972 100644
--- a/libpod/define/podstate.go
+++ b/libpod/define/podstate.go
@@ -10,9 +10,12 @@ const (
PodStateExited = "Exited"
// PodStatePaused indicates the pod has been paused
PodStatePaused = "Paused"
- // PodStateRunning indicates that one or more of the containers in
- // the pod is running
+ // PodStateRunning indicates that all of the containers in the pod are
+ // running.
PodStateRunning = "Running"
+ // PodStateDegraded indicates that at least one, but not all, of the
+ // containers in the pod are running.
+ PodStateDegraded = "Degraded"
// PodStateStopped indicates all of the containers belonging to the pod
// are stopped.
PodStateStopped = "Stopped"
diff --git a/libpod/image/utils.go b/libpod/image/utils.go
index 2538f429b..7429a7f10 100644
--- a/libpod/image/utils.go
+++ b/libpod/image/utils.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/signature"
"github.com/containers/image/v5/types"
+ "github.com/containers/podman/v2/libpod/define"
"github.com/containers/storage"
"github.com/pkg/errors"
)
@@ -42,7 +43,7 @@ func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, er
if len(results) == 0 {
return &storage.Image{}, errors.Errorf("unable to find a name and tag match for %s in repotags", searchName)
} else if len(results) > 1 {
- return &storage.Image{}, errors.Errorf("found multiple name and tag matches for %s in repotags", searchName)
+ return &storage.Image{}, errors.Wrapf(define.ErrMultipleImages, searchName)
}
return results[0], nil
}
diff --git a/libpod/options.go b/libpod/options.go
index 1ffb78da9..5d1ce8755 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1439,6 +1439,25 @@ func WithOverlayVolumes(volumes []*ContainerOverlayVolume) CtrCreateOption {
}
}
+// WithImageVolumes adds the given image volumes to the container.
+func WithImageVolumes(volumes []*ContainerImageVolume) CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return define.ErrCtrFinalized
+ }
+
+ for _, vol := range volumes {
+ ctr.config.ImageVolumes = append(ctr.config.ImageVolumes, &ContainerImageVolume{
+ Dest: vol.Dest,
+ Source: vol.Source,
+ ReadWrite: vol.ReadWrite,
+ })
+ }
+
+ return nil
+ }
+}
+
// WithHealthCheck adds the healthcheck to the container config
func WithHealthCheck(healthCheck *manifest.Schema2HealthConfig) CtrCreateOption {
return func(ctr *Container) error {
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index f2ddba9c9..87ac5c07a 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -506,7 +506,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
})
ctrStatuses[c.ID()] = c.state.State
}
- podState, err := CreatePodStatusResults(ctrStatuses)
+ podState, err := createPodStatusResults(ctrStatuses)
if err != nil {
return nil, err
}
diff --git a/libpod/pod_status.go b/libpod/pod_status.go
index f4ccf308a..668d45ec7 100644
--- a/libpod/pod_status.go
+++ b/libpod/pod_status.go
@@ -10,10 +10,10 @@ func (p *Pod) GetPodStatus() (string, error) {
if err != nil {
return define.PodStateErrored, err
}
- return CreatePodStatusResults(ctrStatuses)
+ return createPodStatusResults(ctrStatuses)
}
-func CreatePodStatusResults(ctrStatuses map[string]define.ContainerStatus) (string, error) {
+func createPodStatusResults(ctrStatuses map[string]define.ContainerStatus) (string, error) {
ctrNum := len(ctrStatuses)
if ctrNum == 0 {
return define.PodStateCreated, nil
@@ -43,8 +43,10 @@ func CreatePodStatusResults(ctrStatuses map[string]define.ContainerStatus) (stri
}
switch {
- case statuses[define.PodStateRunning] > 0:
+ case statuses[define.PodStateRunning] == ctrNum:
return define.PodStateRunning, nil
+ case statuses[define.PodStateRunning] > 0:
+ return define.PodStateDegraded, nil
case statuses[define.PodStatePaused] == ctrNum:
return define.PodStatePaused, nil
case statuses[define.PodStateStopped] == ctrNum:
diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index 7f58e86d8..76419587a 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -131,6 +131,7 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
logrus.Debugf("Using %q as infra container entrypoint", entryCmd)
+ g.RemoveMount("/dev/shm")
if isRootless {
g.RemoveMount("/dev/pts")
devPts := spec.Mount{