aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/exec.go9
-rw-r--r--docs/podman-exec.1.md34
-rw-r--r--docs/podman-run.1.md17
-rw-r--r--docs/podman.1.md11
-rw-r--r--libpod/boltdb_state.go70
-rw-r--r--libpod/boltdb_state_internal.go170
-rw-r--r--libpod/container_api.go2
-rw-r--r--vendor.conf2
-rw-r--r--vendor/github.com/containers/storage/drivers/aufs/aufs.go22
-rw-r--r--vendor/github.com/containers/storage/drivers/btrfs/btrfs.go10
-rw-r--r--vendor/github.com/containers/storage/drivers/devmapper/driver.go8
-rw-r--r--vendor/github.com/containers/storage/drivers/driver.go15
-rw-r--r--vendor/github.com/containers/storage/drivers/overlay/overlay.go124
-rw-r--r--vendor/github.com/containers/storage/drivers/vfs/driver.go8
-rw-r--r--vendor/github.com/containers/storage/drivers/windows/windows.go4
-rw-r--r--vendor/github.com/containers/storage/drivers/zfs/zfs.go10
-rw-r--r--vendor/github.com/containers/storage/store.go1
17 files changed, 354 insertions, 163 deletions
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go
index 073e72e64..9e265b48c 100644
--- a/cmd/podman/exec.go
+++ b/cmd/podman/exec.go
@@ -109,5 +109,12 @@ func execCmd(c *cli.Context) error {
envs = append(envs, fmt.Sprintf("%s=%s", k, v))
}
- return ctr.Exec(c.Bool("tty"), c.Bool("privileged"), envs, cmd, c.String("user"), c.String("workdir"))
+ if err := ctr.Exec(c.Bool("tty"), c.Bool("privileged"), envs, cmd, c.String("user"), c.String("workdir")); err != nil {
+ if errors.Cause(err) == libpod.ErrCtrStateInvalid {
+ exitCode = 126
+ }
+ return err
+ }
+
+ return nil
}
diff --git a/docs/podman-exec.1.md b/docs/podman-exec.1.md
index 77317b0ca..906109f87 100644
--- a/docs/podman-exec.1.md
+++ b/docs/podman-exec.1.md
@@ -46,6 +46,40 @@ The default working directory for running binaries within a container is the roo
The image developer can set a different default with the WORKDIR instruction, which can be overridden
when creating the container.
+## Exit Status
+
+The exit code from `podman exec` gives information about why the command within the container failed to run or why it exited. When `podman exec` exits with a
+non-zero code, the exit codes follow the `chroot` standard, see below:
+
+**_125_** if the error is with podman **_itself_**
+
+ $ podman exec --foo ctrID /bin/sh; echo $?
+ Error: unknown flag: --foo
+ 125
+
+**_126_** if the **_contained command_** cannot be invoked
+
+ $ podman exec ctrID /etc; echo $?
+ Error: container_linux.go:346: starting container process caused "exec: \"/etc\": permission denied": OCI runtime error
+ 126
+
+**_127_** if the **_contained command_** cannot be found
+
+ $ podman exec ctrID foo; echo $?
+ Error: container_linux.go:346: starting container process caused "exec: \"foo\": executable file not found in $PATH": OCI runtime error
+ 127
+
+**_Exit code_** of **_contained command_** otherwise
+
+ $ podman exec ctrID /bin/sh -c 'exit 3'
+ # 3
+
+## EXAMPLES
+
+$ podman exec -it ctrID ls
+$ podman exec -it -w /tmp myCtr pwd
+$ podman exec --user root ctrID ls
+
## SEE ALSO
podman(1), podman-run(1)
diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md
index 8b96ea6d9..ee51c3bb8 100644
--- a/docs/podman-run.1.md
+++ b/docs/podman-run.1.md
@@ -819,28 +819,25 @@ the exit codes follow the `chroot` standard, see below:
**_125_** if the error is with podman **_itself_**
$ podman run --foo busybox; echo $?
- # flag provided but not defined: --foo
- See 'podman run --help'.
- 125
+ Error: unknown flag: --foo
+ 125
**_126_** if the **_contained command_** cannot be invoked
$ podman run busybox /etc; echo $?
- # exec: "/etc": permission denied
- podman: Error response from daemon: Contained command could not be invoked
- 126
+ Error: container_linux.go:346: starting container process caused "exec: \"/etc\": permission denied": OCI runtime error
+ 126
**_127_** if the **_contained command_** cannot be found
$ podman run busybox foo; echo $?
- # exec: "foo": executable file not found in $PATH
- podman: Error response from daemon: Contained command not found or does not exist
- 127
+ Error: container_linux.go:346: starting container process caused "exec: \"foo\": executable file not found in $PATH": OCI runtime error
+ 127
**_Exit code_** of **_contained command_** otherwise
$ podman run busybox /bin/sh -c 'exit 3'
- # 3
+ 3
## EXAMPLES
diff --git a/docs/podman.1.md b/docs/podman.1.md
index a73ebb55e..9be41c3f6 100644
--- a/docs/podman.1.md
+++ b/docs/podman.1.md
@@ -98,24 +98,21 @@ the exit codes follow the `chroot` standard, see below:
**_125_** if the error is with podman **_itself_**
$ podman run --foo busybox; echo $?
- # flag provided but not defined: --foo
- See 'podman run --help'.
+ Error: unknown flag: --foo
125
**_126_** if executing a **_container command_** and the the **_command_** cannot be invoked
$ podman run busybox /etc; echo $?
- # exec: "/etc": permission denied
- podman: Error response from daemon: Contained command could not be invoked
+ Error: container_linux.go:346: starting container process caused "exec: \"/etc\": permission denied": OCI runtime error
126
**_127_** if executing a **_container command_** and the the **_command_** cannot be found
$ podman run busybox foo; echo $?
- # exec: "foo": executable file not found in $PATH
- podman: Error response from daemon: Contained command not found or does not exist
+ Error: container_linux.go:346: starting container process caused "exec: \"foo\": executable file not found in $PATH": OCI runtime error
127
-**_Exit code_** of **_container command_** otherwise
+**_Exit code_** of **_contained command_** otherwise
$ podman run busybox /bin/sh -c 'exit 3'
# 3
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index b154d8bda..fdae08bf3 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -71,42 +71,50 @@ func NewBoltState(path string, runtime *Runtime) (State, error) {
// As such, just a db.Close() is fine here.
defer db.Close()
- // Perform initial database setup
- err = db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucketIfNotExists(idRegistryBkt); err != nil {
- return errors.Wrapf(err, "error creating id-registry bucket")
- }
- if _, err := tx.CreateBucketIfNotExists(nameRegistryBkt); err != nil {
- return errors.Wrapf(err, "error creating name-registry bucket")
- }
- if _, err := tx.CreateBucketIfNotExists(nsRegistryBkt); err != nil {
- return errors.Wrapf(err, "error creating ns-registry bucket")
- }
- if _, err := tx.CreateBucketIfNotExists(ctrBkt); err != nil {
- return errors.Wrapf(err, "error creating containers bucket")
- }
- if _, err := tx.CreateBucketIfNotExists(allCtrsBkt); err != nil {
- return errors.Wrapf(err, "error creating all containers bucket")
- }
- if _, err := tx.CreateBucketIfNotExists(podBkt); err != nil {
- return errors.Wrapf(err, "error creating pods bucket")
- }
- if _, err := tx.CreateBucketIfNotExists(allPodsBkt); err != nil {
- return errors.Wrapf(err, "error creating all pods bucket")
- }
- if _, err := tx.CreateBucketIfNotExists(volBkt); err != nil {
- return errors.Wrapf(err, "error creating volume bucket")
- }
- if _, err := tx.CreateBucketIfNotExists(allVolsBkt); err != nil {
- return errors.Wrapf(err, "error creating all volumes bucket")
+ createBuckets := [][]byte{
+ idRegistryBkt,
+ nameRegistryBkt,
+ nsRegistryBkt,
+ ctrBkt,
+ allCtrsBkt,
+ podBkt,
+ allPodsBkt,
+ volBkt,
+ allVolsBkt,
+ runtimeConfigBkt,
+ }
+
+ // Does the DB need an update?
+ needsUpdate := false
+ err = db.View(func(tx *bolt.Tx) error {
+ for _, bkt := range createBuckets {
+ if test := tx.Bucket(bkt); test == nil {
+ needsUpdate = true
+ break
+ }
}
- if _, err := tx.CreateBucketIfNotExists(runtimeConfigBkt); err != nil {
- return errors.Wrapf(err, "error creating runtime-config bucket")
+ return nil
+ })
+ if err != nil {
+ return nil, errors.Wrapf(err, "error checking DB schema")
+ }
+
+ if !needsUpdate {
+ state.valid = true
+ return state, nil
+ }
+
+ // Ensure schema is properly created in DB
+ err = db.Update(func(tx *bolt.Tx) error {
+ for _, bkt := range createBuckets {
+ if _, err := tx.CreateBucketIfNotExists(bkt); err != nil {
+ return errors.Wrapf(err, "error creating bucket %s", string(bkt))
+ }
}
return nil
})
if err != nil {
- return nil, errors.Wrapf(err, "error creating initial database layout")
+ return nil, errors.Wrapf(err, "error creating buckets for DB")
}
state.valid = true
diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go
index 06f8dcb24..1c746c724 100644
--- a/libpod/boltdb_state_internal.go
+++ b/libpod/boltdb_state_internal.go
@@ -71,89 +71,149 @@ var (
osKey = []byte(osName)
)
+// This represents a field in the runtime configuration that will be validated
+// against the DB to ensure no configuration mismatches occur.
+type dbConfigValidation struct {
+ name string // Only used for error messages
+ runtimeValue string
+ key []byte
+ defaultValue string
+}
+
// 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 {
- err := db.Update(func(tx *bolt.Tx) error {
+ // We need to validate the following things
+ checks := []dbConfigValidation{
+ {
+ "OS",
+ runtime.GOOS,
+ osKey,
+ runtime.GOOS,
+ },
+ {
+ "libpod root directory (staticdir)",
+ rt.config.StaticDir,
+ staticDirKey,
+ "",
+ },
+ {
+ "libpod temporary files directory (tmpdir)",
+ rt.config.TmpDir,
+ tmpDirKey,
+ "",
+ },
+ {
+ "storage temporary directory (runroot)",
+ rt.config.StorageConfig.RunRoot,
+ runRootKey,
+ storage.DefaultStoreOptions.RunRoot,
+ },
+ {
+ "storage graph root directory (graphroot)",
+ rt.config.StorageConfig.GraphRoot,
+ graphRootKey,
+ storage.DefaultStoreOptions.GraphRoot,
+ },
+ {
+ "storage graph driver",
+ rt.config.StorageConfig.GraphDriverName,
+ graphDriverKey,
+ storage.DefaultStoreOptions.GraphDriverName,
+ },
+ }
+
+ // These fields were missing and will have to be recreated.
+ missingFields := []dbConfigValidation{}
+
+ // Let's try and validate read-only first
+ err := db.View(func(tx *bolt.Tx) error {
configBkt, err := getRuntimeConfigBucket(tx)
if err != nil {
return err
}
- if err := validateDBAgainstConfig(configBkt, "OS", runtime.GOOS, osKey, runtime.GOOS); err != nil {
- return err
+ for _, check := range checks {
+ exists, err := readOnlyValidateConfig(configBkt, check)
+ if err != nil {
+ return err
+ }
+ if !exists {
+ missingFields = append(missingFields, check)
+ }
}
- if err := validateDBAgainstConfig(configBkt, "libpod root directory (staticdir)",
- rt.config.StaticDir, staticDirKey, ""); err != nil {
- return err
- }
+ return nil
+ })
+ if err != nil {
+ return err
+ }
- if err := validateDBAgainstConfig(configBkt, "libpod temporary files directory (tmpdir)",
- rt.config.TmpDir, tmpDirKey, ""); err != nil {
- return err
- }
+ if len(missingFields) == 0 {
+ return nil
+ }
- if err := validateDBAgainstConfig(configBkt, "storage temporary directory (runroot)",
- rt.config.StorageConfig.RunRoot, runRootKey,
- storage.DefaultStoreOptions.RunRoot); err != nil {
+ // Populate missing fields
+ return db.Update(func(tx *bolt.Tx) error {
+ configBkt, err := getRuntimeConfigBucket(tx)
+ if err != nil {
return err
}
- if err := validateDBAgainstConfig(configBkt, "storage graph root directory (graphroot)",
- rt.config.StorageConfig.GraphRoot, graphRootKey,
- storage.DefaultStoreOptions.GraphRoot); err != nil {
- return err
+ for _, missing := range missingFields {
+ dbValue := []byte(missing.runtimeValue)
+ if missing.runtimeValue == "" && missing.defaultValue != "" {
+ dbValue = []byte(missing.defaultValue)
+ }
+
+ if err := configBkt.Put(missing.key, dbValue); err != nil {
+ return errors.Wrapf(err, "error updating %s in DB runtime config", missing.name)
+ }
}
- return validateDBAgainstConfig(configBkt, "storage graph driver",
- rt.config.StorageConfig.GraphDriverName,
- graphDriverKey,
- storage.DefaultStoreOptions.GraphDriverName)
+ return nil
})
-
- return err
}
-// Validate a configuration entry in the DB against current runtime config
-// If the given configuration key does not exist it will be created
-// If the given runtimeValue or value retrieved from the database are the empty
-// string and defaultValue is not, defaultValue will be checked instead. This
-// ensures that we will not fail on configuration changes in configured c/storage.
-func validateDBAgainstConfig(bucket *bolt.Bucket, fieldName, runtimeValue string, keyName []byte, defaultValue string) error {
- keyBytes := bucket.Get(keyName)
+// Attempt a read-only validation of a configuration entry in the DB against an
+// element of the current runtime configuration.
+// If the configuration key in question does not exist, (false, nil) will be
+// returned.
+// If the configuration key does exist, and matches the runtime configuration
+// successfully, (true, nil) is returned.
+// An error is only returned when validation fails.
+// if the given runtimeValue or value retrieved from the database are empty,
+// and defaultValue is not, defaultValue will be checked instead. This ensures
+// that we will not fail on configuration changes in c/storage (where we may
+// pass the empty string to use defaults).
+func readOnlyValidateConfig(bucket *bolt.Bucket, toCheck dbConfigValidation) (bool, error) {
+ keyBytes := bucket.Get(toCheck.key)
if keyBytes == nil {
- dbValue := []byte(runtimeValue)
- if runtimeValue == "" && defaultValue != "" {
- dbValue = []byte(defaultValue)
- }
+ // False return indicates missing key
+ return false, nil
+ }
- if err := bucket.Put(keyName, dbValue); err != nil {
- return errors.Wrapf(err, "error updating %s in DB runtime config", fieldName)
- }
- } else {
- if runtimeValue != string(keyBytes) {
- // If runtimeValue is the empty string, check against
- // the default
- if runtimeValue == "" && defaultValue != "" &&
- string(keyBytes) == defaultValue {
- return nil
- }
+ dbValue := string(keyBytes)
- // If DB value is the empty string, check that the
- // runtime value is the default
- if string(keyBytes) == "" && defaultValue != "" &&
- runtimeValue == defaultValue {
- return nil
- }
+ if toCheck.runtimeValue != dbValue {
+ // If the runtime value is the empty string and default is not,
+ // check against default.
+ if toCheck.runtimeValue == "" && toCheck.defaultValue != "" && dbValue == toCheck.defaultValue {
+ return true, nil
+ }
- return errors.Wrapf(ErrDBBadConfig, "database %s %s does not match our %s %s",
- fieldName, string(keyBytes), fieldName, runtimeValue)
+ // If the DB value is the empty string, check that the runtime
+ // value is the default.
+ if dbValue == "" && toCheck.defaultValue != "" && toCheck.runtimeValue == toCheck.defaultValue {
+ return true, nil
}
+
+ return true, errors.Wrapf(ErrDBBadConfig, "database %s %q does not match our %s %q",
+ toCheck.name, dbValue, toCheck.name, toCheck.runtimeValue)
}
- return nil
+ return true, nil
}
// Open a connection to the database.
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 4eaf737b0..832801aeb 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -285,7 +285,7 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir
// TODO can probably relax this once we track exec sessions
if conState != ContainerStateRunning {
- return errors.Errorf("cannot exec into container that is not running")
+ return errors.Wrapf(ErrCtrStateInvalid, "cannot exec into container that is not running")
}
if privileged || c.config.Privileged {
capList = caps.GetAllCapabilities()
diff --git a/vendor.conf b/vendor.conf
index c9af75719..5f5b8090a 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 93bced01015eb94bec4821df1876314be8197680
-github.com/containers/storage 06b6c2e4cf254f5922a79da058c94ac2a65bb92f
+github.com/containers/storage 67bf6c9b41967780f4bcb5725c00283ad6397679 https://github.com/mheon/storage.git
github.com/containers/psgo dc0bc9fac5b715034c4310ed4d795b3182360842
github.com/coreos/go-systemd v14
github.com/cri-o/ocicni 2d2983e40c242322a56c22a903785e7f83eb378c
diff --git a/vendor/github.com/containers/storage/drivers/aufs/aufs.go b/vendor/github.com/containers/storage/drivers/aufs/aufs.go
index e821bc0c5..3b4562bdd 100644
--- a/vendor/github.com/containers/storage/drivers/aufs/aufs.go
+++ b/vendor/github.com/containers/storage/drivers/aufs/aufs.go
@@ -83,7 +83,7 @@ type Driver struct {
// Init returns a new AUFS driver.
// An error is returned if AUFS is not supported.
-func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
+func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) {
// Try to load the aufs kernel module
if err := supportsAufs(); err != nil {
@@ -91,7 +91,7 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
}
- fsMagic, err := graphdriver.GetFSMagic(root)
+ fsMagic, err := graphdriver.GetFSMagic(home)
if err != nil {
return nil, err
}
@@ -106,7 +106,7 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
}
var mountOptions string
- for _, option := range options {
+ for _, option := range options.DriverOptions {
key, val, err := parsers.ParseKeyValueOpt(option)
if err != nil {
return nil, err
@@ -126,36 +126,36 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
}
a := &Driver{
- root: root,
- uidMaps: uidMaps,
- gidMaps: gidMaps,
+ root: home,
+ uidMaps: options.UIDMaps,
+ gidMaps: options.GIDMaps,
pathCache: make(map[string]string),
ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicAufs)),
locker: locker.New(),
mountOptions: mountOptions,
}
- rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
+ rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps)
if err != nil {
return nil, err
}
// Create the root aufs driver dir and return
// if it already exists
// If not populate the dir structure
- if err := idtools.MkdirAllAs(root, 0700, rootUID, rootGID); err != nil {
+ if err := idtools.MkdirAllAs(home, 0700, rootUID, rootGID); err != nil {
if os.IsExist(err) {
return a, nil
}
return nil, err
}
- if err := mountpk.MakePrivate(root); err != nil {
+ if err := mountpk.MakePrivate(home); err != nil {
return nil, err
}
// Populate the dir structure
for _, p := range paths {
- if err := idtools.MkdirAllAs(path.Join(root, p), 0700, rootUID, rootGID); err != nil {
+ if err := idtools.MkdirAllAs(path.Join(home, p), 0700, rootUID, rootGID); err != nil {
return nil, err
}
}
@@ -165,7 +165,7 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
})
for _, path := range []string{"mnt", "diff"} {
- p := filepath.Join(root, path)
+ p := filepath.Join(home, path)
entries, err := ioutil.ReadDir(p)
if err != nil {
logger.WithError(err).WithField("dir", p).Error("error reading dir entries")
diff --git a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
index 30254d9fb..6f632a98d 100644
--- a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
+++ b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
@@ -49,7 +49,7 @@ type btrfsOptions struct {
// Init returns a new BTRFS driver.
// An error is returned if BTRFS is not supported.
-func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
+func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) {
fsMagic, err := graphdriver.GetFSMagic(home)
if err != nil {
@@ -60,7 +60,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, errors.Wrapf(graphdriver.ErrPrerequisites, "%q is not on a btrfs filesystem", home)
}
- rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
+ rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps)
if err != nil {
return nil, err
}
@@ -72,15 +72,15 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, err
}
- opt, userDiskQuota, err := parseOptions(options)
+ opt, userDiskQuota, err := parseOptions(options.DriverOptions)
if err != nil {
return nil, err
}
driver := &Driver{
home: home,
- uidMaps: uidMaps,
- gidMaps: gidMaps,
+ uidMaps: options.UIDMaps,
+ gidMaps: options.GIDMaps,
options: opt,
}
diff --git a/vendor/github.com/containers/storage/drivers/devmapper/driver.go b/vendor/github.com/containers/storage/drivers/devmapper/driver.go
index 13677c93a..f384a6242 100644
--- a/vendor/github.com/containers/storage/drivers/devmapper/driver.go
+++ b/vendor/github.com/containers/storage/drivers/devmapper/driver.go
@@ -34,8 +34,8 @@ type Driver struct {
}
// Init creates a driver with the given home and the set of options.
-func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
- deviceSet, err := NewDeviceSet(home, true, options, uidMaps, gidMaps)
+func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) {
+ deviceSet, err := NewDeviceSet(home, true, options.DriverOptions, options.UIDMaps, options.GIDMaps)
if err != nil {
return nil, err
}
@@ -47,8 +47,8 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
d := &Driver{
DeviceSet: deviceSet,
home: home,
- uidMaps: uidMaps,
- gidMaps: gidMaps,
+ uidMaps: options.UIDMaps,
+ gidMaps: options.GIDMaps,
ctr: graphdriver.NewRefCounter(graphdriver.NewDefaultChecker()),
locker: locker.New(),
}
diff --git a/vendor/github.com/containers/storage/drivers/driver.go b/vendor/github.com/containers/storage/drivers/driver.go
index dda172574..ac4775f76 100644
--- a/vendor/github.com/containers/storage/drivers/driver.go
+++ b/vendor/github.com/containers/storage/drivers/driver.go
@@ -53,7 +53,7 @@ type MountOpts struct {
}
// InitFunc initializes the storage driver.
-type InitFunc func(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error)
+type InitFunc func(homedir string, options Options) (Driver, error)
// ProtoDriver defines the basic capabilities of a driver.
// This interface exists solely to be a minimum set of methods
@@ -202,7 +202,7 @@ func Register(name string, initFunc InitFunc) error {
// GetDriver initializes and returns the registered driver
func GetDriver(name string, config Options) (Driver, error) {
if initFunc, exists := drivers[name]; exists {
- return initFunc(filepath.Join(config.Root, name), config.DriverOptions, config.UIDMaps, config.GIDMaps)
+ return initFunc(filepath.Join(config.Root, name), config)
}
logrus.Errorf("Failed to GetDriver graph %s %s", name, config.Root)
@@ -210,9 +210,9 @@ func GetDriver(name string, config Options) (Driver, error) {
}
// getBuiltinDriver initializes and returns the registered driver, but does not try to load from plugins
-func getBuiltinDriver(name, home string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) {
+func getBuiltinDriver(name, home string, options Options) (Driver, error) {
if initFunc, exists := drivers[name]; exists {
- return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps)
+ return initFunc(filepath.Join(home, name), options)
}
logrus.Errorf("Failed to built-in GetDriver graph %s %s", name, home)
return nil, errors.Wrapf(ErrNotSupported, "failed to built-in GetDriver graph %s %s", name, home)
@@ -221,6 +221,7 @@ func getBuiltinDriver(name, home string, options []string, uidMaps, gidMaps []id
// Options is used to initialize a graphdriver
type Options struct {
Root string
+ RunRoot string
DriverOptions []string
UIDMaps []idtools.IDMap
GIDMaps []idtools.IDMap
@@ -244,7 +245,7 @@ func New(name string, config Options) (Driver, error) {
if _, prior := driversMap[name]; prior {
// of the state found from prior drivers, check in order of our priority
// which we would prefer
- driver, err := getBuiltinDriver(name, config.Root, config.DriverOptions, config.UIDMaps, config.GIDMaps)
+ driver, err := getBuiltinDriver(name, config.Root, config)
if err != nil {
// unlike below, we will return error here, because there is prior
// state, and now it is no longer supported/prereq/compatible, so
@@ -272,7 +273,7 @@ func New(name string, config Options) (Driver, error) {
// Check for priority drivers first
for _, name := range priority {
- driver, err := getBuiltinDriver(name, config.Root, config.DriverOptions, config.UIDMaps, config.GIDMaps)
+ driver, err := getBuiltinDriver(name, config.Root, config)
if err != nil {
if isDriverNotSupported(err) {
continue
@@ -284,7 +285,7 @@ func New(name string, config Options) (Driver, error) {
// Check all registered drivers if no priority driver is found
for name, initFunc := range drivers {
- driver, err := initFunc(filepath.Join(config.Root, name), config.DriverOptions, config.UIDMaps, config.GIDMaps)
+ driver, err := initFunc(filepath.Join(config.Root, name), config)
if err != nil {
if isDriverNotSupported(err) {
continue
diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
index 57d6dd63a..262734d31 100644
--- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go
+++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
@@ -97,6 +97,7 @@ type overlayOptions struct {
type Driver struct {
name string
home string
+ runhome string
uidMaps []idtools.IDMap
gidMaps []idtools.IDMap
ctr *graphdriver.RefCounter
@@ -125,8 +126,8 @@ func init() {
// Init returns the a native diff driver for overlay filesystem.
// If overlay filesystem is not supported on the host, a wrapped graphdriver.ErrNotSupported is returned as error.
// If an overlay filesystem is not supported over an existing filesystem then a wrapped graphdriver.ErrIncompatibleFS is returned.
-func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
- opts, err := parseOptions(options)
+func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) {
+ opts, err := parseOptions(options.DriverOptions)
if err != nil {
return nil, err
}
@@ -148,7 +149,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
}
}
- rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
+ rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps)
if err != nil {
return nil, err
}
@@ -157,32 +158,72 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
if err := idtools.MkdirAllAs(path.Join(home, linkDir), 0700, rootUID, rootGID); err != nil && !os.IsExist(err) {
return nil, err
}
+ runhome := filepath.Join(options.RunRoot, filepath.Base(home))
+ if err := idtools.MkdirAllAs(runhome, 0700, rootUID, rootGID); err != nil && !os.IsExist(err) {
+ return nil, err
+ }
var usingMetacopy bool
var supportsDType bool
if opts.mountProgram != "" {
supportsDType = true
} else {
- supportsDType, err = supportsOverlay(home, fsMagic, rootUID, rootGID)
- if err != nil {
- os.Remove(filepath.Join(home, linkDir))
- os.Remove(home)
- patherr, ok := err.(*os.PathError)
- if ok && patherr.Err == syscall.ENOSPC {
+ feature := "overlay"
+ overlayCacheResult, overlayCacheText, err := cachedFeatureCheck(runhome, feature)
+ if err == nil {
+ if overlayCacheResult {
+ logrus.Debugf("cached value indicated that overlay is supported")
+ } else {
+ logrus.Debugf("cached value indicated that overlay is not supported")
+ }
+ supportsDType = overlayCacheResult
+ if !supportsDType {
+ return nil, errors.New(overlayCacheText)
+ }
+ } else {
+ supportsDType, err = supportsOverlay(home, fsMagic, rootUID, rootGID)
+ if err != nil {
+ os.Remove(filepath.Join(home, linkDir))
+ os.Remove(home)
+ patherr, ok := err.(*os.PathError)
+ if ok && patherr.Err == syscall.ENOSPC {
+ return nil, err
+ }
+ err = errors.Wrap(err, "kernel does not support overlay fs")
+ if err2 := cachedFeatureRecord(runhome, feature, false, err.Error()); err2 != nil {
+ return nil, errors.Wrapf(err2, "error recording overlay not being supported (%v)", err)
+ }
return nil, err
}
- return nil, errors.Wrap(err, "kernel does not support overlay fs")
+ if err = cachedFeatureRecord(runhome, feature, supportsDType, ""); err != nil {
+ return nil, errors.Wrap(err, "error recording overlay support status")
+ }
}
- usingMetacopy, err = doesMetacopy(home, opts.mountOptions)
+
+ feature = fmt.Sprintf("metacopy(%s)", opts.mountOptions)
+ metacopyCacheResult, _, err := cachedFeatureCheck(runhome, feature)
if err == nil {
- if usingMetacopy {
- logrus.Debugf("overlay test mount indicated that metacopy is being used")
+ if metacopyCacheResult {
+ logrus.Debugf("cached value indicated that metacopy is being used")
} else {
- logrus.Debugf("overlay test mount indicated that metacopy is not being used")
+ logrus.Debugf("cached value indicated that metacopy is not being used")
}
+ usingMetacopy = metacopyCacheResult
} else {
- logrus.Warnf("overlay test mount did not indicate whether or not metacopy is being used: %v", err)
- return nil, err
+ usingMetacopy, err = doesMetacopy(home, opts.mountOptions)
+ if err == nil {
+ if usingMetacopy {
+ logrus.Debugf("overlay test mount indicated that metacopy is being used")
+ } else {
+ logrus.Debugf("overlay test mount indicated that metacopy is not being used")
+ }
+ if err = cachedFeatureRecord(runhome, feature, usingMetacopy, ""); err != nil {
+ return nil, errors.Wrap(err, "error recording metacopy-being-used status")
+ }
+ } else {
+ logrus.Warnf("overlay test mount did not indicate whether or not metacopy is being used: %v", err)
+ return nil, err
+ }
}
}
@@ -201,8 +242,9 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
d := &Driver{
name: "overlay",
home: home,
- uidMaps: uidMaps,
- gidMaps: gidMaps,
+ runhome: runhome,
+ uidMaps: options.UIDMaps,
+ gidMaps: options.GIDMaps,
ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicOverlay)),
supportsDType: supportsDType,
usingMetacopy: usingMetacopy,
@@ -291,6 +333,36 @@ func parseOptions(options []string) (*overlayOptions, error) {
return o, nil
}
+func cachedFeatureSet(feature string, set bool) string {
+ if set {
+ return fmt.Sprintf("%s-true", feature)
+ }
+ return fmt.Sprintf("%s-false", feature)
+}
+
+func cachedFeatureCheck(runhome, feature string) (supported bool, text string, err error) {
+ content, err := ioutil.ReadFile(filepath.Join(runhome, cachedFeatureSet(feature, true)))
+ if err == nil {
+ return true, string(content), nil
+ }
+ content, err = ioutil.ReadFile(filepath.Join(runhome, cachedFeatureSet(feature, false)))
+ if err == nil {
+ return false, string(content), nil
+ }
+ return false, "", err
+}
+
+func cachedFeatureRecord(runhome, feature string, supported bool, text string) (err error) {
+ f, err := os.Create(filepath.Join(runhome, cachedFeatureSet(feature, supported)))
+ if f != nil {
+ if text != "" {
+ fmt.Fprintf(f, "%s", text)
+ }
+ f.Close()
+ }
+ return err
+}
+
func supportsOverlay(home string, homeMagic graphdriver.FsMagic, rootUID, rootGID int) (supportsDType bool, err error) {
// We can try to modprobe overlay first
@@ -363,10 +435,24 @@ func (d *Driver) useNaiveDiff() bool {
useNaiveDiffOnly = true
return
}
+ feature := fmt.Sprintf("native-diff(%s)", d.options.mountOptions)
+ nativeDiffCacheResult, nativeDiffCacheText, err := cachedFeatureCheck(d.runhome, feature)
+ if err == nil {
+ if nativeDiffCacheResult {
+ logrus.Debugf("cached value indicated that native-diff is usable")
+ } else {
+ logrus.Debugf("cached value indicated that native-diff is not being used")
+ logrus.Warn(nativeDiffCacheText)
+ }
+ useNaiveDiffOnly = !nativeDiffCacheResult
+ return
+ }
if err := doesSupportNativeDiff(d.home, d.options.mountOptions); err != nil {
- logrus.Warnf("Not using native diff for overlay, this may cause degraded performance for building images: %v", err)
+ nativeDiffCacheText = fmt.Sprintf("Not using native diff for overlay, this may cause degraded performance for building images: %v", err)
+ logrus.Warn(nativeDiffCacheText)
useNaiveDiffOnly = true
}
+ cachedFeatureRecord(d.runhome, feature, !useNaiveDiffOnly, nativeDiffCacheText)
})
return useNaiveDiffOnly
}
diff --git a/vendor/github.com/containers/storage/drivers/vfs/driver.go b/vendor/github.com/containers/storage/drivers/vfs/driver.go
index 5941ccc17..8b981632a 100644
--- a/vendor/github.com/containers/storage/drivers/vfs/driver.go
+++ b/vendor/github.com/containers/storage/drivers/vfs/driver.go
@@ -24,16 +24,16 @@ func init() {
// Init returns a new VFS driver.
// This sets the home directory for the driver and returns NaiveDiffDriver.
-func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
+func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) {
d := &Driver{
homes: []string{home},
- idMappings: idtools.NewIDMappingsFromMaps(uidMaps, gidMaps),
+ idMappings: idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps),
}
rootIDs := d.idMappings.RootPair()
if err := idtools.MkdirAllAndChown(home, 0700, rootIDs); err != nil {
return nil, err
}
- for _, option := range options {
+ for _, option := range options.DriverOptions {
if strings.HasPrefix(option, "vfs.imagestore=") {
d.homes = append(d.homes, strings.Split(option[15:], ",")...)
continue
@@ -59,7 +59,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
}
}
if d.ostreeRepo != "" {
- rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
+ rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/containers/storage/drivers/windows/windows.go b/vendor/github.com/containers/storage/drivers/windows/windows.go
index c7df1c1fe..f0437a275 100644
--- a/vendor/github.com/containers/storage/drivers/windows/windows.go
+++ b/vendor/github.com/containers/storage/drivers/windows/windows.go
@@ -83,10 +83,10 @@ type Driver struct {
}
// InitFilter returns a new Windows storage filter driver.
-func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
+func InitFilter(home string, options graphdriver.Options) (graphdriver.Driver, error) {
logrus.Debugf("WindowsGraphDriver InitFilter at %s", home)
- for _, option := range options {
+ for _, option := range options.DriverOptions {
if strings.HasPrefix(option, "windows.mountopt=") {
return nil, fmt.Errorf("windows driver does not support mount options")
} else {
diff --git a/vendor/github.com/containers/storage/drivers/zfs/zfs.go b/vendor/github.com/containers/storage/drivers/zfs/zfs.go
index eaa9e8bc5..a2bf5565b 100644
--- a/vendor/github.com/containers/storage/drivers/zfs/zfs.go
+++ b/vendor/github.com/containers/storage/drivers/zfs/zfs.go
@@ -44,7 +44,7 @@ func (*Logger) Log(cmd []string) {
// Init returns a new ZFS driver.
// It takes base mount path and an array of options which are represented as key value pairs.
// Each option is in the for key=value. 'zfs.fsname' is expected to be a valid key in the options.
-func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
+func Init(base string, opt graphdriver.Options) (graphdriver.Driver, error) {
var err error
logger := logrus.WithField("storage-driver", "zfs")
@@ -61,7 +61,7 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri
}
defer file.Close()
- options, err := parseOptions(opt)
+ options, err := parseOptions(opt.DriverOptions)
if err != nil {
return nil, err
}
@@ -103,7 +103,7 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri
return nil, fmt.Errorf("BUG: zfs get all -t filesystem -rHp '%s' should contain '%s'", options.fsName, options.fsName)
}
- rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
+ rootUID, rootGID, err := idtools.GetRootUIDGID(opt.UIDMaps, opt.GIDMaps)
if err != nil {
return nil, fmt.Errorf("Failed to get root uid/guid: %v", err)
}
@@ -115,8 +115,8 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri
dataset: rootDataset,
options: options,
filesystemsCache: filesystemsCache,
- uidMaps: uidMaps,
- gidMaps: gidMaps,
+ uidMaps: opt.UIDMaps,
+ gidMaps: opt.GIDMaps,
ctr: graphdriver.NewRefCounter(graphdriver.NewDefaultChecker()),
}
return graphdriver.NewNaiveDiffDriver(d, graphdriver.NewNaiveLayerIDMapUpdater(d)), nil
diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go
index 856c73e51..acc22be27 100644
--- a/vendor/github.com/containers/storage/store.go
+++ b/vendor/github.com/containers/storage/store.go
@@ -695,6 +695,7 @@ func (s *store) getGraphDriver() (drivers.Driver, error) {
}
config := drivers.Options{
Root: s.graphRoot,
+ RunRoot: s.runRoot,
DriverOptions: s.graphOptions,
UIDMaps: s.uidMap,
GIDMaps: s.gidMap,