summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/boltdb_state_internal.go11
-rw-r--r--libpod/common/common.go15
-rw-r--r--libpod/container.go25
-rw-r--r--libpod/container_internal.go47
-rw-r--r--libpod/container_internal_linux.go25
-rw-r--r--libpod/events.go6
-rw-r--r--libpod/image/image.go5
-rw-r--r--libpod/image/pull.go2
-rw-r--r--libpod/image/search.go3
-rw-r--r--libpod/info.go9
-rw-r--r--libpod/oci.go10
-rw-r--r--libpod/oci_linux.go91
-rw-r--r--libpod/options.go35
-rw-r--r--libpod/pod_api.go5
-rw-r--r--libpod/runtime.go56
-rw-r--r--libpod/runtime_ctr.go16
-rw-r--r--libpod/runtime_volume_linux.go24
-rw-r--r--libpod/util.go10
-rw-r--r--libpod/util_linux.go21
-rw-r--r--libpod/util_unsupported.go6
-rw-r--r--libpod/volume.go2
21 files changed, 214 insertions, 210 deletions
diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go
index 936ccbf4c..b6a0759b1 100644
--- a/libpod/boltdb_state_internal.go
+++ b/libpod/boltdb_state_internal.go
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/boltdb/bolt"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -95,22 +96,26 @@ func checkRuntimeConfig(db *bolt.DB, rt *Runtime) error {
return err
}
+ storeOpts, err := storage.DefaultStoreOptions(rootless.IsRootless(), rootless.GetRootlessUID())
+ if err != nil {
+ return err
+ }
if err := validateDBAgainstConfig(configBkt, "storage temporary directory (runroot)",
rt.config.StorageConfig.RunRoot, runRootKey,
- storage.DefaultStoreOptions.RunRoot); err != nil {
+ storeOpts.RunRoot); err != nil {
return err
}
if err := validateDBAgainstConfig(configBkt, "storage graph root directory (graphroot)",
rt.config.StorageConfig.GraphRoot, graphRootKey,
- storage.DefaultStoreOptions.GraphRoot); err != nil {
+ storeOpts.GraphRoot); err != nil {
return err
}
if err := validateDBAgainstConfig(configBkt, "storage graph driver",
rt.config.StorageConfig.GraphDriverName,
graphDriverKey,
- storage.DefaultStoreOptions.GraphDriverName); err != nil {
+ storeOpts.GraphDriverName); err != nil {
return err
}
diff --git a/libpod/common/common.go b/libpod/common/common.go
index 5d10bee36..93a736af2 100644
--- a/libpod/common/common.go
+++ b/libpod/common/common.go
@@ -1,20 +1,5 @@
package common
-import (
- "github.com/containers/image/types"
-)
-
-// GetSystemContext Constructs a new containers/image/types.SystemContext{} struct from the given signaturePolicy path
-func GetSystemContext(signaturePolicyPath, authFilePath string, forceCompress bool) *types.SystemContext {
- sc := &types.SystemContext{}
- if signaturePolicyPath != "" {
- sc.SignaturePolicyPath = signaturePolicyPath
- }
- sc.AuthFilePath = authFilePath
- sc.DirForceCompress = forceCompress
- return sc
-}
-
// IsTrue determines whether the given string equals "true"
func IsTrue(str string) bool {
return str == "true"
diff --git a/libpod/container.go b/libpod/container.go
index 806e75c63..739406e42 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -17,7 +17,6 @@ import (
"github.com/cri-o/ocicni/pkg/ocicni"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
- "github.com/ulule/deepcopier"
)
// ContainerStatus represents the current state of a container
@@ -147,18 +146,12 @@ type ContainerState struct {
ConfigPath string `json:"configPath,omitempty"`
// RunDir is a per-boot directory for container content
RunDir string `json:"runDir,omitempty"`
- // DestinationRunDir is where the files in RunDir will be accessible for the container.
- // It is different than RunDir when using userNS
- DestinationRunDir string `json:"destinationRunDir,omitempty"`
// Mounted indicates whether the container's storage has been mounted
// for use
Mounted bool `json:"mounted,omitempty"`
// Mountpoint contains the path to the container's mounted storage as given
- // by containers/storage. It can be different than RealMountpoint when
- // usernamespaces are used
+ // by containers/storage.
Mountpoint string `json:"mountPoint,omitempty"`
- // RealMountpoint contains the path to the container's mounted storage
- RealMountpoint string `json:"realMountPoint,omitempty"`
// StartedTime is the time the container was started
StartedTime time.Time `json:"startedTime,omitempty"`
// FinishedTime is the time the container finished executing
@@ -187,10 +180,6 @@ type ContainerState struct {
// the path of the file on disk outside the container
BindMounts map[string]string `json:"bindMounts,omitempty"`
- // UserNSRoot is the directory used as root for the container when using
- // user namespaces.
- UserNSRoot string `json:"userNSRoot,omitempty"`
-
// ExtensionStageHooks holds hooks which will be executed by libpod
// and not delegated to the OCI runtime.
ExtensionStageHooks map[string][]spec.Hook `json:"extensionStageHooks,omitempty"`
@@ -407,7 +396,9 @@ func (t ContainerStatus) String() string {
// Config returns the configuration used to create the container
func (c *Container) Config() *ContainerConfig {
returnConfig := new(ContainerConfig)
- deepcopier.Copy(c.config).To(returnConfig)
+ if err := JSONDeepCopy(c.config, returnConfig); err != nil {
+ return nil
+ }
return returnConfig
}
@@ -417,7 +408,9 @@ func (c *Container) Config() *ContainerConfig {
// spec may differ slightly as mounts are added based on the image
func (c *Container) Spec() *spec.Spec {
returnSpec := new(spec.Spec)
- deepcopier.Copy(c.config.Spec).To(returnSpec)
+ if err := JSONDeepCopy(c.config.Spec, returnSpec); err != nil {
+ return nil
+ }
return returnSpec
}
@@ -1094,7 +1087,9 @@ func (c *Container) ContainerState() (*ContainerState, error) {
}
}
returnConfig := new(ContainerState)
- deepcopier.Copy(c.state).To(returnConfig)
+ if err := JSONDeepCopy(c.state, returnConfig); err != nil {
+ return nil, errors.Wrapf(err, "error copying container %s state", c.ID())
+ }
return c.state, nil
}
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 7a90bc7d4..daa32007a 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -310,23 +310,12 @@ func (c *Container) setupStorage(ctx context.Context) error {
}
if !rootless.IsRootless() && (len(c.config.IDMappings.UIDMap) != 0 || len(c.config.IDMappings.GIDMap) != 0) {
- info, err := os.Stat(c.runtime.config.TmpDir)
- if err != nil {
- return errors.Wrapf(err, "cannot stat `%s`", c.runtime.config.TmpDir)
- }
- if err := os.Chmod(c.runtime.config.TmpDir, info.Mode()|0111); err != nil {
- return errors.Wrapf(err, "cannot chmod `%s`", c.runtime.config.TmpDir)
- }
- root := filepath.Join(c.runtime.config.TmpDir, "containers-root", c.ID())
- if err := os.MkdirAll(root, 0755); err != nil {
- return errors.Wrapf(err, "error creating userNS tmpdir for container %s", c.ID())
- }
- if err := os.Chown(root, c.RootUID(), c.RootGID()); err != nil {
+ if err := os.Chown(containerInfo.RunDir, c.RootUID(), c.RootGID()); err != nil {
return err
}
- c.state.UserNSRoot, err = filepath.EvalSymlinks(root)
- if err != nil {
- return errors.Wrapf(err, "failed to eval symlinks for %s", root)
+
+ if err := os.Chown(containerInfo.Dir, c.RootUID(), c.RootGID()); err != nil {
+ return err
}
}
@@ -334,10 +323,6 @@ func (c *Container) setupStorage(ctx context.Context) error {
c.config.MountLabel = containerInfo.MountLabel
c.config.StaticDir = containerInfo.Dir
c.state.RunDir = containerInfo.RunDir
- c.state.DestinationRunDir = c.state.RunDir
- if c.state.UserNSRoot != "" {
- c.state.DestinationRunDir = filepath.Join(c.state.UserNSRoot, "rundir")
- }
// Set the default Entrypoint and Command
if containerInfo.Config != nil {
@@ -372,12 +357,6 @@ func (c *Container) teardownStorage() error {
return errors.Wrapf(err, "failed to cleanup container %s storage", c.ID())
}
- if c.state.UserNSRoot != "" {
- if err := os.RemoveAll(c.state.UserNSRoot); err != nil {
- return errors.Wrapf(err, "error removing userns root %q", c.state.UserNSRoot)
- }
- }
-
if err := c.runtime.storageService.DeleteContainer(c.ID()); err != nil {
// If the container has already been removed, warn but do not
// error - we wanted it gone, it is already gone.
@@ -432,6 +411,7 @@ func (c *Container) refresh() error {
if err != nil {
return errors.Wrapf(err, "error retrieving temporary directory for container %s", c.ID())
}
+ c.state.RunDir = dir
if len(c.config.IDMappings.UIDMap) != 0 || len(c.config.IDMappings.GIDMap) != 0 {
info, err := os.Stat(c.runtime.config.TmpDir)
@@ -448,16 +428,6 @@ func (c *Container) refresh() error {
if err := os.Chown(root, c.RootUID(), c.RootGID()); err != nil {
return err
}
- c.state.UserNSRoot, err = filepath.EvalSymlinks(root)
- if err != nil {
- return errors.Wrapf(err, "failed to eval symlinks for %s", root)
- }
- }
-
- c.state.RunDir = dir
- c.state.DestinationRunDir = c.state.RunDir
- if c.state.UserNSRoot != "" {
- c.state.DestinationRunDir = filepath.Join(c.state.UserNSRoot, "rundir")
}
// We need to pick up a new lock
@@ -1260,7 +1230,7 @@ func (c *Container) writeStringToRundir(destFile, output string) (string, error)
return "", err
}
- return filepath.Join(c.state.DestinationRunDir, destFile), nil
+ return filepath.Join(c.state.RunDir, destFile), nil
}
// appendStringToRundir appends the provided string to the runtimedir file
@@ -1277,7 +1247,7 @@ func (c *Container) appendStringToRundir(destFile, output string) (string, error
return "", errors.Wrapf(err, "unable to write %s", destFileName)
}
- return filepath.Join(c.state.DestinationRunDir, destFile), nil
+ return filepath.Join(c.state.RunDir, destFile), nil
}
// Save OCI spec to disk, replacing any existing specs for the container
@@ -1410,6 +1380,9 @@ func (c *Container) mount() (string, error) {
if err != nil {
return "", errors.Wrapf(err, "error resolving storage path for container %s", c.ID())
}
+ if err := os.Chown(mountPoint, c.RootUID(), c.RootGID()); err != nil {
+ return "", errors.Wrapf(err, "cannot chown %s to %d:%d", mountPoint, c.RootUID(), c.RootGID())
+ }
return mountPoint, nil
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 02f8d6aa4..504d6c135 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -25,7 +25,6 @@ import (
"github.com/containers/libpod/pkg/lookup"
"github.com/containers/libpod/pkg/resolvconf"
"github.com/containers/libpod/pkg/rootless"
- "github.com/containers/storage/pkg/idtools"
"github.com/cyphar/filepath-securejoin"
"github.com/opencontainers/runc/libcontainer/user"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -99,11 +98,6 @@ func (c *Container) prepare() (err error) {
// Finish up mountStorage
c.state.Mounted = true
c.state.Mountpoint = mountPoint
- if c.state.UserNSRoot == "" {
- c.state.RealMountpoint = c.state.Mountpoint
- } else {
- c.state.RealMountpoint = filepath.Join(c.state.UserNSRoot, "mountpoint")
- }
logrus.Debugf("Created root filesystem for container %s at %s", c.ID(), c.state.Mountpoint)
}()
@@ -220,13 +214,6 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
}
m.Options = options
-
- // If we are using a user namespace, we will use an intermediate
- // directory to bind mount volumes
- if c.state.UserNSRoot != "" && strings.HasPrefix(m.Source, c.runtime.config.VolumePath) {
- newSourceDir := filepath.Join(c.state.UserNSRoot, "volumes")
- m.Source = strings.Replace(m.Source, c.runtime.config.VolumePath, newSourceDir, 1)
- }
}
g.SetProcessSelinuxLabel(c.ProcessLabel())
@@ -313,13 +300,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
}
- if c.config.Rootfs == "" {
- if err := idtools.MkdirAllAs(c.state.RealMountpoint, 0700, c.RootUID(), c.RootGID()); err != nil {
- return nil, err
- }
- }
-
- g.SetRootPath(c.state.RealMountpoint)
+ g.SetRootPath(c.state.Mountpoint)
g.AddAnnotation(crioAnnotations.Created, c.config.CreatedTime.Format(time.RFC3339Nano))
g.AddAnnotation("org.opencontainers.image.stopSignal", fmt.Sprintf("%d", c.config.StopSignal))
@@ -820,7 +801,7 @@ func (c *Container) makeBindMounts() error {
}
// Add Secret Mounts
- secretMounts := secrets.SecretMountsWithUIDGID(c.config.MountLabel, c.state.RunDir, c.runtime.config.DefaultMountsFile, c.state.DestinationRunDir, c.RootUID(), c.RootGID())
+ secretMounts := secrets.SecretMountsWithUIDGID(c.config.MountLabel, c.state.RunDir, c.runtime.config.DefaultMountsFile, c.state.RunDir, c.RootUID(), c.RootGID(), rootless.IsRootless())
for _, mount := range secretMounts {
if _, ok := c.state.BindMounts[mount.Destination]; !ok {
c.state.BindMounts[mount.Destination] = mount.Source
@@ -907,7 +888,7 @@ func (c *Container) generateResolvConf() (string, error) {
return "", err
}
- return filepath.Join(c.state.DestinationRunDir, "resolv.conf"), nil
+ return filepath.Join(c.state.RunDir, "resolv.conf"), nil
}
// generateHosts creates a containers hosts file
diff --git a/libpod/events.go b/libpod/events.go
index 139600982..b6a277789 100644
--- a/libpod/events.go
+++ b/libpod/events.go
@@ -58,6 +58,10 @@ func (v *Volume) newVolumeEvent(status events.Status) {
// Events is a wrapper function for everyone to begin tailing the events log
// with options
func (r *Runtime) Events(fromStart, stream bool, options []events.EventFilter, eventChannel chan *events.Event) error {
+ if !r.valid {
+ return ErrRuntimeStopped
+ }
+
t, err := r.getTail(fromStart, stream)
if err != nil {
return err
@@ -71,7 +75,7 @@ func (r *Runtime) Events(fromStart, stream bool, options []events.EventFilter, e
case events.Image, events.Volume, events.Pod, events.Container:
// no-op
default:
- return errors.Errorf("event type %s is not valid in %s", event.Type.String(), r.GetConfig().EventsLogFilePath)
+ return errors.Errorf("event type %s is not valid in %s", event.Type.String(), r.config.EventsLogFilePath)
}
include := true
for _, filter := range options {
diff --git a/libpod/image/image.go b/libpod/image/image.go
index f79bc3dc2..4862bf1d6 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"os"
+ "path/filepath"
"strings"
"syscall"
"time"
@@ -22,7 +23,6 @@ import (
"github.com/containers/image/transports"
"github.com/containers/image/transports/alltransports"
"github.com/containers/image/types"
- "github.com/containers/libpod/libpod/common"
"github.com/containers/libpod/libpod/driver"
"github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/pkg/inspect"
@@ -548,6 +548,7 @@ func (i *Image) PushImageToHeuristicDestination(ctx context.Context, destination
// PushImageToReference pushes the given image to a location described by the given path
func (i *Image) PushImageToReference(ctx context.Context, dest types.ImageReference, manifestMIMEType, authFile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions SigningOptions, dockerRegistryOptions *DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
sc := GetSystemContext(signaturePolicyPath, authFile, forceCompress)
+ sc.BlobInfoCacheDir = filepath.Join(i.imageruntime.store.GraphRoot(), "cache")
policyContext, err := getPolicyContext(sc)
if err != nil {
@@ -909,7 +910,7 @@ func (ir *Runtime) Import(ctx context.Context, path, reference string, writer io
return nil, errors.Wrapf(err, "error updating image config")
}
- sc := common.GetSystemContext("", "", false)
+ sc := GetSystemContext("", "", false)
// if reference not given, get the image digest
if reference == "" {
diff --git a/libpod/image/pull.go b/libpod/image/pull.go
index a3b716e65..5a0706b07 100644
--- a/libpod/image/pull.go
+++ b/libpod/image/pull.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
+ "path/filepath"
"strings"
cp "github.com/containers/image/copy"
@@ -204,6 +205,7 @@ func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName s
var goal *pullGoal
sc := GetSystemContext(signaturePolicyPath, authfile, false)
+ sc.BlobInfoCacheDir = filepath.Join(ir.store.GraphRoot(), "cache")
srcRef, err := alltransports.ParseImageName(inputName)
if err != nil {
// could be trying to pull from registry with short name
diff --git a/libpod/image/search.go b/libpod/image/search.go
index 212eff00b..2c66ce284 100644
--- a/libpod/image/search.go
+++ b/libpod/image/search.go
@@ -9,7 +9,6 @@ import (
"github.com/containers/image/docker"
"github.com/containers/image/types"
- "github.com/containers/libpod/libpod/common"
sysreg "github.com/containers/libpod/pkg/registries"
"github.com/fatih/camelcase"
"github.com/pkg/errors"
@@ -157,7 +156,7 @@ func searchImageInRegistry(term string, registry string, options SearchOptions)
limit = options.Limit
}
- sc := common.GetSystemContext("", options.Authfile, false)
+ sc := GetSystemContext("", options.Authfile, false)
sc.DockerInsecureSkipTLSVerify = options.InsecureSkipTLSVerify
// FIXME: Set this more globally. Probably no reason not to have it in
// every types.SystemContext, and to compute the value just once in one
diff --git a/libpod/info.go b/libpod/info.go
index 62088b730..b42f64a1f 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -13,8 +13,8 @@ import (
"github.com/containers/buildah"
"github.com/containers/libpod/pkg/rootless"
- "github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/utils"
+ "github.com/containers/storage"
"github.com/containers/storage/pkg/system"
"github.com/pkg/errors"
)
@@ -116,12 +116,17 @@ func (r *Runtime) hostInfo() (map[string]interface{}, error) {
func (r *Runtime) storeInfo() (map[string]interface{}, error) {
// lets say storage driver in use, number of images, number of containers
info := map[string]interface{}{}
- info["ConfigFile"] = util.StorageConfigFile()
info["GraphRoot"] = r.store.GraphRoot()
info["RunRoot"] = r.store.RunRoot()
info["GraphDriverName"] = r.store.GraphDriverName()
info["GraphOptions"] = r.store.GraphOptions()
info["VolumePath"] = r.config.VolumePath
+
+ configFile, err := storage.DefaultConfigFile(rootless.IsRootless())
+ if err != nil {
+ return nil, err
+ }
+ info["ConfigFile"] = configFile
statusPairs, err := r.store.Status()
if err != nil {
return nil, err
diff --git a/libpod/oci.go b/libpod/oci.go
index 69cff6d3c..62331b879 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -325,8 +325,8 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res
cmd.Env = append(r.conmonEnv, fmt.Sprintf("_OCI_SYNCPIPE=%d", 3))
cmd.Env = append(cmd.Env, fmt.Sprintf("_OCI_STARTPIPE=%d", 4))
cmd.Env = append(cmd.Env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir))
- cmd.Env = append(cmd.Env, fmt.Sprintf("_LIBPOD_USERNS_CONFIGURED=%s", os.Getenv("_LIBPOD_USERNS_CONFIGURED")))
- cmd.Env = append(cmd.Env, fmt.Sprintf("_LIBPOD_ROOTLESS_UID=%s", os.Getenv("_LIBPOD_ROOTLESS_UID")))
+ cmd.Env = append(cmd.Env, fmt.Sprintf("_CONTAINERS_USERNS_CONFIGURED=%s", os.Getenv("_CONTAINERS_USERNS_CONFIGURED")))
+ cmd.Env = append(cmd.Env, fmt.Sprintf("_CONTAINERS_ROOTLESS_UID=%s", os.Getenv("_CONTAINERS_ROOTLESS_UID")))
cmd.Env = append(cmd.Env, fmt.Sprintf("HOME=%s", os.Getenv("HOME")))
if r.reservePorts && !ctr.config.NetMode.IsSlirp4netns() {
@@ -473,7 +473,7 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res
// If useRunc is false, we will not directly hit runc to see the container's
// status, but will instead only check for the existence of the conmon exit file
// and update state to stopped if it exists.
-func (r *OCIRuntime) updateContainerStatus(ctr *Container, useRunc bool) error {
+func (r *OCIRuntime) updateContainerStatus(ctr *Container, useRuntime bool) error {
exitFile := ctr.exitFilePath()
runtimeDir, err := util.GetRootlessRuntimeDir()
@@ -481,8 +481,8 @@ func (r *OCIRuntime) updateContainerStatus(ctr *Container, useRunc bool) error {
return err
}
- // If not using runc, we don't need to do most of this.
- if !useRunc {
+ // If not using the OCI runtime, we don't need to do most of this.
+ if !useRuntime {
// If the container's not running, nothing to do.
if ctr.state.State != ContainerStateRunning && ctr.state.State != ContainerStatePaused {
return nil
diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go
index f85c5ee62..8c0abad80 100644
--- a/libpod/oci_linux.go
+++ b/libpod/oci_linux.go
@@ -3,17 +3,14 @@
package libpod
import (
- "fmt"
"os"
"os/exec"
"path/filepath"
- "runtime"
"strings"
- "sync"
+ "syscall"
"github.com/containerd/cgroups"
"github.com/containers/libpod/utils"
- "github.com/containers/storage/pkg/idtools"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
@@ -62,72 +59,40 @@ func newPipe() (parent *os.File, child *os.File, err error) {
return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil
}
-// CreateContainer creates a container in the OCI runtime
-// TODO terminal support for container
-// Presently just ignoring conmon opts related to it
-func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string, restoreOptions *ContainerCheckpointOptions) (err error) {
- if ctr.state.UserNSRoot == "" {
- // no need of an intermediate mount ns
- return r.createOCIContainer(ctr, cgroupParent, restoreOptions)
- }
- var wg sync.WaitGroup
- wg.Add(1)
- go func() {
- defer wg.Done()
- runtime.LockOSThread()
-
- var fd *os.File
- fd, err = os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/mnt", os.Getpid(), unix.Gettid()))
+// makeAccessible changes the path permission and each parent directory to have --x--x--x
+func makeAccessible(path string, uid, gid int) error {
+ for ; path != "/"; path = filepath.Dir(path) {
+ st, err := os.Stat(path)
if err != nil {
- return
- }
- defer fd.Close()
-
- // create a new mountns on the current thread
- if err = unix.Unshare(unix.CLONE_NEWNS); err != nil {
- return
- }
- defer unix.Setns(int(fd.Fd()), unix.CLONE_NEWNS)
-
- // don't spread our mounts around
- err = unix.Mount("/", "/", "none", unix.MS_REC|unix.MS_SLAVE, "")
- if err != nil {
- return
- }
- err = unix.Mount(ctr.state.Mountpoint, ctr.state.RealMountpoint, "none", unix.MS_BIND, "")
- if err != nil {
- return
+ if os.IsNotExist(err) {
+ return nil
+ }
+ return err
}
- if err := idtools.MkdirAllAs(ctr.state.DestinationRunDir, 0700, ctr.RootUID(), ctr.RootGID()); err != nil {
- return
+ if int(st.Sys().(*syscall.Stat_t).Uid) == uid && int(st.Sys().(*syscall.Stat_t).Gid) == gid {
+ continue
}
-
- err = unix.Mount(ctr.state.RunDir, ctr.state.DestinationRunDir, "none", unix.MS_BIND, "")
- if err != nil {
- return
+ if st.Mode()&0111 != 0111 {
+ if err := os.Chmod(path, os.FileMode(st.Mode()|0111)); err != nil {
+ return err
+ }
}
+ }
+ return nil
+}
- if ctr.state.UserNSRoot != "" {
- _, err := os.Stat(ctr.runtime.config.VolumePath)
- if err != nil && !os.IsNotExist(err) {
- return
- }
- if err == nil {
- volumesTarget := filepath.Join(ctr.state.UserNSRoot, "volumes")
- if err := idtools.MkdirAs(volumesTarget, 0700, ctr.RootUID(), ctr.RootGID()); err != nil {
- return
- }
- if err = unix.Mount(ctr.runtime.config.VolumePath, volumesTarget, "none", unix.MS_BIND, ""); err != nil {
- return
- }
+// CreateContainer creates a container in the OCI runtime
+// TODO terminal support for container
+// Presently just ignoring conmon opts related to it
+func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string, restoreOptions *ContainerCheckpointOptions) (err error) {
+ if len(ctr.config.IDMappings.UIDMap) != 0 || len(ctr.config.IDMappings.GIDMap) != 0 {
+ for _, i := range []string{ctr.state.RunDir, ctr.runtime.config.TmpDir, ctr.config.StaticDir, ctr.state.Mountpoint, ctr.runtime.config.VolumePath} {
+ if err := makeAccessible(i, ctr.RootUID(), ctr.RootGID()); err != nil {
+ return err
}
}
-
- err = r.createOCIContainer(ctr, cgroupParent, restoreOptions)
- }()
- wg.Wait()
-
- return err
+ }
+ return r.createOCIContainer(ctr, cgroupParent, restoreOptions)
}
func rpmVersion(path string) string {
diff --git a/libpod/options.go b/libpod/options.go
index 3ca80e96c..24f126e66 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/image/manifest"
"github.com/containers/libpod/pkg/namespaces"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/idtools"
"github.com/cri-o/ocicni/pkg/ocicni"
@@ -17,7 +18,7 @@ import (
)
var (
- nameRegex = regexp.MustCompile("[a-zA-Z0-9_-]+")
+ nameRegex = regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9_.-]*$")
)
// Runtime Creation Options
@@ -82,11 +83,15 @@ func WithStorageConfig(config storage.StoreOptions) RuntimeOption {
// or graphdriveroptions are set, then GraphRoot and RunRoot
// must be set
if setField {
+ storeOpts, err := storage.DefaultStoreOptions(rootless.IsRootless(), rootless.GetRootlessUID())
+ if err != nil {
+ return err
+ }
if rt.config.StorageConfig.GraphRoot == "" {
- rt.config.StorageConfig.GraphRoot = storage.DefaultStoreOptions.GraphRoot
+ rt.config.StorageConfig.GraphRoot = storeOpts.GraphRoot
}
if rt.config.StorageConfig.RunRoot == "" {
- rt.config.StorageConfig.RunRoot = storage.DefaultStoreOptions.RunRoot
+ rt.config.StorageConfig.RunRoot = storeOpts.RunRoot
}
}
@@ -925,7 +930,7 @@ func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool, netmo
ctr.config.PostConfigureNetNS = postConfigureNetNS
ctr.config.NetMode = namespaces.NetworkMode(netmode)
- ctr.config.CreateNetNS = !ctr.config.NetMode.IsUserDefined()
+ ctr.config.CreateNetNS = true
ctr.config.PortMappings = portMappings
ctr.config.Networks = networks
@@ -1269,6 +1274,28 @@ func WithVolumeName(name string) VolumeCreateOption {
}
}
+// WithVolumeUID sets the uid of the owner.
+func WithVolumeUID(uid int) VolumeCreateOption {
+ return func(volume *Volume) error {
+ if volume.valid {
+ return ErrVolumeFinalized
+ }
+ volume.config.UID = uid
+ return nil
+ }
+}
+
+// WithVolumeGID sets the gid of the owner.
+func WithVolumeGID(gid int) VolumeCreateOption {
+ return func(volume *Volume) error {
+ if volume.valid {
+ return ErrVolumeFinalized
+ }
+ volume.config.GID = gid
+ return nil
+ }
+}
+
// WithVolumeLabels sets the labels of the volume.
func WithVolumeLabels(labels map[string]string) VolumeCreateOption {
return func(volume *Volume) error {
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index b9a11000e..9a6baf23e 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -6,7 +6,6 @@ import (
"github.com/containers/libpod/libpod/events"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
- "github.com/ulule/deepcopier"
)
// Start starts all containers within a pod
@@ -441,7 +440,9 @@ func (p *Pod) Inspect() (*PodInspect, error) {
infraContainerID := p.state.InfraContainerID
config := new(PodConfig)
- deepcopier.Copy(p.config).To(config)
+ if err := JSONDeepCopy(p.config, config); err != nil {
+ return nil, err
+ }
inspectData := PodInspect{
Config: config,
State: &PodInspectState{
diff --git a/libpod/runtime.go b/libpod/runtime.go
index b3b75d791..6e54de558 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -23,7 +23,6 @@ import (
"github.com/docker/docker/pkg/namesgenerator"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
- "github.com/ulule/deepcopier"
)
// RuntimeStateStore is a constant indicating which state store implementation
@@ -249,11 +248,16 @@ type runtimeConfiguredFrom struct {
noPivotRoot bool
}
-var (
- defaultRuntimeConfig = RuntimeConfig{
+func defaultRuntimeConfig() (RuntimeConfig, error) {
+ storeOpts, err := storage.DefaultStoreOptions(rootless.IsRootless(), rootless.GetRootlessUID())
+ if err != nil {
+ return RuntimeConfig{}, err
+ }
+
+ return RuntimeConfig{
// Leave this empty so containers/storage will use its defaults
StorageConfig: storage.StoreOptions{},
- VolumePath: filepath.Join(storage.DefaultStoreOptions.GraphRoot, "volumes"),
+ VolumePath: filepath.Join(storeOpts.GraphRoot, "volumes"),
ImageDefaultTransport: DefaultTransport,
StateType: BoltDBStateStore,
OCIRuntime: "runc",
@@ -282,7 +286,7 @@ var (
},
InitPath: DefaultInitPath,
CgroupManager: SystemdCgroupsManager,
- StaticDir: filepath.Join(storage.DefaultStoreOptions.GraphRoot, "libpod"),
+ StaticDir: filepath.Join(storeOpts.GraphRoot, "libpod"),
TmpDir: "",
MaxLogSize: -1,
NoPivotRoot: false,
@@ -293,8 +297,8 @@ var (
EnablePortReservation: true,
EnableLabeling: true,
NumLocks: 2048,
- }
-)
+ }, nil
+}
func getDefaultTmpDir() (string, error) {
if !rootless.IsRootless() {
@@ -305,7 +309,17 @@ func getDefaultTmpDir() (string, error) {
if err != nil {
return "", err
}
- return filepath.Join(rootlessRuntimeDir, "libpod", "tmp"), nil
+ libpodRuntimeDir := filepath.Join(rootlessRuntimeDir, "libpod")
+
+ if err := os.Mkdir(libpodRuntimeDir, 0700|os.ModeSticky); err != nil {
+ if !os.IsExist(err) {
+ return "", errors.Wrapf(err, "cannot mkdir %s", libpodRuntimeDir)
+ } else if err := os.Chmod(libpodRuntimeDir, 0700|os.ModeSticky); err != nil {
+ // The directory already exist, just set the sticky bit
+ return "", errors.Wrapf(err, "could not set sticky bit on %s", libpodRuntimeDir)
+ }
+ }
+ return filepath.Join(libpodRuntimeDir, "tmp"), nil
}
// SetXdgRuntimeDir ensures the XDG_RUNTIME_DIR env variable is set
@@ -355,10 +369,17 @@ func newRuntimeFromConfig(userConfigPath string, options ...RuntimeOption) (runt
if err != nil {
return nil, err
}
- deepcopier.Copy(defaultRuntimeConfig).To(runtime.config)
+
+ defRunConf, err := defaultRuntimeConfig()
+ if err != nil {
+ return nil, err
+ }
+ if err := JSONDeepCopy(defRunConf, runtime.config); err != nil {
+ return nil, errors.Wrapf(err, "error copying runtime default config")
+ }
runtime.config.TmpDir = tmpDir
- storageConf, err := util.GetDefaultStoreOptions()
+ storageConf, err := storage.DefaultStoreOptions(rootless.IsRootless(), rootless.GetRootlessUID())
if err != nil {
return nil, errors.Wrapf(err, "error retrieving storage config")
}
@@ -507,7 +528,10 @@ func newRuntimeFromConfig(userConfigPath string, options ...RuntimeOption) (runt
}
if rootlessConfigPath != "" {
// storage.conf
- storageConfFile := util.StorageConfigFile()
+ storageConfFile, err := storage.DefaultConfigFile(rootless.IsRootless())
+ if err != nil {
+ return nil, err
+ }
if _, err := os.Stat(storageConfFile); os.IsNotExist(err) {
if err := util.WriteStorageConfigFile(&runtime.config.StorageConfig, storageConfFile); err != nil {
return nil, errors.Wrapf(err, "cannot write config file %s", storageConfFile)
@@ -923,20 +947,22 @@ func makeRuntime(runtime *Runtime) (err error) {
}
// GetConfig returns a copy of the configuration used by the runtime
-func (r *Runtime) GetConfig() *RuntimeConfig {
+func (r *Runtime) GetConfig() (*RuntimeConfig, error) {
r.lock.RLock()
defer r.lock.RUnlock()
if !r.valid {
- return nil
+ return nil, ErrRuntimeStopped
}
config := new(RuntimeConfig)
// Copy so the caller won't be able to modify the actual config
- deepcopier.Copy(r.config).To(config)
+ if err := JSONDeepCopy(r.config, config); err != nil {
+ return nil, errors.Wrapf(err, "error copying config")
+ }
- return config
+ return config, nil
}
// Shutdown shuts down the runtime and associated containers and storage
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index f23dc86dd..506aee477 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -19,7 +19,6 @@ import (
opentracing "github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
- "github.com/ulule/deepcopier"
)
// CtrRemoveTimeout is the default number of seconds to wait after stopping a container
@@ -63,7 +62,9 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
ctr.config.ID = stringid.GenerateNonCryptoID()
ctr.config.Spec = new(spec.Spec)
- deepcopier.Copy(rSpec).To(ctr.config.Spec)
+ if err := JSONDeepCopy(rSpec, ctr.config.Spec); err != nil {
+ return nil, errors.Wrapf(err, "error copying runtime spec while creating container")
+ }
ctr.config.CreatedTime = time.Now()
ctr.config.ShmSize = DefaultShmSize
@@ -181,14 +182,11 @@ 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), withSetCtrSpecific())
+ newVol, err := r.newVolume(ctx, WithVolumeName(vol.Source), withSetCtrSpecific(), WithVolumeUID(ctr.RootUID()), WithVolumeGID(ctr.RootGID()))
if err != nil {
return nil, errors.Wrapf(err, "error creating named volume %q", vol.Source)
}
ctr.config.Spec.Mounts[i].Source = newVol.MountPoint()
- if err := os.Chown(ctr.config.Spec.Mounts[i].Source, ctr.RootUID(), ctr.RootGID()); err != nil {
- return nil, errors.Wrapf(err, "cannot chown %q to %d:%d", ctr.config.Spec.Mounts[i].Source, ctr.RootUID(), ctr.RootGID())
- }
if err := ctr.copyWithTarFromImage(ctr.config.Spec.Mounts[i].Destination, ctr.config.Spec.Mounts[i].Source); err != nil && !os.IsNotExist(err) {
return nil, errors.Wrapf(err, "failed to copy content into new volume mount %q", vol.Source)
}
@@ -203,11 +201,7 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
}
if !MountExists(ctr.config.Spec.Mounts, "/dev/shm") && ctr.config.ShmDir == "" {
- if ctr.state.UserNSRoot == "" {
- ctr.config.ShmDir = filepath.Join(ctr.bundlePath(), "shm")
- } else {
- ctr.config.ShmDir = filepath.Join(ctr.state.UserNSRoot, "shm")
- }
+ ctr.config.ShmDir = filepath.Join(ctr.bundlePath(), "shm")
if err := os.MkdirAll(ctr.config.ShmDir, 0700); err != nil {
if !os.IsExist(err) {
return nil, errors.Wrapf(err, "unable to create shm %q dir", ctr.config.ShmDir)
diff --git a/libpod/runtime_volume_linux.go b/libpod/runtime_volume_linux.go
index b51bb8213..db5c29242 100644
--- a/libpod/runtime_volume_linux.go
+++ b/libpod/runtime_volume_linux.go
@@ -10,7 +10,6 @@ import (
"github.com/containers/libpod/libpod/events"
"github.com/containers/storage/pkg/stringid"
- "github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -52,19 +51,22 @@ func (r *Runtime) newVolume(ctx context.Context, options ...VolumeCreateOption)
}
// Create the mountpoint of this volume
- fullVolPath := filepath.Join(r.config.VolumePath, volume.config.Name, "_data")
- if err := os.MkdirAll(fullVolPath, 0755); err != nil {
- return nil, errors.Wrapf(err, "error creating volume directory %q", fullVolPath)
+ volPathRoot := filepath.Join(r.config.VolumePath, volume.config.Name)
+ if err := os.MkdirAll(volPathRoot, 0700); err != nil {
+ return nil, errors.Wrapf(err, "error creating volume directory %q", volPathRoot)
}
- _, mountLabel, err := label.InitLabels([]string{})
- if err != nil {
- return nil, errors.Wrapf(err, "error getting default mountlabels")
+ if err := os.Chown(volPathRoot, volume.config.UID, volume.config.GID); err != nil {
+ return nil, errors.Wrapf(err, "error chowning volume directory %q to %d:%d", volPathRoot, volume.config.UID, volume.config.GID)
+ }
+ fullVolPath := filepath.Join(volPathRoot, "_data")
+ if err := os.Mkdir(fullVolPath, 0755); err != nil {
+ return nil, errors.Wrapf(err, "error creating volume directory %q", fullVolPath)
}
- if err := label.ReleaseLabel(mountLabel); err != nil {
- return nil, errors.Wrapf(err, "error releasing label %q", mountLabel)
+ if err := os.Chown(fullVolPath, volume.config.UID, volume.config.GID); err != nil {
+ return nil, errors.Wrapf(err, "error chowning volume directory %q to %d:%d", fullVolPath, volume.config.UID, volume.config.GID)
}
- if err := label.Relabel(fullVolPath, mountLabel, true); err != nil {
- return nil, errors.Wrapf(err, "error setting selinux label to %q", fullVolPath)
+ if err := LabelVolumePath(fullVolPath, true); err != nil {
+ return nil, err
}
volume.config.MountPoint = fullVolPath
diff --git a/libpod/util.go b/libpod/util.go
index b7578135a..7e2dff21a 100644
--- a/libpod/util.go
+++ b/libpod/util.go
@@ -187,3 +187,13 @@ func validPodNSOption(p *Pod, ctrPod string) error {
}
return nil
}
+
+// JSONDeepCopy performs a deep copy by performing a JSON encode/decode of the
+// given structures. From and To should be identically typed structs.
+func JSONDeepCopy(from, to interface{}) error {
+ tmp, err := json.Marshal(from)
+ if err != nil {
+ return err
+ }
+ return json.Unmarshal(tmp, to)
+}
diff --git a/libpod/util_linux.go b/libpod/util_linux.go
index 30e2538c3..a801df2ee 100644
--- a/libpod/util_linux.go
+++ b/libpod/util_linux.go
@@ -9,6 +9,7 @@ import (
"github.com/containerd/cgroups"
"github.com/containers/libpod/pkg/util"
spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -91,3 +92,23 @@ func GetV1CGroups(excludes []string) cgroups.Hierarchy {
return filtered, nil
}
}
+
+// LabelVolumePath takes a mount path for a volume and gives it an
+// selinux label of either shared or not
+func LabelVolumePath(path string, shared bool) error {
+ _, mountLabel, err := label.InitLabels([]string{})
+ if err != nil {
+ return errors.Wrapf(err, "error getting default mountlabels")
+ }
+ if err := label.ReleaseLabel(mountLabel); err != nil {
+ return errors.Wrapf(err, "error releasing label %q", mountLabel)
+ }
+ if err := label.Relabel(path, mountLabel, shared); err != nil {
+ permString := "private"
+ if shared {
+ permString = "shared"
+ }
+ return errors.Wrapf(err, "error setting selinux label for %s to %q as %s", path, mountLabel, permString)
+ }
+ return nil
+}
diff --git a/libpod/util_unsupported.go b/libpod/util_unsupported.go
index d598b465f..940006e69 100644
--- a/libpod/util_unsupported.go
+++ b/libpod/util_unsupported.go
@@ -21,3 +21,9 @@ func deleteSystemdCgroup(path string) error {
func assembleSystemdCgroupName(baseSlice, newSlice string) (string, error) {
return "", errors.Wrapf(ErrOSNotSupported, "cgroups are not supported on non-linux OSes")
}
+
+// LabelVolumePath takes a mount path for a volume and gives it an
+// selinux label of either shared or not
+func LabelVolumePath(path string, shared bool) error {
+ return ErrNotImplemented
+}
diff --git a/libpod/volume.go b/libpod/volume.go
index 0c7618841..0b37d44ef 100644
--- a/libpod/volume.go
+++ b/libpod/volume.go
@@ -21,6 +21,8 @@ type VolumeConfig struct {
Options map[string]string `json:"options"`
Scope string `json:"scope"`
IsCtrSpecific bool `json:"ctrSpecific"`
+ UID int `json:"uid"`
+ GID int `json:"gid"`
}
// Name retrieves the volume's name