summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml2
-rw-r--r--.papr.yml1
-rw-r--r--Dockerfile2
-rw-r--r--cmd/podman/create.go67
-rw-r--r--cmd/podman/exists.go37
-rw-r--r--cmd/podman/libpodruntime/runtime.go38
-rw-r--r--cmd/podman/main.go9
-rw-r--r--cmd/podman/pod.go1
-rw-r--r--cmd/podman/rmi.go19
-rw-r--r--cmd/podman/run.go2
-rw-r--r--completions/bash/podman8
-rw-r--r--contrib/python/pypodman/pypodman/lib/actions/inspect_action.py14
-rw-r--r--docs/libpod.conf.5.md12
-rw-r--r--docs/podman-create.1.md3
-rw-r--r--docs/podman-pod-exists.1.md40
-rw-r--r--docs/podman-run.1.md3
-rw-r--r--docs/podman.1.md24
-rw-r--r--libpod/boltdb_state.go85
-rw-r--r--libpod/boltdb_state_internal.go47
-rw-r--r--libpod/container_internal.go48
-rw-r--r--libpod/container_internal_linux.go28
-rw-r--r--libpod/in_memory_state.go12
-rw-r--r--libpod/options.go58
-rw-r--r--libpod/runtime.go173
-rw-r--r--libpod/state.go26
-rw-r--r--libpod/state_test.go7
-rw-r--r--libpod/testdata/config.toml2
-rw-r--r--pkg/lookup/lookup.go18
-rw-r--r--pkg/rootless/rootless_linux.go26
-rw-r--r--pkg/spec/createconfig.go7
-rw-r--r--pkg/util/utils.go2
-rw-r--r--test/e2e/create_test.go11
-rw-r--r--test/e2e/exists_test.go32
-rw-r--r--test/e2e/rmi_test.go21
-rw-r--r--test/e2e/run_test.go13
-rw-r--r--vendor.conf2
-rw-r--r--vendor/github.com/containers/storage/drivers/fsdiff.go5
-rw-r--r--vendor/github.com/containers/storage/drivers/overlay/overlay.go2
-rw-r--r--vendor/github.com/containers/storage/layers.go5
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/archive.go5
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/example_changes.go97
-rw-r--r--vendor/github.com/containers/storage/pkg/chrootarchive/archive.go2
42 files changed, 687 insertions, 329 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 304efb2f4..625b96fdd 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -20,7 +20,7 @@ env:
CNI_COMMIT: "7480240de9749f9a0a5c8614b17f1f03e0c06ab9"
CRIO_COMMIT: "7a283c391abb7bd25086a8ff91dbb36ebdd24466"
CRIU_COMMIT: "c74b83cd49c00589c0c0468ba5fe685b67fdbd0a"
- RUNC_COMMIT: "869add33186caff4a22e3e11a7472a2d48d77889"
+ RUNC_COMMIT: "96ec2177ae841256168fcf76954f7177af9446eb"
# File to update in home-dir with task-specific env. var values
ENVLIB: ".bash_profile"
# Overrides default location (/tmp/cirrus) for repo clone
diff --git a/.papr.yml b/.papr.yml
index b82da28e5..fbdbcb5cd 100644
--- a/.papr.yml
+++ b/.papr.yml
@@ -122,6 +122,7 @@ packages:
- python3-varlink
- python3-dateutil
- python3-psutil
+ - https://kojipkgs.fedoraproject.org//packages/runc/1.0.0/54.dev.git00dc700.fc28/x86_64/runc-1.0.0-54.dev.git00dc700.fc28.x86_64.rpm
tests:
- sed 's/^expand-check.*/expand-check=0/g' -i /etc/selinux/semanage.conf
diff --git a/Dockerfile b/Dockerfile
index e1d7b4649..08af0f851 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -52,7 +52,7 @@ ADD . /go/src/github.com/containers/libpod
RUN set -x && cd /go/src/github.com/containers/libpod && make install.libseccomp.sudo
# Install runc
-ENV RUNC_COMMIT 869add33186caff4a22e3e11a7472a2d48d77889
+ENV RUNC_COMMIT 96ec2177ae841256168fcf76954f7177af9446eb
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/opencontainers/runc.git "$GOPATH/src/github.com/opencontainers/runc" \
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index bcf830c7c..228438d75 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -11,6 +11,7 @@ import (
"syscall"
"github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
ann "github.com/containers/libpod/pkg/annotations"
@@ -66,7 +67,7 @@ func createCmd(c *cli.Context) error {
rootless.SetSkipStorageSetup(true)
}
- runtime, err := libpodruntime.GetContainerRuntime(c)
+ runtime, err := libpodruntime.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
@@ -375,8 +376,8 @@ func configureEntrypoint(c *cli.Context, data *inspect.ImageData) []string {
return entrypoint
}
-func configurePod(c *cli.Context, runtime *libpod.Runtime, namespaces map[string]string) (map[string]string, error) {
- pod, err := runtime.LookupPod(c.String("pod"))
+func configurePod(c *cli.Context, runtime *libpod.Runtime, namespaces map[string]string, podName string) (map[string]string, error) {
+ pod, err := runtime.LookupPod(podName)
if err != nil {
return namespaces, err
}
@@ -409,6 +410,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
inputCommand, command []string
memoryLimit, memoryReservation, memorySwap, memoryKernel int64
blkioWeight uint16
+ namespaces map[string]string
)
idmappings, err := util.ParseIDMapping(c.StringSlice("uidmap"), c.StringSlice("gidmap"), c.String("subuidname"), c.String("subgidname"))
if err != nil {
@@ -492,12 +494,21 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
return nil, errors.Errorf("--cpu-quota and --cpus cannot be set together")
}
+ // EXPOSED PORTS
+ var portBindings map[nat.Port][]nat.PortBinding
+ if data != nil {
+ portBindings, err = cc.ExposedPorts(c.StringSlice("expose"), c.StringSlice("publish"), c.Bool("publish-all"), data.ContainerConfig.ExposedPorts)
+ if err != nil {
+ return nil, err
+ }
+ }
+
// Kernel Namespaces
// TODO Fix handling of namespace from pod
// Instead of integrating here, should be done in libpod
// However, that also involves setting up security opts
// when the pod's namespace is integrated
- namespaces := map[string]string{
+ namespaces = map[string]string{
"pid": c.String("pid"),
"net": c.String("net"),
"ipc": c.String("ipc"),
@@ -505,8 +516,41 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
"uts": c.String("uts"),
}
+ originalPodName := c.String("pod")
+ podName := strings.Replace(originalPodName, "new:", "", 1)
+ // after we strip out :new, make sure there is something left for a pod name
+ if len(podName) < 1 && c.IsSet("pod") {
+ return nil, errors.Errorf("new pod name must be at least one character")
+ }
if c.IsSet("pod") {
- namespaces, err = configurePod(c, runtime, namespaces)
+ if strings.HasPrefix(originalPodName, "new:") {
+ // pod does not exist; lets make it
+ var podOptions []libpod.PodCreateOption
+ podOptions = append(podOptions, libpod.WithPodName(podName), libpod.WithInfraContainer(), libpod.WithPodCgroups())
+ if len(portBindings) > 0 {
+ ociPortBindings, err := cc.NatToOCIPortBindings(portBindings)
+ if err != nil {
+ return nil, err
+ }
+ podOptions = append(podOptions, libpod.WithInfraContainerPorts(ociPortBindings))
+ }
+
+ podNsOptions, err := shared.GetNamespaceOptions(strings.Split(DefaultKernelNamespaces, ","))
+ if err != nil {
+ return nil, err
+ }
+ podOptions = append(podOptions, podNsOptions...)
+ // make pod
+ pod, err := runtime.NewPod(ctx, podOptions...)
+ if err != nil {
+ return nil, err
+ }
+ logrus.Debugf("pod %s created by new container request", pod.ID())
+
+ // The container now cannot have port bindings; so we reset the map
+ portBindings = make(map[nat.Port][]nat.PortBinding)
+ }
+ namespaces, err = configurePod(c, runtime, namespaces, podName)
if err != nil {
return nil, err
}
@@ -535,7 +579,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
// Make sure if network is set to container namespace, port binding is not also being asked for
netMode := ns.NetworkMode(namespaces["net"])
if netMode.IsContainer() {
- if len(c.StringSlice("publish")) > 0 || c.Bool("publish-all") {
+ if len(portBindings) > 0 {
return nil, errors.Errorf("cannot set port bindings on an existing container network namespace")
}
}
@@ -644,15 +688,6 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
return nil, errors.Errorf("No command specified on command line or as CMD or ENTRYPOINT in this image")
}
- // EXPOSED PORTS
- var portBindings map[nat.Port][]nat.PortBinding
- if data != nil {
- portBindings, err = cc.ExposedPorts(c.StringSlice("expose"), c.StringSlice("publish"), c.Bool("publish-all"), data.ContainerConfig.ExposedPorts)
- if err != nil {
- return nil, err
- }
- }
-
// SHM Size
shmSize, err := units.FromHumanSize(c.String("shm-size"))
if err != nil {
@@ -746,7 +781,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
NetMode: netMode,
UtsMode: utsMode,
PidMode: pidMode,
- Pod: c.String("pod"),
+ Pod: podName,
Privileged: c.Bool("privileged"),
Publish: c.StringSlice("publish"),
PublishAll: c.Bool("publish-all"),
diff --git a/cmd/podman/exists.go b/cmd/podman/exists.go
index 2f7b7c185..2e2559ec7 100644
--- a/cmd/podman/exists.go
+++ b/cmd/podman/exists.go
@@ -44,6 +44,23 @@ var (
}
)
+var (
+ podExistsDescription = `
+ podman pod exists
+
+ Check if a pod exists in local storage
+`
+
+ podExistsCommand = cli.Command{
+ Name: "exists",
+ Usage: "Check if a pod exists in local storage",
+ Description: podExistsDescription,
+ Action: podExistsCmd,
+ ArgsUsage: "POD-NAME",
+ OnUsageError: usageErrorHandler,
+ }
+)
+
func imageExistsCmd(c *cli.Context) error {
args := c.Args()
if len(args) > 1 || len(args) < 1 {
@@ -81,3 +98,23 @@ func containerExistsCmd(c *cli.Context) error {
}
return nil
}
+
+func podExistsCmd(c *cli.Context) error {
+ args := c.Args()
+ if len(args) > 1 || len(args) < 1 {
+ return errors.New("you may only check for the existence of one pod at a time")
+ }
+ runtime, err := libpodruntime.GetRuntime(c)
+ if err != nil {
+ return errors.Wrapf(err, "could not get runtime")
+ }
+ defer runtime.Shutdown(false)
+
+ if _, err := runtime.LookupPod(args[0]); err != nil {
+ if errors.Cause(err) == libpod.ErrNoSuchPod {
+ os.Exit(1)
+ }
+ return err
+ }
+ return nil
+}
diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go
index a4b3581be..0dc6bcf18 100644
--- a/cmd/podman/libpodruntime/runtime.go
+++ b/cmd/podman/libpodruntime/runtime.go
@@ -11,32 +11,18 @@ import (
// GetRuntime generates a new libpod runtime configured by command line options
func GetRuntime(c *cli.Context) (*libpod.Runtime, error) {
- storageOpts, err := util.GetDefaultStoreOptions()
- if err != nil {
- return nil, err
- }
- return GetRuntimeWithStorageOpts(c, &storageOpts)
-}
-
-// GetContainerRuntime generates a new libpod runtime configured by command line options for containers
-func GetContainerRuntime(c *cli.Context) (*libpod.Runtime, error) {
- mappings, err := util.ParseIDMapping(c.StringSlice("uidmap"), c.StringSlice("gidmap"), c.String("subuidmap"), c.String("subgidmap"))
- if err != nil {
- return nil, err
- }
- storageOpts, err := util.GetDefaultStoreOptions()
- if err != nil {
- return nil, err
- }
- storageOpts.UIDMap = mappings.UIDMap
- storageOpts.GIDMap = mappings.GIDMap
- return GetRuntimeWithStorageOpts(c, &storageOpts)
-}
-
-// GetRuntime generates a new libpod runtime configured by command line options
-func GetRuntimeWithStorageOpts(c *cli.Context, storageOpts *storage.StoreOptions) (*libpod.Runtime, error) {
+ storageOpts := new(storage.StoreOptions)
options := []libpod.RuntimeOption{}
+ if c.IsSet("uidmap") || c.IsSet("gidmap") || c.IsSet("subuidmap") || c.IsSet("subgidmap") {
+ mappings, err := util.ParseIDMapping(c.StringSlice("uidmap"), c.StringSlice("gidmap"), c.String("subuidmap"), c.String("subgidmap"))
+ if err != nil {
+ return nil, err
+ }
+ storageOpts.UIDMap = mappings.UIDMap
+ storageOpts.GIDMap = mappings.GIDMap
+ }
+
if c.GlobalIsSet("root") {
storageOpts.GraphRoot = c.GlobalString("root")
}
@@ -90,8 +76,8 @@ func GetRuntimeWithStorageOpts(c *cli.Context, storageOpts *storage.StoreOptions
if c.GlobalIsSet("default-mounts-file") {
options = append(options, libpod.WithDefaultMountsFile(c.GlobalString("default-mounts-file")))
}
- if c.GlobalIsSet("hooks-dir-path") {
- options = append(options, libpod.WithHooksDir(c.GlobalString("hooks-dir-path")))
+ if c.GlobalIsSet("hooks-dir") {
+ options = append(options, libpod.WithHooksDir(c.GlobalStringSlice("hooks-dir")...))
}
// TODO flag to set CNI plugins dir?
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 6be192593..bcae04575 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -8,7 +8,6 @@ import (
"syscall"
"github.com/containers/libpod/libpod"
- "github.com/containers/libpod/pkg/hooks"
_ "github.com/containers/libpod/pkg/hooks/0.1.0"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/version"
@@ -206,11 +205,9 @@ func main() {
Usage: "path to default mounts file",
Hidden: true,
},
- cli.StringFlag{
- Name: "hooks-dir-path",
- Usage: "set the OCI hooks directory path",
- Value: hooks.DefaultDir,
- Hidden: true,
+ cli.StringSliceFlag{
+ Name: "hooks-dir",
+ Usage: "set the OCI hooks directory path (may be set multiple times)",
},
cli.IntFlag{
Name: "max-workers",
diff --git a/cmd/podman/pod.go b/cmd/podman/pod.go
index 0c6ec5e8c..a30361134 100644
--- a/cmd/podman/pod.go
+++ b/cmd/podman/pod.go
@@ -11,6 +11,7 @@ Pods are a group of one or more containers sharing the same network, pid and ipc
`
podSubCommands = []cli.Command{
podCreateCommand,
+ podExistsCommand,
podInspectCommand,
podKillCommand,
podPauseCommand,
diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go
index c0a0d69df..0f4f8765b 100644
--- a/cmd/podman/rmi.go
+++ b/cmd/podman/rmi.go
@@ -91,8 +91,23 @@ func rmiCmd(c *cli.Context) error {
if err != nil {
return errors.Wrapf(err, "unable to query local images")
}
- for _, i := range imagesToDelete {
- removeImage(i)
+ lastNumberofImages := 0
+ for len(imagesToDelete) > 0 {
+ if lastNumberofImages == len(imagesToDelete) {
+ return errors.New("unable to delete all images; re-run the rmi command again.")
+ }
+ for _, i := range imagesToDelete {
+ isParent, err := i.IsParent()
+ if err != nil {
+ return err
+ }
+ if isParent {
+ continue
+ }
+ removeImage(i)
+ }
+ lastNumberofImages = len(imagesToDelete)
+ imagesToDelete, err = runtime.ImageRuntime().GetImages()
}
} else {
// Create image.image objects for deletion from user input.
diff --git a/cmd/podman/run.go b/cmd/podman/run.go
index af6ced45d..a4b5c918e 100644
--- a/cmd/podman/run.go
+++ b/cmd/podman/run.go
@@ -44,7 +44,7 @@ func runCmd(c *cli.Context) error {
rootless.SetSkipStorageSetup(true)
}
- runtime, err := libpodruntime.GetContainerRuntime(c)
+ runtime, err := libpodruntime.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
diff --git a/completions/bash/podman b/completions/bash/podman
index 3cccf2192..9518cfa22 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -2235,6 +2235,14 @@ _podman_container_exists() {
"
}
+_podman_pod_exists() {
+ local options_with_args="
+ "
+
+ local boolean_options="
+ "
+}
+
_podman_image_exists() {
local options_with_args="
"
diff --git a/contrib/python/pypodman/pypodman/lib/actions/inspect_action.py b/contrib/python/pypodman/pypodman/lib/actions/inspect_action.py
index 514b4702a..a581e7e4e 100644
--- a/contrib/python/pypodman/pypodman/lib/actions/inspect_action.py
+++ b/contrib/python/pypodman/pypodman/lib/actions/inspect_action.py
@@ -23,9 +23,9 @@ class Inspect(AbstractActionBase):
help='Type of object to inspect',
)
parser.add_argument(
- 'size',
+ '--size',
action='store_true',
- default=True,
+ default=False,
help='Display the total file size if the type is a container.'
' Always True.')
parser.add_argument(
@@ -59,7 +59,7 @@ class Inspect(AbstractActionBase):
def inspect(self):
"""Inspect provided podman objects."""
- output = {}
+ output = []
try:
for ident in self._args.objects:
obj = None
@@ -78,7 +78,13 @@ class Inspect(AbstractActionBase):
msg = 'Object "{}" not found'.format(ident)
print(msg, file=sys.stderr, flush=True)
else:
- output.update(obj._asdict())
+ fields = obj._asdict()
+ if not self._args.size:
+ try:
+ del fields['sizerootfs']
+ except KeyError:
+ pass
+ output.append(fields)
except podman.ErrorOccurred as e:
sys.stdout.flush()
print(
diff --git a/docs/libpod.conf.5.md b/docs/libpod.conf.5.md
index 198e927ee..d63baeb88 100644
--- a/docs/libpod.conf.5.md
+++ b/docs/libpod.conf.5.md
@@ -24,6 +24,18 @@ libpod to manage containers.
**cgroup_manager**=""
Specify the CGroup Manager to use; valid values are "systemd" and "cgroupfs"
+**hooks_dir**=["*path*", ...]
+
+ Each `*.json` file in the path configures a hook for Podman containers. For more details on the syntax of the JSON files and the semantics of hook injection, see `oci-hooks(5)`. Podman and libpod currently support both the 1.0.0 and 0.1.0 hook schemas, although the 0.1.0 schema is deprecated.
+
+ Paths listed later in the array higher precedence (`oci-hooks(5)` discusses directory precedence).
+
+ For the annotation conditions, libpod uses any annotations set in the generated OCI configuration.
+
+ For the bind-mount conditions, only mounts explicitly requested by the caller via `--volume` are considered. Bind mounts that libpod inserts by default (e.g. `/dev/shm`) are not considered.
+
+ If `hooks_dir` is unset for root callers, Podman and libpod will currently default to `/usr/share/containers/oci/hooks.d` and `/etc/containers/oci/hooks.d` in order of increasing precedence. Using these defaults is deprecated, and callers should migrate to explicitly setting `hooks_dir`.
+
**static_dir**=""
Directory for persistent libpod files (database, etc)
By default this will be configured relative to where containers/storage
diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md
index 6fbdd0d03..f1409a554 100644
--- a/docs/podman-create.1.md
+++ b/docs/podman-create.1.md
@@ -455,7 +455,8 @@ Tune the container's pids limit. Set `-1` to have unlimited pids for the contain
**--pod**=""
-Run container in an existing pod
+Run container in an existing pod. If you want podman to make the pod for you, preference the pod name with `new:`.
+To make a pod with more granular options, use the `podman pod create` command before creating a container.
**--privileged**=*true*|*false*
diff --git a/docs/podman-pod-exists.1.md b/docs/podman-pod-exists.1.md
new file mode 100644
index 000000000..8fb2fc90e
--- /dev/null
+++ b/docs/podman-pod-exists.1.md
@@ -0,0 +1,40 @@
+% podman-pod-exits(1) Podman Man Pages
+% Brent Baude
+% December 2018
+# NAME
+podman-pod-exists- Check if a pod exists in local storage
+
+# SYNOPSIS
+**podman pod exists**
+[**-h**|**--help**]
+POD
+
+# DESCRIPTION
+**podman pod exists** checks if a pod exists in local storage. The **ID** or **Name**
+of the pod may be used as input. Podman will return an exit code
+of `0` when the pod is found. A `1` will be returned otherwise. An exit code of `125` indicates there
+was an issue accessing the local storage.
+
+## Examples ##
+
+Check if a pod called `web` exists in local storage (the pod does actually exist).
+```
+$ sudo podman pod exists web
+$ echo $?
+0
+$
+```
+
+Check if a pod called `backend` exists in local storage (the pod does not actually exist).
+```
+$ sudo podman pod exists backend
+$ echo $?
+1
+$
+```
+
+## SEE ALSO
+podman-pod(1), podman(1)
+
+# HISTORY
+December 2018, Originally compiled by Brent Baude (bbaude at redhat dot com)
diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md
index a6761a393..5917f6f7a 100644
--- a/docs/podman-run.1.md
+++ b/docs/podman-run.1.md
@@ -439,7 +439,8 @@ Tune the container's pids limit. Set `-1` to have unlimited pids for the contain
**--pod**=""
-Run container in an existing pod
+Run container in an existing pod. If you want podman to make the pod for you, preference the pod name with `new:`.
+To make a pod with more granular options, use the `podman pod create` command before creating a container.
**--privileged**=*true*|*false*
diff --git a/docs/podman.1.md b/docs/podman.1.md
index b7433d850..bde349e6f 100644
--- a/docs/podman.1.md
+++ b/docs/podman.1.md
@@ -31,6 +31,18 @@ CGroup manager to use for container cgroups. Supported values are cgroupfs or sy
Path to where the cpu performance results should be written
+**--hooks-dir**=**path**
+
+Each `*.json` file in the path configures a hook for Podman containers. For more details on the syntax of the JSON files and the semantics of hook injection, see `oci-hooks(5)`. Podman and libpod currently support both the 1.0.0 and 0.1.0 hook schemas, although the 0.1.0 schema is deprecated.
+
+This option may be set multiple times; paths from later options have higher precedence (`oci-hooks(5)` discusses directory precedence).
+
+For the annotation conditions, libpod uses any annotations set in the generated OCI configuration.
+
+For the bind-mount conditions, only mounts explicitly requested by the caller via `--volume` are considered. Bind mounts that libpod inserts by default (e.g. `/dev/shm`) are not considered.
+
+If `--hooks-dir` is unset for root callers, Podman and libpod will currently default to `/usr/share/containers/oci/hooks.d` and `/etc/containers/oci/hooks.d` in order of increasing precedence. Using these defaults is deprecated, and callers should migrate to explicitly setting `--hooks-dir`.
+
**--log-level**
Log messages above specified level: debug, info, warn, error (default), fatal or panic
@@ -161,18 +173,6 @@ the exit codes follow the `chroot` standard, see below:
The mounts.conf file specifies volume mount directories that are automatically mounted inside containers when executing the `podman run` or `podman start` commands. When Podman runs in rootless mode, the file `$HOME/.config/containers/mounts.conf` is also used. Please refer to containers-mounts.conf(5) for further details.
-**OCI hooks JSON** (`/etc/containers/oci/hooks.d/*.json`, `/usr/share/containers/oci/hooks.d/*.json`)
-
- Each `*.json` file in `/etc/containers/oci/hooks.d` and `/usr/share/containers/oci/hooks.d` configures a hook for Podman containers, with `/etc/containers/oci/hooks.d` having higher precedence. For more details on the syntax of the JSON files and the semantics of hook injection, see `oci-hooks(5)`.
-
- Podman and libpod currently support both the 1.0.0 and 0.1.0 hook schemas, although the 0.1.0 schema is deprecated.
-
- For the annotation conditions, libpod uses any annotations set in the generated OCI configuration.
-
- For the bind-mount conditions, only mounts explicitly requested by the caller via `--volume` are considered. Bind mounts that libpod inserts by default (e.g. `/dev/shm`) are not considered.
-
- Hooks are not used when running in rootless mode.
-
**policy.json** (`/etc/containers/policy.json`)
Signature verification policy files are used to specify policy, e.g. trusted keys, applicable when deciding whether to accept an image, or individual signatures of that image, as valid.
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index 42f029379..cb661d4e9 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -3,7 +3,6 @@ package libpod
import (
"bytes"
"encoding/json"
- "os"
"strings"
"sync"
@@ -19,7 +18,6 @@ type BoltState struct {
dbLock sync.Mutex
namespace string
namespaceBytes []byte
- lockDir string
runtime *Runtime
}
@@ -52,25 +50,15 @@ type BoltState struct {
// containers/storage do not occur.
// NewBoltState creates a new bolt-backed state database
-func NewBoltState(path, lockDir string, runtime *Runtime) (State, error) {
+func NewBoltState(path string, runtime *Runtime) (State, error) {
state := new(BoltState)
state.dbPath = path
- state.lockDir = lockDir
state.runtime = runtime
state.namespace = ""
state.namespaceBytes = nil
logrus.Debugf("Initializing boltdb state at %s", path)
- // Make the directory that will hold container lockfiles
- if err := os.MkdirAll(lockDir, 0750); err != nil {
- // The directory is allowed to exist
- if !os.IsExist(err) {
- return nil, errors.Wrapf(err, "error creating lockfiles dir %s", lockDir)
- }
- }
- state.lockDir = lockDir
-
db, err := bolt.Open(path, 0600, nil)
if err != nil {
return nil, errors.Wrapf(err, "error opening database %s", path)
@@ -115,11 +103,6 @@ func NewBoltState(path, lockDir string, runtime *Runtime) (State, error) {
return nil, errors.Wrapf(err, "error creating initial database layout")
}
- // Check runtime configuration
- if err := checkRuntimeConfig(db, runtime); err != nil {
- return nil, err
- }
-
state.valid = true
return state, nil
@@ -240,6 +223,72 @@ func (s *BoltState) Refresh() error {
return err
}
+// GetDBConfig retrieves runtime configuration fields that were created when
+// the database was first initialized
+func (s *BoltState) GetDBConfig() (*DBConfig, error) {
+ if !s.valid {
+ return nil, ErrDBClosed
+ }
+
+ cfg := new(DBConfig)
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return nil, err
+ }
+ defer s.closeDBCon(db)
+
+ err = db.View(func(tx *bolt.Tx) error {
+ configBucket, err := getRuntimeConfigBucket(tx)
+ if err != nil {
+ return nil
+ }
+
+ // Some of these may be nil
+ // When we convert to string, Go will coerce them to ""
+ // That's probably fine - we could raise an error if the key is
+ // missing, but just not including it is also OK.
+ libpodRoot := configBucket.Get(staticDirKey)
+ libpodTmp := configBucket.Get(tmpDirKey)
+ storageRoot := configBucket.Get(graphRootKey)
+ storageTmp := configBucket.Get(runRootKey)
+ graphDriver := configBucket.Get(graphDriverKey)
+
+ cfg.LibpodRoot = string(libpodRoot)
+ cfg.LibpodTmp = string(libpodTmp)
+ cfg.StorageRoot = string(storageRoot)
+ cfg.StorageTmp = string(storageTmp)
+ cfg.GraphDriver = string(graphDriver)
+
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return cfg, nil
+}
+
+// ValidateDBConfig validates paths in the given runtime against the database
+func (s *BoltState) ValidateDBConfig(runtime *Runtime) error {
+ if !s.valid {
+ return ErrDBClosed
+ }
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return err
+ }
+ defer s.closeDBCon(db)
+
+ // Check runtime configuration
+ if err := checkRuntimeConfig(db, runtime); err != nil {
+ return err
+ }
+
+ return nil
+}
+
// SetNamespace sets the namespace that will be used for container and pod
// retrieval
func (s *BoltState) SetNamespace(ns string) error {
diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go
index cc7d106cc..3f00657ea 100644
--- a/libpod/boltdb_state_internal.go
+++ b/libpod/boltdb_state_internal.go
@@ -30,6 +30,13 @@ const (
containersName = "containers"
podIDName = "pod-id"
namespaceName = "namespace"
+
+ staticDirName = "static-dir"
+ tmpDirName = "tmp-dir"
+ runRootName = "run-root"
+ graphRootName = "graph-root"
+ graphDriverName = "graph-driver-name"
+ osName = "os"
)
var (
@@ -49,21 +56,19 @@ var (
containersBkt = []byte(containersName)
podIDKey = []byte(podIDName)
namespaceKey = []byte(namespaceName)
+
+ staticDirKey = []byte(staticDirName)
+ tmpDirKey = []byte(tmpDirName)
+ runRootKey = []byte(runRootName)
+ graphRootKey = []byte(graphRootName)
+ graphDriverKey = []byte(graphDriverName)
+ osKey = []byte(osName)
)
// Check if the configuration of the database is compatible with the
// configuration of the runtime opening it
// If there is no runtime configuration loaded, load our own
func checkRuntimeConfig(db *bolt.DB, rt *Runtime) error {
- var (
- staticDir = []byte("static-dir")
- tmpDir = []byte("tmp-dir")
- runRoot = []byte("run-root")
- graphRoot = []byte("graph-root")
- graphDriverName = []byte("graph-driver-name")
- osKey = []byte("os")
- )
-
err := db.Update(func(tx *bolt.Tx) error {
configBkt, err := getRuntimeConfigBucket(tx)
if err != nil {
@@ -74,31 +79,31 @@ func checkRuntimeConfig(db *bolt.DB, rt *Runtime) error {
return err
}
- if err := validateDBAgainstConfig(configBkt, "static dir",
- rt.config.StaticDir, staticDir, ""); err != nil {
+ if err := validateDBAgainstConfig(configBkt, "libpod root directory (staticdir)",
+ rt.config.StaticDir, staticDirKey, ""); err != nil {
return err
}
- if err := validateDBAgainstConfig(configBkt, "tmp dir",
- rt.config.TmpDir, tmpDir, ""); err != nil {
+ if err := validateDBAgainstConfig(configBkt, "libpod temporary files directory (tmpdir)",
+ rt.config.TmpDir, tmpDirKey, ""); err != nil {
return err
}
- if err := validateDBAgainstConfig(configBkt, "run root",
- rt.config.StorageConfig.RunRoot, runRoot,
+ if err := validateDBAgainstConfig(configBkt, "storage temporary directory (runroot)",
+ rt.config.StorageConfig.RunRoot, runRootKey,
storage.DefaultStoreOptions.RunRoot); err != nil {
return err
}
- if err := validateDBAgainstConfig(configBkt, "graph root",
- rt.config.StorageConfig.GraphRoot, graphRoot,
+ if err := validateDBAgainstConfig(configBkt, "storage graph root directory (graphroot)",
+ rt.config.StorageConfig.GraphRoot, graphRootKey,
storage.DefaultStoreOptions.GraphRoot); err != nil {
return err
}
- return validateDBAgainstConfig(configBkt, "graph driver name",
+ return validateDBAgainstConfig(configBkt, "storage graph driver",
rt.config.StorageConfig.GraphDriverName,
- graphDriverName,
+ graphDriverKey,
storage.DefaultStoreOptions.GraphDriverName)
})
@@ -261,7 +266,7 @@ func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt.
}
// Get the lock
- lockPath := filepath.Join(s.lockDir, string(id))
+ lockPath := filepath.Join(s.runtime.lockDir, string(id))
lock, err := storage.GetLockfile(lockPath)
if err != nil {
return errors.Wrapf(err, "error retrieving lockfile for container %s", string(id))
@@ -297,7 +302,7 @@ func (s *BoltState) getPodFromDB(id []byte, pod *Pod, podBkt *bolt.Bucket) error
}
// Get the lock
- lockPath := filepath.Join(s.lockDir, string(id))
+ lockPath := filepath.Join(s.runtime.lockDir, string(id))
lock, err := storage.GetLockfile(lockPath)
if err != nil {
return errors.Wrapf(err, "error retrieving lockfile for pod %s", string(id))
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index e31a8099c..934ad7a22 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1168,10 +1168,6 @@ func (c *Container) saveSpec(spec *spec.Spec) error {
}
func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (extensionStageHooks map[string][]spec.Hook, err error) {
- if len(c.runtime.config.HooksDir) == 0 {
- return nil, nil
- }
-
var locale string
var ok bool
for _, envVar := range []string{
@@ -1199,25 +1195,39 @@ func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (exten
}
}
- allHooks := make(map[string][]spec.Hook)
- for _, hDir := range c.runtime.config.HooksDir {
- manager, err := hooks.New(ctx, []string{hDir}, []string{"poststop"}, lang)
- if err != nil {
- if c.runtime.config.HooksDirNotExistFatal || !os.IsNotExist(err) {
- return nil, err
- }
- logrus.Warnf("failed to load hooks: %q", err)
+ if c.runtime.config.HooksDir == nil {
+ if rootless.IsRootless() {
return nil, nil
}
- hooks, err := manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0)
- if err != nil {
- return nil, err
- }
- for i, hook := range hooks {
- allHooks[i] = hook
+ allHooks := make(map[string][]spec.Hook)
+ for _, hDir := range []string{hooks.DefaultDir, hooks.OverrideDir} {
+ manager, err := hooks.New(ctx, []string{hDir}, []string{"poststop"}, lang)
+ if err != nil {
+ if os.IsNotExist(err) {
+ continue
+ }
+ return nil, err
+ }
+ hooks, 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)
+ }
+ for i, hook := range hooks {
+ allHooks[i] = hook
+ }
}
+ return allHooks, nil
}
- return allHooks, nil
+
+ manager, err := hooks.New(ctx, c.runtime.config.HooksDir, []string{"poststop"}, lang)
+ if err != nil {
+ return nil, err
+ }
+
+ return manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0)
}
// mount mounts the container's root filesystem
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 8861d7728..b540bbeb8 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -224,10 +224,8 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
}
- if !rootless.IsRootless() {
- if c.state.ExtensionStageHooks, err = c.setupOCIHooks(ctx, g.Config); err != nil {
- return nil, errors.Wrapf(err, "error setting up OCI Hooks")
- }
+ if c.state.ExtensionStageHooks, err = c.setupOCIHooks(ctx, g.Config); err != nil {
+ return nil, errors.Wrapf(err, "error setting up OCI Hooks")
}
// Bind builtin image volumes
@@ -238,9 +236,6 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
if c.config.User != "" {
- if !c.state.Mounted {
- return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to translate User field", c.ID())
- }
// User and Group must go together
g.SetProcessUID(uint32(execUser.Uid))
g.SetProcessGID(uint32(execUser.Gid))
@@ -248,9 +243,6 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
// Add addition groups if c.config.GroupAdd is not empty
if len(c.config.Groups) > 0 {
- if !c.state.Mounted {
- return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to add additional groups", c.ID())
- }
gids, _ := lookup.GetContainerGroups(c.config.Groups, c.state.Mountpoint, nil)
for _, gid := range gids {
g.AddProcessAdditionalGid(gid)
@@ -802,7 +794,6 @@ func (c *Container) generateHosts() (string, error) {
func (c *Container) generatePasswd() (string, error) {
var (
groupspec string
- group *user.Group
gid int
)
if c.config.User == "" {
@@ -827,17 +818,16 @@ func (c *Container) generatePasswd() (string, error) {
return "", nil
}
if groupspec != "" {
- if !c.state.Mounted {
- return "", errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to translate group field for passwd record", c.ID())
- }
- group, err = lookup.GetGroup(c.state.Mountpoint, groupspec)
- if err != nil {
- if err == user.ErrNoGroupEntries {
+ ugid, err := strconv.ParseUint(groupspec, 10, 32)
+ if err == nil {
+ gid = int(ugid)
+ } else {
+ group, err := lookup.GetGroup(c.state.Mountpoint, groupspec)
+ if err != nil {
return "", errors.Wrapf(err, "unable to get gid %s from group file", groupspec)
}
- return "", err
+ gid = group.Gid
}
- gid = group.Gid
}
originPasswdFile := filepath.Join(c.state.Mountpoint, "/etc/passwd")
orig, err := ioutil.ReadFile(originPasswdFile)
diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go
index 78e765ccd..77eba0cc6 100644
--- a/libpod/in_memory_state.go
+++ b/libpod/in_memory_state.go
@@ -73,6 +73,18 @@ func (s *InMemoryState) Refresh() error {
return nil
}
+// GetDBConfig is not implemented for in-memory state.
+// As we do not store a config, return an empty one.
+func (s *InMemoryState) GetDBConfig() (*DBConfig, error) {
+ return &DBConfig{}, nil
+}
+
+// ValidateDBConfig is not implemented for the in-memory state.
+// Since we do nothing just return no error.
+func (s *InMemoryState) ValidateDBConfig(runtime *Runtime) error {
+ return nil
+}
+
// SetNamespace sets the namespace for container and pod retrieval.
func (s *InMemoryState) SetNamespace(ns string) error {
s.namespace = ns
diff --git a/libpod/options.go b/libpod/options.go
index 7f4e3ac6b..3e43d73f0 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -29,19 +29,40 @@ func WithStorageConfig(config storage.StoreOptions) RuntimeOption {
return ErrRuntimeFinalized
}
- rt.config.StorageConfig.RunRoot = config.RunRoot
- rt.config.StorageConfig.GraphRoot = config.GraphRoot
- rt.config.StorageConfig.GraphDriverName = config.GraphDriverName
- rt.config.StaticDir = filepath.Join(config.GraphRoot, "libpod")
+ if config.RunRoot != "" {
+ rt.config.StorageConfig.RunRoot = config.RunRoot
+ rt.configuredFrom.storageRunRootSet = true
+ }
+
+ if config.GraphRoot != "" {
+ rt.config.StorageConfig.GraphRoot = config.GraphRoot
+ rt.configuredFrom.storageGraphRootSet = true
+
+ // Also set libpod static dir, so we are a subdirectory
+ // of the c/storage store by default
+ rt.config.StaticDir = filepath.Join(config.GraphRoot, "libpod")
+ rt.configuredFrom.libpodStaticDirSet = true
+ }
+
+ if config.GraphDriverName != "" {
+ rt.config.StorageConfig.GraphDriverName = config.GraphDriverName
+ rt.configuredFrom.storageGraphDriverSet = true
+ }
- rt.config.StorageConfig.GraphDriverOptions = make([]string, len(config.GraphDriverOptions))
- copy(rt.config.StorageConfig.GraphDriverOptions, config.GraphDriverOptions)
+ if config.GraphDriverOptions != nil {
+ rt.config.StorageConfig.GraphDriverOptions = make([]string, len(config.GraphDriverOptions))
+ copy(rt.config.StorageConfig.GraphDriverOptions, config.GraphDriverOptions)
+ }
- rt.config.StorageConfig.UIDMap = make([]idtools.IDMap, len(config.UIDMap))
- copy(rt.config.StorageConfig.UIDMap, config.UIDMap)
+ if config.UIDMap != nil {
+ rt.config.StorageConfig.UIDMap = make([]idtools.IDMap, len(config.UIDMap))
+ copy(rt.config.StorageConfig.UIDMap, config.UIDMap)
+ }
- rt.config.StorageConfig.GIDMap = make([]idtools.IDMap, len(config.GIDMap))
- copy(rt.config.StorageConfig.GIDMap, config.GIDMap)
+ if config.GIDMap != nil {
+ rt.config.StorageConfig.GIDMap = make([]idtools.IDMap, len(config.GIDMap))
+ copy(rt.config.StorageConfig.GIDMap, config.GIDMap)
+ }
return nil
}
@@ -174,26 +195,26 @@ func WithStaticDir(dir string) RuntimeOption {
}
rt.config.StaticDir = dir
+ rt.configuredFrom.libpodStaticDirSet = true
return nil
}
}
-// WithHooksDir sets the directory to look for OCI runtime hooks config.
-// Note we are not saving this in database, since this is really just for used
-// for testing.
-func WithHooksDir(hooksDir string) RuntimeOption {
+// WithHooksDir sets the directories to look for OCI runtime hook configuration.
+func WithHooksDir(hooksDirs ...string) RuntimeOption {
return func(rt *Runtime) error {
if rt.valid {
return ErrRuntimeFinalized
}
- if hooksDir == "" {
- return errors.Wrap(ErrInvalidArg, "empty-string hook directories are not supported")
+ for _, hooksDir := range hooksDirs {
+ if hooksDir == "" {
+ return errors.Wrap(ErrInvalidArg, "empty-string hook directories are not supported")
+ }
}
- rt.config.HooksDir = []string{hooksDir}
- rt.config.HooksDirNotExistFatal = true
+ rt.config.HooksDir = hooksDirs
return nil
}
}
@@ -226,6 +247,7 @@ func WithTmpDir(dir string) RuntimeOption {
}
rt.config.TmpDir = dir
+ rt.configuredFrom.libpodTmpDirSet = true
return nil
}
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 9feae03fc..6b6a8cc2d 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -12,7 +12,6 @@ import (
"github.com/containers/image/types"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/firewall"
- "github.com/containers/libpod/pkg/hooks"
sysreg "github.com/containers/libpod/pkg/registries"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util"
@@ -84,6 +83,7 @@ type Runtime struct {
lock sync.RWMutex
imageRuntime *image.Runtime
firewallBackend firewall.FirewallBackend
+ configuredFrom *runtimeConfiguredFrom
}
// RuntimeConfig contains configuration options used to set up the runtime
@@ -141,11 +141,11 @@ type RuntimeConfig struct {
// CNIDefaultNetwork is the network name of the default CNI network
// to attach pods to
CNIDefaultNetwork string `toml:"cni_default_network,omitempty"`
- // HooksDir Path to the directory containing hooks configuration files
+ // HooksDir holds paths to the directories containing hooks
+ // configuration files. When the same filename is present in in
+ // multiple directories, the file in the directory listed last in
+ // this slice takes precedence.
HooksDir []string `toml:"hooks_dir"`
- // HooksDirNotExistFatal switches between fatal errors and non-fatal
- // warnings if the configured HooksDir does not exist.
- HooksDirNotExistFatal bool `toml:"hooks_dir_not_exist_fatal"`
// DefaultMountsFile is the path to the default mounts file for testing
// purposes only
DefaultMountsFile string `toml:"-"`
@@ -175,6 +175,20 @@ type RuntimeConfig struct {
EnableLabeling bool `toml:"label"`
}
+// runtimeConfiguredFrom is a struct used during early runtime init to help
+// assemble the full RuntimeConfig struct from defaults.
+// It indicated whether several fields in the runtime configuration were set
+// explicitly.
+// If they were not, we may override them with information from the database,
+// if it exists and differs from what is present in the system already.
+type runtimeConfiguredFrom struct {
+ storageGraphDriverSet bool
+ storageGraphRootSet bool
+ storageRunRootSet bool
+ libpodStaticDirSet bool
+ libpodTmpDirSet bool
+}
+
var (
defaultRuntimeConfig = RuntimeConfig{
// Leave this empty so containers/storage will use its defaults
@@ -203,7 +217,6 @@ var (
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
},
CgroupManager: SystemdCgroupsManager,
- HooksDir: []string{hooks.DefaultDir, hooks.OverrideDir},
StaticDir: filepath.Join(storage.DefaultStoreOptions.GraphRoot, "libpod"),
TmpDir: "",
MaxLogSize: -1,
@@ -253,6 +266,7 @@ func SetXdgRuntimeDir(val string) error {
func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
runtime = new(Runtime)
runtime.config = new(RuntimeConfig)
+ runtime.configuredFrom = new(runtimeConfiguredFrom)
// Copy the default configuration
tmpDir, err := getDefaultTmpDir()
@@ -262,6 +276,16 @@ 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, 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")
+ }
+
configPath := ConfigPath
foundConfig := true
rootlessConfigPath := ""
@@ -307,6 +331,25 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
if err != nil {
return nil, errors.Wrapf(err, "error reading configuration file %s", configPath)
}
+
+ // This is ugly, but we need to decode twice.
+ // Once to check if libpod static and tmp dirs were explicitly
+ // set (not enough to check if they're not the default value,
+ // might have been explicitly configured to the default).
+ // A second time to actually get a usable config.
+ tmpConfig := new(RuntimeConfig)
+ if _, err := toml.Decode(string(contents), tmpConfig); err != nil {
+ return nil, errors.Wrapf(err, "error decoding configuration file %s",
+ configPath)
+ }
+
+ if tmpConfig.StaticDir != "" {
+ runtime.configuredFrom.libpodStaticDirSet = true
+ }
+ if tmpConfig.TmpDir != "" {
+ runtime.configuredFrom.libpodTmpDirSet = true
+ }
+
if _, err := toml.Decode(string(contents), runtime.config); err != nil {
return nil, errors.Wrapf(err, "error decoding configuration file %s", configPath)
}
@@ -348,6 +391,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
func NewRuntimeFromConfig(configPath string, options ...RuntimeOption) (runtime *Runtime, err error) {
runtime = new(Runtime)
runtime.config = new(RuntimeConfig)
+ runtime.configuredFrom = new(runtimeConfiguredFrom)
// Set two fields not in the TOML config
runtime.config.StateType = defaultRuntimeConfig.StateType
@@ -426,6 +470,77 @@ func makeRuntime(runtime *Runtime) (err error) {
runtime.config.ConmonPath)
}
+ // Make the static files directory if it does not exist
+ if err := os.MkdirAll(runtime.config.StaticDir, 0700); err != nil {
+ // The directory is allowed to exist
+ if !os.IsExist(err) {
+ return errors.Wrapf(err, "error creating runtime static files directory %s",
+ runtime.config.StaticDir)
+ }
+ }
+
+ // Set up the state
+ switch runtime.config.StateType {
+ case InMemoryStateStore:
+ state, err := NewInMemoryState()
+ if err != nil {
+ return err
+ }
+ runtime.state = state
+ case SQLiteStateStore:
+ return errors.Wrapf(ErrInvalidArg, "SQLite state is currently disabled")
+ case BoltDBStateStore:
+ dbPath := filepath.Join(runtime.config.StaticDir, "bolt_state.db")
+
+ state, err := NewBoltState(dbPath, runtime)
+ if err != nil {
+ return err
+ }
+ runtime.state = state
+ default:
+ return errors.Wrapf(ErrInvalidArg, "unrecognized state type passed")
+ }
+
+ // Grab config from the database so we can reset some defaults
+ dbConfig, err := runtime.state.GetDBConfig()
+ if err != nil {
+ return errors.Wrapf(err, "error retrieving runtime configuration from database")
+ }
+
+ // Reset defaults if they were not explicitly set
+ if !runtime.configuredFrom.storageGraphDriverSet && dbConfig.GraphDriver != "" {
+ runtime.config.StorageConfig.GraphDriverName = dbConfig.GraphDriver
+ }
+ if !runtime.configuredFrom.storageGraphRootSet && dbConfig.StorageRoot != "" {
+ runtime.config.StorageConfig.GraphRoot = dbConfig.StorageRoot
+ }
+ if !runtime.configuredFrom.storageRunRootSet && dbConfig.StorageTmp != "" {
+ runtime.config.StorageConfig.RunRoot = dbConfig.StorageTmp
+ }
+ if !runtime.configuredFrom.libpodStaticDirSet && dbConfig.LibpodRoot != "" {
+ runtime.config.StaticDir = dbConfig.LibpodRoot
+ }
+ if !runtime.configuredFrom.libpodTmpDirSet && dbConfig.LibpodTmp != "" {
+ runtime.config.TmpDir = dbConfig.LibpodTmp
+ }
+
+ logrus.Debugf("Using graph driver %s", runtime.config.StorageConfig.GraphDriverName)
+ logrus.Debugf("Using graph root %s", runtime.config.StorageConfig.GraphRoot)
+ logrus.Debugf("Using run root %s", runtime.config.StorageConfig.RunRoot)
+ logrus.Debugf("Using static dir %s", runtime.config.StaticDir)
+ logrus.Debugf("Using tmp dir %s", runtime.config.TmpDir)
+
+ // Validate our config against the database, now that we've set our
+ // final storage configuration
+ if err := runtime.state.ValidateDBConfig(runtime); err != nil {
+ return err
+ }
+
+ if err := runtime.state.SetNamespace(runtime.config.Namespace); err != nil {
+ return errors.Wrapf(err, "error setting libpod namespace in state")
+ }
+ logrus.Debugf("Set libpod namespace to %q", runtime.config.Namespace)
+
// Set up containers/storage
var store storage.Store
if rootless.SkipStorageSetup() {
@@ -493,15 +608,6 @@ func makeRuntime(runtime *Runtime) (err error) {
}
runtime.ociRuntime = ociRuntime
- // Make the static files directory if it does not exist
- if err := os.MkdirAll(runtime.config.StaticDir, 0755); err != nil {
- // The directory is allowed to exist
- if !os.IsExist(err) {
- return errors.Wrapf(err, "error creating runtime static files directory %s",
- runtime.config.StaticDir)
- }
- }
-
// Make a directory to hold container lockfiles
lockDir := filepath.Join(runtime.config.TmpDir, "lock")
if err := os.MkdirAll(lockDir, 0755); err != nil {
@@ -523,11 +629,13 @@ func makeRuntime(runtime *Runtime) (err error) {
}
// Set up the CNI net plugin
- netPlugin, err := ocicni.InitCNI(runtime.config.CNIDefaultNetwork, runtime.config.CNIConfigDir, runtime.config.CNIPluginDir...)
- if err != nil {
- return errors.Wrapf(err, "error configuring CNI network plugin")
+ if !rootless.IsRootless() {
+ netPlugin, err := ocicni.InitCNI(runtime.config.CNIDefaultNetwork, runtime.config.CNIConfigDir, runtime.config.CNIPluginDir...)
+ if err != nil {
+ return errors.Wrapf(err, "error configuring CNI network plugin")
+ }
+ runtime.netPlugin = netPlugin
}
- runtime.netPlugin = netPlugin
// Set up a firewall backend
backendType := ""
@@ -540,33 +648,6 @@ func makeRuntime(runtime *Runtime) (err error) {
}
runtime.firewallBackend = fwBackend
- // Set up the state
- switch runtime.config.StateType {
- case InMemoryStateStore:
- state, err := NewInMemoryState()
- if err != nil {
- return err
- }
- runtime.state = state
- case SQLiteStateStore:
- return errors.Wrapf(ErrInvalidArg, "SQLite state is currently disabled")
- case BoltDBStateStore:
- dbPath := filepath.Join(runtime.config.StaticDir, "bolt_state.db")
-
- state, err := NewBoltState(dbPath, runtime.lockDir, runtime)
- if err != nil {
- return err
- }
- runtime.state = state
- default:
- return errors.Wrapf(ErrInvalidArg, "unrecognized state type passed")
- }
-
- if err := runtime.state.SetNamespace(runtime.config.Namespace); err != nil {
- return errors.Wrapf(err, "error setting libpod namespace in state")
- }
- logrus.Debugf("Set libpod namespace to %q", runtime.config.Namespace)
-
// We now need to see if the system has restarted
// We check for the presence of a file in our tmp directory to verify this
// This check must be locked to prevent races
diff --git a/libpod/state.go b/libpod/state.go
index 273e81318..06c2003d8 100644
--- a/libpod/state.go
+++ b/libpod/state.go
@@ -1,5 +1,15 @@
package libpod
+// DBConfig is a set of Libpod runtime configuration settings that are saved
+// in a State when it is first created, and can subsequently be retrieved.
+type DBConfig struct {
+ LibpodRoot string
+ LibpodTmp string
+ StorageRoot string
+ StorageTmp string
+ GraphDriver string
+}
+
// State is a storage backend for libpod's current state.
// A State is only initialized once per instance of libpod.
// As such, initialization methods for State implementations may safely assume
@@ -21,6 +31,22 @@ type State interface {
// Refresh clears container and pod states after a reboot
Refresh() error
+ // GetDBConfig retrieves several paths configured within the database
+ // when it was created - namely, Libpod root and tmp dirs, c/storage
+ // root and tmp dirs, and c/storage graph driver.
+ // This is not implemented by the in-memory state, as it has no need to
+ // validate runtime configuration.
+ GetDBConfig() (*DBConfig, error)
+
+ // ValidateDBConfig validates the config in the given Runtime struct
+ // against paths stored in the configured database.
+ // Libpod root and tmp dirs and c/storage root and tmp dirs and graph
+ // driver are validated.
+ // This is not implemented by the in-memory state, as it has no need to
+ // validate runtime configuration that may change over multiple runs of
+ // the program.
+ ValidateDBConfig(runtime *Runtime) error
+
// SetNamespace() sets the namespace for the store, and will determine
// what containers are retrieved with container and pod retrieval calls.
// A namespace of "", the empty string, acts as no namespace, and
diff --git a/libpod/state_test.go b/libpod/state_test.go
index 04572fb29..d93a371f3 100644
--- a/libpod/state_test.go
+++ b/libpod/state_test.go
@@ -45,11 +45,16 @@ func getEmptyBoltState() (s State, p string, p2 string, err error) {
dbPath := filepath.Join(tmpDir, "db.sql")
lockDir := filepath.Join(tmpDir, "locks")
+ if err := os.Mkdir(lockDir, 0755); err != nil {
+ return nil, "", "", err
+ }
+
runtime := new(Runtime)
runtime.config = new(RuntimeConfig)
runtime.config.StorageConfig = storage.StoreOptions{}
+ runtime.lockDir = lockDir
- state, err := NewBoltState(dbPath, lockDir, runtime)
+ state, err := NewBoltState(dbPath, runtime)
if err != nil {
return nil, "", "", err
}
diff --git a/libpod/testdata/config.toml b/libpod/testdata/config.toml
index e19d36017..1d78f2083 100644
--- a/libpod/testdata/config.toml
+++ b/libpod/testdata/config.toml
@@ -14,7 +14,7 @@
seccomp_profile = "/etc/crio/seccomp.json"
apparmor_profile = "crio-default"
cgroup_manager = "cgroupfs"
- hooks_dir_path = "/usr/share/containers/oci/hooks.d"
+ hooks_dir = ["/usr/share/containers/oci/hooks.d"]
pids_limit = 2048
container_exits_dir = "/var/run/podman/exits"
[crio.image]
diff --git a/pkg/lookup/lookup.go b/pkg/lookup/lookup.go
index a9d975b4b..70b97144f 100644
--- a/pkg/lookup/lookup.go
+++ b/pkg/lookup/lookup.go
@@ -99,9 +99,11 @@ func GetContainerGroups(groups []string, containerMount string, override *Overri
return uintgids, nil
}
-// GetUser takes a containermount path and user name or id and returns
+// GetUser takes a containermount path and user name or ID and returns
// a matching User structure from /etc/passwd. If it cannot locate a user
// with the provided information, an ErrNoPasswdEntries is returned.
+// When the provided user name was an ID, a User structure with Uid
+// set is returned along with ErrNoPasswdEntries.
func GetUser(containerMount, userIDorName string) (*user.User, error) {
var inputIsName bool
uid, err := strconv.Atoi(userIDorName)
@@ -124,12 +126,17 @@ func GetUser(containerMount, userIDorName string) (*user.User, error) {
if len(users) > 0 {
return &users[0], nil
}
+ if !inputIsName {
+ return &user.User{Uid: uid}, user.ErrNoPasswdEntries
+ }
return nil, user.ErrNoPasswdEntries
}
-// GetGroup takes ac ontainermount path and a group name or id and returns
-// a match Group struct from /etc/group. if it cannot locate a group,
-// an ErrNoGroupEntries error is returned.
+// GetGroup takes a containermount path and a group name or ID and returns
+// a match Group struct from /etc/group. If it cannot locate a group,
+// an ErrNoGroupEntries error is returned. When the provided group name
+// was an ID, a Group structure with Gid set is returned along with
+// ErrNoGroupEntries.
func GetGroup(containerMount, groupIDorName string) (*user.Group, error) {
var inputIsName bool
gid, err := strconv.Atoi(groupIDorName)
@@ -154,5 +161,8 @@ func GetGroup(containerMount, groupIDorName string) (*user.Group, error) {
if len(groups) > 0 {
return &groups[0], nil
}
+ if !inputIsName {
+ return &user.Group{Gid: gid}, user.ErrNoGroupEntries
+ }
return nil, user.ErrNoGroupEntries
}
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index 85b0ef392..07002da3f 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -74,7 +74,7 @@ func GetRootlessUID() int {
func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap) error {
path, err := exec.LookPath(tool)
if err != nil {
- return err
+ return errors.Wrapf(err, "cannot find %s", tool)
}
appendTriplet := func(l []string, a, b, c int) []string {
@@ -92,7 +92,11 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap)
Path: path,
Args: args,
}
- return cmd.Run()
+
+ if err := cmd.Run(); err != nil {
+ return errors.Wrapf(err, "cannot setup namespace using %s", tool)
+ }
+ return nil
}
// JoinNS re-exec podman in a new userNS and join the user namespace of the specified
@@ -191,11 +195,13 @@ func BecomeRootInUserNS() (bool, int, error) {
return false, -1, errors.Errorf("cannot re-exec process")
}
+ allowSingleIDMapping := os.Getenv("PODMAN_ALLOW_SINGLE_ID_MAPPING_IN_USERNS") != ""
+
var uids, gids []idtools.IDMap
username := os.Getenv("USER")
if username == "" {
user, err := user.LookupId(fmt.Sprintf("%d", os.Getuid()))
- if err != nil && os.Getenv("PODMAN_ALLOW_SINGLE_ID_MAPPING_IN_USERNS") == "" {
+ if err != nil && !allowSingleIDMapping {
if os.IsNotExist(err) {
return false, 0, errors.Wrapf(err, "/etc/subuid or /etc/subgid does not exist, see subuid/subgid man pages for information on these files")
}
@@ -206,7 +212,7 @@ func BecomeRootInUserNS() (bool, int, error) {
}
}
mappings, err := idtools.NewIDMappings(username, username)
- if os.Getenv("PODMAN_ALLOW_SINGLE_ID_MAPPING_IN_USERNS") == "" {
+ if !allowSingleIDMapping {
if err != nil {
return false, -1, err
}
@@ -236,7 +242,11 @@ func BecomeRootInUserNS() (bool, int, error) {
uidsMapped := false
if mappings != nil && uids != nil {
- uidsMapped = tryMappingTool("newuidmap", pid, os.Getuid(), uids) == nil
+ err := tryMappingTool("newuidmap", pid, os.Getuid(), uids)
+ if !allowSingleIDMapping && err != nil {
+ return false, 0, err
+ }
+ uidsMapped = err == nil
}
if !uidsMapped {
setgroups := fmt.Sprintf("/proc/%d/setgroups", pid)
@@ -254,7 +264,11 @@ func BecomeRootInUserNS() (bool, int, error) {
gidsMapped := false
if mappings != nil && gids != nil {
- gidsMapped = tryMappingTool("newgidmap", pid, os.Getgid(), gids) == nil
+ err := tryMappingTool("newgidmap", pid, os.Getgid(), gids)
+ if !allowSingleIDMapping && err != nil {
+ return false, 0, err
+ }
+ gidsMapped = err == nil
}
if !gidsMapped {
gidMap := fmt.Sprintf("/proc/%d/gid_map", pid)
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index a0fd40318..25f8cd7a1 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -496,8 +496,13 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib
// CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands
func (c *CreateConfig) CreatePortBindings() ([]ocicni.PortMapping, error) {
+ return NatToOCIPortBindings(c.PortBindings)
+}
+
+// NatToOCIPortBindings iterates a nat.portmap slice and creates []ocicni portmapping slice
+func NatToOCIPortBindings(ports nat.PortMap) ([]ocicni.PortMapping, error) {
var portBindings []ocicni.PortMapping
- for containerPb, hostPb := range c.PortBindings {
+ for containerPb, hostPb := range ports {
var pm ocicni.PortMapping
pm.ContainerPort = int32(containerPb.Int())
for _, i := range hostPb {
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index de29bc5d8..e483253a4 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -313,7 +313,7 @@ func getTomlStorage(storeOptions *storage.StoreOptions) *tomlConfig {
return config
}
-// GetDefaultStoreOptions returns the storage ops for containers
+// GetDefaultStoreOptions returns the default storage options for containers.
func GetDefaultStoreOptions() (storage.StoreOptions, error) {
storageOpts := storage.DefaultStoreOptions
if rootless.IsRootless() {
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index 366a58f02..684a7cd88 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -189,4 +189,15 @@ var _ = Describe("Podman create", func() {
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("/create/test rw,nosuid,nodev,noexec,relatime - tmpfs"))
})
+
+ It("podman create --pod automatically", func() {
+ session := podmanTest.Podman([]string{"create", "--pod", "new:foobar", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"pod", "ps", "--no-trunc"})
+ check.WaitWithDefaultTimeout()
+ match, _ := check.GrepString("foobar")
+ Expect(match).To(BeTrue())
+ })
})
diff --git a/test/e2e/exists_test.go b/test/e2e/exists_test.go
index 9165e8902..d9652de4b 100644
--- a/test/e2e/exists_test.go
+++ b/test/e2e/exists_test.go
@@ -82,4 +82,36 @@ var _ = Describe("Podman image|container exists", func() {
Expect(session.ExitCode()).To(Equal(1))
})
+ It("podman pod exists in local storage by name", func() {
+ setup, rc, _ := podmanTest.CreatePod("foobar")
+ setup.WaitWithDefaultTimeout()
+ Expect(rc).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"pod", "exists", "foobar"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+ It("podman pod exists in local storage by container ID", func() {
+ setup, rc, podID := podmanTest.CreatePod("")
+ setup.WaitWithDefaultTimeout()
+ Expect(rc).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"pod", "exists", podID})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+ It("podman pod exists in local storage by short container ID", func() {
+ setup, rc, podID := podmanTest.CreatePod("")
+ setup.WaitWithDefaultTimeout()
+ Expect(rc).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"pod", "exists", podID[0:12]})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+ It("podman pod does not exist in local storage", func() {
+ session := podmanTest.Podman([]string{"pod", "exists", "foobar"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(1))
+ })
})
diff --git a/test/e2e/rmi_test.go b/test/e2e/rmi_test.go
index c2eb8b7d7..22bfbbe8c 100644
--- a/test/e2e/rmi_test.go
+++ b/test/e2e/rmi_test.go
@@ -250,4 +250,25 @@ var _ = Describe("Podman rmi", func() {
session2.WaitWithDefaultTimeout()
Expect(session2.ExitCode()).To(Equal(0))
})
+
+ It("podman rmi -a with parent|child images", func() {
+ dockerfile := `FROM docker.io/library/alpine:latest AS base
+RUN touch /1
+ENV LOCAL=/1
+RUN find $LOCAL
+FROM base
+RUN find $LOCAL
+
+`
+ podmanTest.BuildImage(dockerfile, "test", "true")
+ session := podmanTest.Podman([]string{"rmi", "-a"})
+ session.WaitWithDefaultTimeout()
+ fmt.Println(session.OutputToString())
+ Expect(session.ExitCode()).To(Equal(0))
+
+ images := podmanTest.Podman([]string{"images", "--all"})
+ images.WaitWithDefaultTimeout()
+ Expect(images.ExitCode()).To(Equal(0))
+ Expect(len(images.OutputToStringArray())).To(Equal(0))
+ })
})
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 38504828b..4a9bd4e46 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -336,7 +336,7 @@ var _ = Describe("Podman run", func() {
hooksDir := tempdir + "/hooks"
os.Mkdir(hooksDir, 0755)
fileutils.CopyFile("hooks/hooks.json", hooksDir)
- os.Setenv("HOOK_OPTION", fmt.Sprintf("--hooks-dir-path=%s", hooksDir))
+ os.Setenv("HOOK_OPTION", fmt.Sprintf("--hooks-dir=%s", hooksDir))
os.Remove(hcheck)
session := podmanTest.Podman([]string{"run", ALPINE, "ls"})
session.Wait(10)
@@ -628,4 +628,15 @@ USER mail`
isSharedOnly := !strings.Contains(shared[0], "shared,")
Expect(isSharedOnly).Should(BeTrue())
})
+
+ It("podman run --pod automatically", func() {
+ session := podmanTest.Podman([]string{"run", "--pod", "new:foobar", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"pod", "ps", "--no-trunc"})
+ check.WaitWithDefaultTimeout()
+ match, _ := check.GrepString("foobar")
+ Expect(match).To(BeTrue())
+ })
})
diff --git a/vendor.conf b/vendor.conf
index be306a181..51907f763 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -12,7 +12,7 @@ github.com/containerd/continuity master
github.com/containernetworking/cni v0.7.0-alpha1
github.com/containernetworking/plugins 1562a1e60ed101aacc5e08ed9dbeba8e9f3d4ec1
github.com/containers/image bd10b1b53b2976f215b3f2f848fb8e7cad779aeb
-github.com/containers/storage 9d3838cd434d32042f9bdf1f9f4a2bf2d6ea8dc5
+github.com/containers/storage ad0f9c4dfa38fcb160f430ff1d653dc3dae03810
github.com/containers/psgo 5dde6da0bc8831b35243a847625bcf18183bd1ee
github.com/coreos/go-systemd v14
github.com/cri-o/ocicni 2d2983e40c242322a56c22a903785e7f83eb378c
diff --git a/vendor/github.com/containers/storage/drivers/fsdiff.go b/vendor/github.com/containers/storage/drivers/fsdiff.go
index 19da7d101..ab2c41e58 100644
--- a/vendor/github.com/containers/storage/drivers/fsdiff.go
+++ b/vendor/github.com/containers/storage/drivers/fsdiff.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/storage/pkg/chrootarchive"
"github.com/containers/storage/pkg/idtools"
"github.com/containers/storage/pkg/ioutils"
+ rsystem "github.com/opencontainers/runc/libcontainer/system"
"github.com/sirupsen/logrus"
)
@@ -167,7 +168,9 @@ func (gdw *NaiveDiffDriver) ApplyDiff(id string, applyMappings *idtools.IDMappin
}
defer driver.Put(id)
- options := &archive.TarOptions{}
+ options := &archive.TarOptions{
+ InUserNS: rsystem.RunningInUserNS(),
+ }
if applyMappings != nil {
options.UIDMaps = applyMappings.UIDs()
options.GIDMaps = applyMappings.GIDs()
diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
index a165a13a3..df736c0a9 100644
--- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go
+++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
@@ -29,6 +29,7 @@ import (
"github.com/containers/storage/pkg/parsers"
"github.com/containers/storage/pkg/system"
units "github.com/docker/go-units"
+ rsystem "github.com/opencontainers/runc/libcontainer/system"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -876,6 +877,7 @@ func (d *Driver) ApplyDiff(id string, idMappings *idtools.IDMappings, parent str
UIDMaps: idMappings.UIDs(),
GIDMaps: idMappings.GIDs(),
WhiteoutFormat: d.getWhiteoutFormat(),
+ InUserNS: rsystem.RunningInUserNS(),
}); err != nil {
return 0, err
}
diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go
index 6c8f59b8b..0b532eb77 100644
--- a/vendor/github.com/containers/storage/layers.go
+++ b/vendor/github.com/containers/storage/layers.go
@@ -28,9 +28,8 @@ import (
)
const (
- tarSplitSuffix = ".tar-split.gz"
- incompleteFlag = "incomplete"
- compressionFlag = "diff-compression"
+ tarSplitSuffix = ".tar-split.gz"
+ incompleteFlag = "incomplete"
)
// A Layer is a record of a copy-on-write layer that's stored by the lower
diff --git a/vendor/github.com/containers/storage/pkg/archive/archive.go b/vendor/github.com/containers/storage/pkg/archive/archive.go
index 4c4382625..8d6eaacf3 100644
--- a/vendor/github.com/containers/storage/pkg/archive/archive.go
+++ b/vendor/github.com/containers/storage/pkg/archive/archive.go
@@ -22,6 +22,7 @@ import (
"github.com/containers/storage/pkg/pools"
"github.com/containers/storage/pkg/promise"
"github.com/containers/storage/pkg/system"
+ rsystem "github.com/opencontainers/runc/libcontainer/system"
"github.com/sirupsen/logrus"
)
@@ -1054,6 +1055,7 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
GIDMaps: tarMappings.GIDs(),
Compression: Uncompressed,
CopyPass: true,
+ InUserNS: rsystem.RunningInUserNS(),
}
archive, err := TarWithOptions(src, options)
if err != nil {
@@ -1068,6 +1070,7 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
UIDMaps: untarMappings.UIDs(),
GIDMaps: untarMappings.GIDs(),
ChownOpts: archiver.ChownOpts,
+ InUserNS: rsystem.RunningInUserNS(),
}
return archiver.Untar(archive, dst, options)
}
@@ -1087,6 +1090,7 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
UIDMaps: untarMappings.UIDs(),
GIDMaps: untarMappings.GIDs(),
ChownOpts: archiver.ChownOpts,
+ InUserNS: rsystem.RunningInUserNS(),
}
return archiver.Untar(archive, dst, options)
}
@@ -1186,6 +1190,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
UIDMaps: archiver.UntarIDMappings.UIDs(),
GIDMaps: archiver.UntarIDMappings.GIDs(),
ChownOpts: archiver.ChownOpts,
+ InUserNS: rsystem.RunningInUserNS(),
}
err = archiver.Untar(r, filepath.Dir(dst), options)
if err != nil {
diff --git a/vendor/github.com/containers/storage/pkg/archive/example_changes.go b/vendor/github.com/containers/storage/pkg/archive/example_changes.go
deleted file mode 100644
index 70f9c5564..000000000
--- a/vendor/github.com/containers/storage/pkg/archive/example_changes.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// +build ignore
-
-// Simple tool to create an archive stream from an old and new directory
-//
-// By default it will stream the comparison of two temporary directories with junk files
-package main
-
-import (
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "path"
-
- "github.com/containers/storage/pkg/archive"
- "github.com/sirupsen/logrus"
-)
-
-var (
- flDebug = flag.Bool("D", false, "debugging output")
- flNewDir = flag.String("newdir", "", "")
- flOldDir = flag.String("olddir", "", "")
- log = logrus.New()
-)
-
-func main() {
- flag.Usage = func() {
- fmt.Println("Produce a tar from comparing two directory paths. By default a demo tar is created of around 200 files (including hardlinks)")
- fmt.Printf("%s [OPTIONS]\n", os.Args[0])
- flag.PrintDefaults()
- }
- flag.Parse()
- log.Out = os.Stderr
- if (len(os.Getenv("DEBUG")) > 0) || *flDebug {
- logrus.SetLevel(logrus.DebugLevel)
- }
- var newDir, oldDir string
-
- if len(*flNewDir) == 0 {
- var err error
- newDir, err = ioutil.TempDir("", "storage-test-newDir")
- if err != nil {
- log.Fatal(err)
- }
- defer os.RemoveAll(newDir)
- if _, err := prepareUntarSourceDirectory(100, newDir, true); err != nil {
- log.Fatal(err)
- }
- } else {
- newDir = *flNewDir
- }
-
- if len(*flOldDir) == 0 {
- oldDir, err := ioutil.TempDir("", "storage-test-oldDir")
- if err != nil {
- log.Fatal(err)
- }
- defer os.RemoveAll(oldDir)
- } else {
- oldDir = *flOldDir
- }
-
- changes, err := archive.ChangesDirs(newDir, oldDir)
- if err != nil {
- log.Fatal(err)
- }
-
- a, err := archive.ExportChanges(newDir, changes)
- if err != nil {
- log.Fatal(err)
- }
- defer a.Close()
-
- i, err := io.Copy(os.Stdout, a)
- if err != nil && err != io.EOF {
- log.Fatal(err)
- }
- fmt.Fprintf(os.Stderr, "wrote archive of %d bytes", i)
-}
-
-func prepareUntarSourceDirectory(numberOfFiles int, targetPath string, makeLinks bool) (int, error) {
- fileData := []byte("fooo")
- for n := 0; n < numberOfFiles; n++ {
- fileName := fmt.Sprintf("file-%d", n)
- if err := ioutil.WriteFile(path.Join(targetPath, fileName), fileData, 0700); err != nil {
- return 0, err
- }
- if makeLinks {
- if err := os.Link(path.Join(targetPath, fileName), path.Join(targetPath, fileName+"-link")); err != nil {
- return 0, err
- }
- }
- }
- totalSize := numberOfFiles * len(fileData)
- return totalSize, nil
-}
diff --git a/vendor/github.com/containers/storage/pkg/chrootarchive/archive.go b/vendor/github.com/containers/storage/pkg/chrootarchive/archive.go
index b9fa228e6..dde8d44d3 100644
--- a/vendor/github.com/containers/storage/pkg/chrootarchive/archive.go
+++ b/vendor/github.com/containers/storage/pkg/chrootarchive/archive.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/idtools"
+ rsystem "github.com/opencontainers/runc/libcontainer/system"
)
// NewArchiver returns a new Archiver which uses chrootarchive.Untar
@@ -52,6 +53,7 @@ func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions
}
if options == nil {
options = &archive.TarOptions{}
+ options.InUserNS = rsystem.RunningInUserNS()
}
if options.ExcludePatterns == nil {
options.ExcludePatterns = []string{}