diff options
Diffstat (limited to 'vendor/github.com')
36 files changed, 981 insertions, 243 deletions
diff --git a/vendor/github.com/containers/storage/containers_ffjson.go b/vendor/github.com/containers/storage/containers_ffjson.go index aef6becfe..40b912bb3 100644 --- a/vendor/github.com/containers/storage/containers_ffjson.go +++ b/vendor/github.com/containers/storage/containers_ffjson.go @@ -1,5 +1,5 @@ // Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT. -// source: containers.go +// source: ./containers.go package storage diff --git a/vendor/github.com/containers/storage/drivers/aufs/aufs.go b/vendor/github.com/containers/storage/drivers/aufs/aufs.go index ca69816be..e821bc0c5 100644 --- a/vendor/github.com/containers/storage/drivers/aufs/aufs.go +++ b/vendor/github.com/containers/storage/drivers/aufs/aufs.go @@ -253,6 +253,11 @@ func (a *Driver) AdditionalImageStores() []string { return nil } +// CreateFromTemplate creates a layer with the same contents and parent as another layer. +func (a *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error { + return graphdriver.NaiveCreateFromTemplate(a, id, template, templateIDMappings, parent, parentIDMappings, opts, readWrite) +} + // CreateReadWrite creates a layer that is writable for use as a container // file system. func (a *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { diff --git a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go index 567cda9d3..30254d9fb 100644 --- a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go +++ b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go @@ -490,6 +490,11 @@ func (d *Driver) quotasDirID(id string) string { return path.Join(d.quotasDir(), id) } +// CreateFromTemplate creates a layer with the same contents and parent as another layer. +func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error { + return d.Create(id, template, opts) +} + // CreateReadWrite creates a layer that is writable for use as a container // file system. func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { diff --git a/vendor/github.com/containers/storage/drivers/devmapper/driver.go b/vendor/github.com/containers/storage/drivers/devmapper/driver.go index 39a4fbe2c..13677c93a 100644 --- a/vendor/github.com/containers/storage/drivers/devmapper/driver.go +++ b/vendor/github.com/containers/storage/drivers/devmapper/driver.go @@ -123,6 +123,11 @@ func (d *Driver) Cleanup() error { return err } +// CreateFromTemplate creates a layer with the same contents and parent as another layer. +func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error { + return d.Create(id, template, opts) +} + // CreateReadWrite creates a layer that is writable for use as a container // file system. func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { diff --git a/vendor/github.com/containers/storage/drivers/driver.go b/vendor/github.com/containers/storage/drivers/driver.go index 476b55160..dda172574 100644 --- a/vendor/github.com/containers/storage/drivers/driver.go +++ b/vendor/github.com/containers/storage/drivers/driver.go @@ -72,6 +72,9 @@ type ProtoDriver interface { // specified id and parent and options passed in opts. Parent // may be "" and opts may be nil. Create(id, parent string, opts *CreateOpts) error + // CreateFromTemplate creates a new filesystem layer with the specified id + // and parent, with contents identical to the specified template layer. + CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *CreateOpts, readWrite bool) error // Remove attempts to remove the filesystem layer with this id. Remove(id string) error // Get returns the mountpoint for the layered filesystem referred diff --git a/vendor/github.com/containers/storage/drivers/overlay/check.go b/vendor/github.com/containers/storage/drivers/overlay/check.go index 590d517fa..a566e4afd 100644 --- a/vendor/github.com/containers/storage/drivers/overlay/check.go +++ b/vendor/github.com/containers/storage/drivers/overlay/check.go @@ -10,6 +10,8 @@ import ( "path/filepath" "syscall" + "github.com/containers/storage/pkg/ioutils" + "github.com/containers/storage/pkg/mount" "github.com/containers/storage/pkg/system" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -57,10 +59,11 @@ func doesSupportNativeDiff(d, mountOpts string) error { } opts := fmt.Sprintf("lowerdir=%s:%s,upperdir=%s,workdir=%s", path.Join(td, "l2"), path.Join(td, "l1"), path.Join(td, "l3"), path.Join(td, "work")) - if mountOpts != "" { - opts = fmt.Sprintf("%s,%s", opts, mountOpts) + flags, data := mount.ParseOptions(mountOpts) + if data != "" { + opts = fmt.Sprintf("%s,%s", opts, data) } - if err := unix.Mount("overlay", filepath.Join(td, "merged"), "overlay", 0, opts); err != nil { + if err := unix.Mount("overlay", filepath.Join(td, "merged"), "overlay", uintptr(flags), opts); err != nil { return errors.Wrap(err, "failed to mount overlay") } defer func() { @@ -103,3 +106,60 @@ func doesSupportNativeDiff(d, mountOpts string) error { return nil } + +// doesMetacopy checks if the filesystem is going to optimize changes to +// metadata by using nodes marked with an "overlay.metacopy" attribute to avoid +// copying up a file from a lower layer unless/until its contents are being +// modified +func doesMetacopy(d, mountOpts string) (bool, error) { + td, err := ioutil.TempDir(d, "metacopy-check") + if err != nil { + return false, err + } + defer func() { + if err := os.RemoveAll(td); err != nil { + logrus.Warnf("Failed to remove check directory %v: %v", td, err) + } + }() + + // Make directories l1, l2, work, merged + if err := os.MkdirAll(filepath.Join(td, "l1"), 0755); err != nil { + return false, err + } + if err := ioutils.AtomicWriteFile(filepath.Join(td, "l1", "f"), []byte{0xff}, 0700); err != nil { + return false, err + } + if err := os.MkdirAll(filepath.Join(td, "l2"), 0755); err != nil { + return false, err + } + if err := os.Mkdir(filepath.Join(td, "work"), 0755); err != nil { + return false, err + } + if err := os.Mkdir(filepath.Join(td, "merged"), 0755); err != nil { + return false, err + } + // Mount using the mandatory options and configured options + opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", path.Join(td, "l1"), path.Join(td, "l2"), path.Join(td, "work")) + flags, data := mount.ParseOptions(mountOpts) + if data != "" { + opts = fmt.Sprintf("%s,%s", opts, data) + } + if err := unix.Mount("overlay", filepath.Join(td, "merged"), "overlay", uintptr(flags), opts); err != nil { + return false, errors.Wrap(err, "failed to mount overlay for metacopy check") + } + defer func() { + if err := unix.Unmount(filepath.Join(td, "merged"), 0); err != nil { + logrus.Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err) + } + }() + // Make a change that only impacts the inode, and check if the pulled-up copy is marked + // as a metadata-only copy + if err := os.Chmod(filepath.Join(td, "merged", "f"), 0600); err != nil { + return false, errors.Wrap(err, "error changing permissions on file for metacopy check") + } + metacopy, err := system.Lgetxattr(filepath.Join(td, "l2", "f"), "trusted.overlay.metacopy") + if err != nil { + return false, errors.Wrap(err, "metacopy flag was not set on file in upper layer") + } + return metacopy != nil, nil +} diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go index 2455b6736..57d6dd63a 100644 --- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go +++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go @@ -85,13 +85,12 @@ const ( ) type overlayOptions struct { - overrideKernelCheck bool - imageStores []string - quota quota.Quota - mountProgram string - ostreeRepo string - skipMountHome bool - mountOptions string + imageStores []string + quota quota.Quota + mountProgram string + ostreeRepo string + skipMountHome bool + mountOptions string } // Driver contains information about the home directory and the list of active mounts that are created using this driver. @@ -105,6 +104,7 @@ type Driver struct { options overlayOptions naiveDiff graphdriver.DiffDriver supportsDType bool + usingMetacopy bool locker *locker.Locker convert map[string]bool } @@ -158,6 +158,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap return nil, err } + var usingMetacopy bool var supportsDType bool if opts.mountProgram != "" { supportsDType = true @@ -172,6 +173,17 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap } return nil, errors.Wrap(err, "kernel does not support overlay fs") } + 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") + } + } else { + logrus.Warnf("overlay test mount did not indicate whether or not metacopy is being used: %v", err) + return nil, err + } } if !opts.skipMountHome { @@ -193,6 +205,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap gidMaps: gidMaps, ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicOverlay)), supportsDType: supportsDType, + usingMetacopy: usingMetacopy, locker: locker.New(), options: *opts, convert: make(map[string]bool), @@ -212,7 +225,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap return nil, fmt.Errorf("Storage option overlay.size only supported for backingFS XFS. Found %v", backingFs) } - logrus.Debugf("backingFs=%s, projectQuotaSupported=%v, useNativeDiff=%v", backingFs, projectQuotaSupported, !d.useNaiveDiff()) + logrus.Debugf("backingFs=%s, projectQuotaSupported=%v, useNativeDiff=%v, usingMetacopy=%v", backingFs, projectQuotaSupported, !d.useNaiveDiff(), d.usingMetacopy) return d, nil } @@ -226,12 +239,6 @@ func parseOptions(options []string) (*overlayOptions, error) { } key = strings.ToLower(key) switch key { - case ".override_kernel_check", "overlay.override_kernel_check", "overlay2.override_kernel_check": - logrus.Debugf("overlay: override_kernelcheck=%s", val) - o.overrideKernelCheck, err = strconv.ParseBool(val) - if err != nil { - return nil, err - } case ".mountopt", "overlay.mountopt", "overlay2.mountopt": o.mountOptions = val case ".size", "overlay.size", "overlay2.size": @@ -375,6 +382,7 @@ func (d *Driver) Status() [][2]string { {"Backing Filesystem", backingFs}, {"Supports d_type", strconv.FormatBool(d.supportsDType)}, {"Native Overlay Diff", strconv.FormatBool(!d.useNaiveDiff())}, + {"Using metacopy", strconv.FormatBool(d.usingMetacopy)}, } } @@ -410,6 +418,14 @@ func (d *Driver) Cleanup() error { return mount.Unmount(d.home) } +// CreateFromTemplate creates a layer with the same contents and parent as another layer. +func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error { + if readWrite { + return d.CreateReadWrite(id, template, opts) + } + return d.Create(id, template, opts) +} + // CreateReadWrite creates a layer that is writable for use as a container // file system. func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { @@ -793,6 +809,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO mountTarget = path.Join(id, "merged") } flags, data := mount.ParseOptions(mountData) + logrus.Debugf("overlay: mount_data=%s", mountData) if err := mountFunc("overlay", mountTarget, "overlay", uintptr(flags), data); err != nil { return "", fmt.Errorf("error creating overlay mount to %s: %v", mountTarget, err) } @@ -986,6 +1003,7 @@ func (d *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMapp // Mount the new layer and handle ownership changes and possible copy_ups in it. options := graphdriver.MountOpts{ MountLabel: mountLabel, + Options: strings.Split(d.options.mountOptions, ","), } layerFs, err := d.get(id, true, options) if err != nil { diff --git a/vendor/github.com/containers/storage/drivers/template.go b/vendor/github.com/containers/storage/drivers/template.go new file mode 100644 index 000000000..dfcbffb83 --- /dev/null +++ b/vendor/github.com/containers/storage/drivers/template.go @@ -0,0 +1,45 @@ +package graphdriver + +import ( + "github.com/sirupsen/logrus" + + "github.com/containers/storage/pkg/idtools" +) + +// TemplateDriver is just barely enough of a driver that we can implement a +// naive version of CreateFromTemplate on top of it. +type TemplateDriver interface { + DiffDriver + CreateReadWrite(id, parent string, opts *CreateOpts) error + Create(id, parent string, opts *CreateOpts) error + Remove(id string) error +} + +// CreateFromTemplate creates a layer with the same contents and parent as +// another layer. Internally, it may even depend on that other layer +// continuing to exist, as if it were actually a child of the child layer. +func NaiveCreateFromTemplate(d TemplateDriver, id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *CreateOpts, readWrite bool) error { + var err error + if readWrite { + err = d.CreateReadWrite(id, parent, opts) + } else { + err = d.Create(id, parent, opts) + } + if err != nil { + return err + } + diff, err := d.Diff(template, templateIDMappings, parent, parentIDMappings, opts.MountLabel) + if err != nil { + if err2 := d.Remove(id); err2 != nil { + logrus.Errorf("error removing layer %q: %v", id, err2) + } + return err + } + if _, err = d.ApplyDiff(id, templateIDMappings, parent, opts.MountLabel, diff); err != nil { + if err2 := d.Remove(id); err2 != nil { + logrus.Errorf("error removing layer %q: %v", id, err2) + } + return err + } + return nil +} diff --git a/vendor/github.com/containers/storage/drivers/vfs/driver.go b/vendor/github.com/containers/storage/drivers/vfs/driver.go index f7f3c75ba..5941ccc17 100644 --- a/vendor/github.com/containers/storage/drivers/vfs/driver.go +++ b/vendor/github.com/containers/storage/drivers/vfs/driver.go @@ -99,6 +99,14 @@ func (d *Driver) Cleanup() error { return nil } +// CreateFromTemplate creates a layer with the same contents and parent as another layer. +func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error { + if readWrite { + return d.CreateReadWrite(id, template, opts) + } + return d.Create(id, template, opts) +} + // CreateReadWrite creates a layer that is writable for use as a container // file system. func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { diff --git a/vendor/github.com/containers/storage/drivers/windows/windows.go b/vendor/github.com/containers/storage/drivers/windows/windows.go index c6d86a4ab..c7df1c1fe 100644 --- a/vendor/github.com/containers/storage/drivers/windows/windows.go +++ b/vendor/github.com/containers/storage/drivers/windows/windows.go @@ -185,6 +185,11 @@ func (d *Driver) Exists(id string) bool { return result } +// CreateFromTemplate creates a layer with the same contents and parent as another layer. +func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error { + return graphdriver.NaiveCreateFromTemplate(d, id, template, templateIDMappings, parent, parentIDMappings, opts, readWrite) +} + // CreateReadWrite creates a layer that is writable for use as a container // file system. func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { diff --git a/vendor/github.com/containers/storage/drivers/zfs/zfs.go b/vendor/github.com/containers/storage/drivers/zfs/zfs.go index c3ce6e869..eaa9e8bc5 100644 --- a/vendor/github.com/containers/storage/drivers/zfs/zfs.go +++ b/vendor/github.com/containers/storage/drivers/zfs/zfs.go @@ -1,4 +1,4 @@ -// +build linux freebsd solaris +// +build linux freebsd package zfs @@ -16,7 +16,7 @@ import ( "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/mount" "github.com/containers/storage/pkg/parsers" - zfs "github.com/mistifyio/go-zfs" + "github.com/mistifyio/go-zfs" "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -38,7 +38,7 @@ type Logger struct{} // Log wraps log message from ZFS driver with a prefix '[zfs]'. func (*Logger) Log(cmd []string) { - logrus.Debugf("[zfs] %s", strings.Join(cmd, " ")) + logrus.WithField("storage-driver", "zfs").Debugf("%s", strings.Join(cmd, " ")) } // Init returns a new ZFS driver. @@ -47,14 +47,16 @@ func (*Logger) Log(cmd []string) { func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { var err error + logger := logrus.WithField("storage-driver", "zfs") + if _, err := exec.LookPath("zfs"); err != nil { - logrus.Debugf("[zfs] zfs command is not available: %v", err) + logger.Debugf("zfs command is not available: %v", err) return nil, errors.Wrap(graphdriver.ErrPrerequisites, "the 'zfs' command is not available") } file, err := os.OpenFile("/dev/zfs", os.O_RDWR, 0600) if err != nil { - logrus.Debugf("[zfs] cannot open /dev/zfs: %v", err) + logger.Debugf("cannot open /dev/zfs: %v", err) return nil, errors.Wrapf(graphdriver.ErrPrerequisites, "could not open /dev/zfs: %v", err) } defer file.Close() @@ -109,9 +111,6 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri return nil, fmt.Errorf("Failed to create '%s': %v", base, err) } - if err := mount.MakePrivate(base); err != nil { - return nil, err - } d := &Driver{ dataset: rootDataset, options: options, @@ -157,7 +156,7 @@ func lookupZfsDataset(rootdir string) (string, error) { } for _, m := range mounts { if err := unix.Stat(m.Mountpoint, &stat); err != nil { - logrus.Debugf("[zfs] failed to stat '%s' while scanning for zfs mount: %v", m.Mountpoint, err) + logrus.WithField("storage-driver", "zfs").Debugf("failed to stat '%s' while scanning for zfs mount: %v", m.Mountpoint, err) continue // may fail on fuse file systems } @@ -184,7 +183,7 @@ func (d *Driver) String() string { return "zfs" } -// Cleanup is used to implement graphdriver.ProtoDriver. There is no cleanup required for this driver. +// Cleanup is called on when program exits, it is a no-op for ZFS. func (d *Driver) Cleanup() error { return nil } @@ -260,6 +259,11 @@ func (d *Driver) mountPath(id string) string { return path.Join(d.options.mountPath, "graph", getMountpoint(id)) } +// CreateFromTemplate creates a layer with the same contents and parent as another layer. +func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error { + return d.Create(id, template, opts) +} + // CreateReadWrite creates a layer that is writable for use as a container // file system. func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { @@ -360,11 +364,25 @@ func (d *Driver) Remove(id string) error { } // Get returns the mountpoint for the given id after creating the target directories if necessary. -func (d *Driver) Get(id string, options graphdriver.MountOpts) (string, error) { +func (d *Driver) Get(id string, options graphdriver.MountOpts) (_ string, retErr error) { + mountpoint := d.mountPath(id) if count := d.ctr.Increment(mountpoint); count > 1 { return mountpoint, nil } + defer func() { + if retErr != nil { + if c := d.ctr.Decrement(mountpoint); c <= 0 { + if mntErr := unix.Unmount(mountpoint, 0); mntErr != nil { + logrus.WithField("storage-driver", "zfs").Errorf("Error unmounting %v: %v", mountpoint, mntErr) + } + if rmErr := unix.Rmdir(mountpoint); rmErr != nil && !os.IsNotExist(rmErr) { + logrus.WithField("storage-driver", "zfs").Debugf("Failed to remove %s: %v", id, rmErr) + } + + } + } + }() mountOptions := d.options.mountOptions if len(options.Options) > 0 { @@ -373,29 +391,24 @@ func (d *Driver) Get(id string, options graphdriver.MountOpts) (string, error) { filesystem := d.zfsPath(id) opts := label.FormatMountLabel(mountOptions, options.MountLabel) - logrus.Debugf(`[zfs] mount("%s", "%s", "%s")`, filesystem, mountpoint, opts) + logrus.WithField("storage-driver", "zfs").Debugf(`mount("%s", "%s", "%s")`, filesystem, mountpoint, opts) rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) if err != nil { - d.ctr.Decrement(mountpoint) return "", err } // Create the target directories if they don't exist if err := idtools.MkdirAllAs(mountpoint, 0755, rootUID, rootGID); err != nil { - d.ctr.Decrement(mountpoint) return "", err } if err := mount.Mount(filesystem, mountpoint, "zfs", opts); err != nil { - d.ctr.Decrement(mountpoint) - return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err) + return "", errors.Wrap(err, "error creating zfs mount") } // this could be our first mount after creation of the filesystem, and the root dir may still have root // permissions instead of the remapped root uid:gid (if user namespaces are enabled): if err := os.Chown(mountpoint, rootUID, rootGID); err != nil { - mount.Unmount(mountpoint) - d.ctr.Decrement(mountpoint) return "", fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err) } @@ -408,16 +421,18 @@ func (d *Driver) Put(id string) error { if count := d.ctr.Decrement(mountpoint); count > 0 { return nil } - mounted, err := graphdriver.Mounted(graphdriver.FsMagicZfs, mountpoint) - if err != nil || !mounted { - return err - } - logrus.Debugf(`[zfs] unmount("%s")`, mountpoint) + logger := logrus.WithField("storage-driver", "zfs") - if err := mount.Unmount(mountpoint); err != nil { - return fmt.Errorf("error unmounting to %s: %v", mountpoint, err) + logger.Debugf(`unmount("%s")`, mountpoint) + + if err := unix.Unmount(mountpoint, unix.MNT_DETACH); err != nil { + logger.Warnf("Failed to unmount %s mount %s: %v", id, mountpoint, err) + } + if err := unix.Rmdir(mountpoint); err != nil && !os.IsNotExist(err) { + logger.Debugf("Failed to remove %s mount point %s: %v", id, mountpoint, err) } + return nil } diff --git a/vendor/github.com/containers/storage/drivers/zfs/zfs_freebsd.go b/vendor/github.com/containers/storage/drivers/zfs/zfs_freebsd.go index 69c0448d3..bf6905159 100644 --- a/vendor/github.com/containers/storage/drivers/zfs/zfs_freebsd.go +++ b/vendor/github.com/containers/storage/drivers/zfs/zfs_freebsd.go @@ -18,7 +18,7 @@ func checkRootdirFs(rootdir string) error { // on FreeBSD buf.Fstypename contains ['z', 'f', 's', 0 ... ] if (buf.Fstypename[0] != 122) || (buf.Fstypename[1] != 102) || (buf.Fstypename[2] != 115) || (buf.Fstypename[3] != 0) { - logrus.Debugf("[zfs] no zfs dataset found for rootdir '%s'", rootdir) + logrus.WithField("storage-driver", "zfs").Debugf("no zfs dataset found for rootdir '%s'", rootdir) return errors.Wrapf(graphdriver.ErrPrerequisites, "no zfs dataset found for rootdir '%s'", rootdir) } diff --git a/vendor/github.com/containers/storage/drivers/zfs/zfs_linux.go b/vendor/github.com/containers/storage/drivers/zfs/zfs_linux.go index da298047d..fb1ef3a3d 100644 --- a/vendor/github.com/containers/storage/drivers/zfs/zfs_linux.go +++ b/vendor/github.com/containers/storage/drivers/zfs/zfs_linux.go @@ -1,23 +1,24 @@ package zfs import ( - "fmt" - "github.com/containers/storage/drivers" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" ) -func checkRootdirFs(rootdir string) error { - var buf unix.Statfs_t - if err := unix.Statfs(rootdir, &buf); err != nil { - return fmt.Errorf("Failed to access '%s': %s", rootdir, err) +func checkRootdirFs(rootDir string) error { + fsMagic, err := graphdriver.GetFSMagic(rootDir) + if err != nil { + return err + } + backingFS := "unknown" + if fsName, ok := graphdriver.FsNames[fsMagic]; ok { + backingFS = fsName } - if graphdriver.FsMagic(buf.Type) != graphdriver.FsMagicZfs { - logrus.Debugf("[zfs] no zfs dataset found for rootdir '%s'", rootdir) - return errors.Wrapf(graphdriver.ErrPrerequisites, "no zfs dataset found for rootdir '%s'", rootdir) + if fsMagic != graphdriver.FsMagicZfs { + logrus.WithField("root", rootDir).WithField("backingFS", backingFS).WithField("storage-driver", "zfs").Error("No zfs dataset found for root") + return errors.Wrapf(graphdriver.ErrPrerequisites, "no zfs dataset found for rootdir '%s'", rootDir) } return nil diff --git a/vendor/github.com/containers/storage/drivers/zfs/zfs_solaris.go b/vendor/github.com/containers/storage/drivers/zfs/zfs_solaris.go deleted file mode 100644 index 2383bf3bf..000000000 --- a/vendor/github.com/containers/storage/drivers/zfs/zfs_solaris.go +++ /dev/null @@ -1,59 +0,0 @@ -// +build solaris,cgo - -package zfs - -/* -#include <sys/statvfs.h> -#include <stdlib.h> - -static inline struct statvfs *getstatfs(char *s) { - struct statvfs *buf; - int err; - buf = (struct statvfs *)malloc(sizeof(struct statvfs)); - err = statvfs(s, buf); - return buf; -} -*/ -import "C" -import ( - "path/filepath" - "strings" - "unsafe" - - "github.com/containers/storage/drivers" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -func checkRootdirFs(rootdir string) error { - - cs := C.CString(filepath.Dir(rootdir)) - defer C.free(unsafe.Pointer(cs)) - buf := C.getstatfs(cs) - defer C.free(unsafe.Pointer(buf)) - - // on Solaris buf.f_basetype contains ['z', 'f', 's', 0 ... ] - if (buf.f_basetype[0] != 122) || (buf.f_basetype[1] != 102) || (buf.f_basetype[2] != 115) || - (buf.f_basetype[3] != 0) { - logrus.Debugf("[zfs] no zfs dataset found for rootdir '%s'", rootdir) - return errors.Wrapf(graphdriver.ErrPrerequisites, "no zfs dataset found for rootdir '%s'", rootdir) - } - - return nil -} - -/* rootfs is introduced to comply with the OCI spec -which states that root filesystem must be mounted at <CID>/rootfs/ instead of <CID>/ -*/ -func getMountpoint(id string) string { - maxlen := 12 - - // we need to preserve filesystem suffix - suffix := strings.SplitN(id, "-", 2) - - if len(suffix) > 1 { - return filepath.Join(id[:maxlen]+"-"+suffix[1], "rootfs", "root") - } - - return filepath.Join(id[:maxlen], "rootfs", "root") -} diff --git a/vendor/github.com/containers/storage/drivers/zfs/zfs_unsupported.go b/vendor/github.com/containers/storage/drivers/zfs/zfs_unsupported.go index ce8daadaf..643b169bc 100644 --- a/vendor/github.com/containers/storage/drivers/zfs/zfs_unsupported.go +++ b/vendor/github.com/containers/storage/drivers/zfs/zfs_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!freebsd,!solaris +// +build !linux,!freebsd package zfs diff --git a/vendor/github.com/containers/storage/images.go b/vendor/github.com/containers/storage/images.go index b10501b08..d99842534 100644 --- a/vendor/github.com/containers/storage/images.go +++ b/vendor/github.com/containers/storage/images.go @@ -42,7 +42,9 @@ type Image struct { // MappedTopLayers are the IDs of alternate versions of the top layer // which have the same contents and parent, and which differ from - // TopLayer only in which ID mappings they use. + // TopLayer only in which ID mappings they use. When the image is + // to be removed, they should be removed before the TopLayer, as the + // graph driver may depend on that. MappedTopLayers []string `json:"mapped-layers,omitempty"` // Metadata is data we keep for the convenience of the caller. It is not diff --git a/vendor/github.com/containers/storage/images_ffjson.go b/vendor/github.com/containers/storage/images_ffjson.go index 6b40ebd59..539acfe93 100644 --- a/vendor/github.com/containers/storage/images_ffjson.go +++ b/vendor/github.com/containers/storage/images_ffjson.go @@ -1,5 +1,5 @@ // Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT. -// source: images.go +// source: ./images.go package storage diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go index 299d2f818..cdc3cbba9 100644 --- a/vendor/github.com/containers/storage/layers.go +++ b/vendor/github.com/containers/storage/layers.go @@ -551,9 +551,20 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab } } parent := "" - var parentMappings *idtools.IDMappings if parentLayer != nil { parent = parentLayer.ID + } + var parentMappings, templateIDMappings, oldMappings *idtools.IDMappings + if moreOptions.TemplateLayer != "" { + templateLayer, ok := r.lookup(moreOptions.TemplateLayer) + if !ok { + return nil, -1, ErrLayerUnknown + } + templateIDMappings = idtools.NewIDMappingsFromMaps(templateLayer.UIDMap, templateLayer.GIDMap) + } else { + templateIDMappings = &idtools.IDMappings{} + } + if parentLayer != nil { parentMappings = idtools.NewIDMappingsFromMaps(parentLayer.UIDMap, parentLayer.GIDMap) } else { parentMappings = &idtools.IDMappings{} @@ -566,23 +577,34 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab MountLabel: mountLabel, StorageOpt: options, } - if writeable { - if err = r.driver.CreateReadWrite(id, parent, &opts); err != nil { + if moreOptions.TemplateLayer != "" { + if err = r.driver.CreateFromTemplate(id, moreOptions.TemplateLayer, templateIDMappings, parent, parentMappings, &opts, writeable); err != nil { if id != "" { - return nil, -1, errors.Wrapf(err, "error creating read-write layer with ID %q", id) + return nil, -1, errors.Wrapf(err, "error creating copy of template layer %q with ID %q", moreOptions.TemplateLayer, id) } - return nil, -1, errors.Wrapf(err, "error creating read-write layer") + return nil, -1, errors.Wrapf(err, "error creating copy of template layer %q", moreOptions.TemplateLayer) } + oldMappings = templateIDMappings } else { - if err = r.driver.Create(id, parent, &opts); err != nil { - if id != "" { - return nil, -1, errors.Wrapf(err, "error creating layer with ID %q", id) + if writeable { + if err = r.driver.CreateReadWrite(id, parent, &opts); err != nil { + if id != "" { + return nil, -1, errors.Wrapf(err, "error creating read-write layer with ID %q", id) + } + return nil, -1, errors.Wrapf(err, "error creating read-write layer") + } + } else { + if err = r.driver.Create(id, parent, &opts); err != nil { + if id != "" { + return nil, -1, errors.Wrapf(err, "error creating layer with ID %q", id) + } + return nil, -1, errors.Wrapf(err, "error creating layer") } - return nil, -1, errors.Wrapf(err, "error creating layer") } + oldMappings = parentMappings } - if !reflect.DeepEqual(parentMappings.UIDs(), idMappings.UIDs()) || !reflect.DeepEqual(parentMappings.GIDs(), idMappings.GIDs()) { - if err = r.driver.UpdateLayerIDMap(id, parentMappings, idMappings, mountLabel); err != nil { + if !reflect.DeepEqual(oldMappings.UIDs(), idMappings.UIDs()) || !reflect.DeepEqual(oldMappings.GIDs(), idMappings.GIDs()) { + if err = r.driver.UpdateLayerIDMap(id, oldMappings, idMappings, mountLabel); err != nil { // We don't have a record of this layer, but at least // try to clean it up underneath us. r.driver.Remove(id) diff --git a/vendor/github.com/containers/storage/layers_ffjson.go b/vendor/github.com/containers/storage/layers_ffjson.go index 125b5d8c9..09b5d0f33 100644 --- a/vendor/github.com/containers/storage/layers_ffjson.go +++ b/vendor/github.com/containers/storage/layers_ffjson.go @@ -1,5 +1,5 @@ // Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT. -// source: layers.go +// source: ./layers.go package storage diff --git a/vendor/github.com/containers/storage/pkg/archive/example_changes.go b/vendor/github.com/containers/storage/pkg/archive/example_changes.go new file mode 100644 index 000000000..70f9c5564 --- /dev/null +++ b/vendor/github.com/containers/storage/pkg/archive/example_changes.go @@ -0,0 +1,97 @@ +// +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/store.go b/vendor/github.com/containers/storage/store.go index 5877c3b06..3fe305cc1 100644 --- a/vendor/github.com/containers/storage/store.go +++ b/vendor/github.com/containers/storage/store.go @@ -482,6 +482,10 @@ type LayerOptions struct { // inherit settings from its parent layer or, if it has no parent // layer, the Store object. IDMappingOptions + // TemplateLayer is the ID of a layer whose contents will be used to + // initialize this layer. If set, it should be a child of the layer + // which we want to use as the parent of the new layer. + TemplateLayer string } // ImageOptions is used for passing options to a Store's CreateImage() method. @@ -973,7 +977,7 @@ func (s *store) CreateImage(id string, names []string, layer, metadata string, o return ristore.Create(id, names, layer, metadata, creationDate, options.Digest) } -func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, readWrite bool, rlstore LayerStore, lstores []ROLayerStore, options IDMappingOptions) (*Layer, error) { +func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, createMappedLayer bool, rlstore LayerStore, lstores []ROLayerStore, options IDMappingOptions) (*Layer, error) { layerMatchesMappingOptions := func(layer *Layer, options IDMappingOptions) bool { // If the driver supports shifting and the layer has no mappings, we can use it. if s.graphDriver.SupportsShifting() && len(layer.UIDMap) == 0 && len(layer.GIDMap) == 0 { @@ -994,7 +998,6 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, read return reflect.DeepEqual(layer.UIDMap, options.UIDMap) && reflect.DeepEqual(layer.GIDMap, options.GIDMap) } var layer, parentLayer *Layer - var layerHomeStore ROLayerStore // Locate the image's top layer and its parent, if it has one. for _, store := range append([]ROLayerStore{rlstore}, lstores...) { if store != rlstore { @@ -1027,7 +1030,6 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, read if layer == nil { layer = cLayer parentLayer = cParentLayer - layerHomeStore = store } } } @@ -1037,27 +1039,25 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, read } // The top layer's mappings don't match the ones we want, but it's in a read-only // image store, so we can't create and add a mapped copy of the layer to the image. - if !readWrite { + // We'll have to do the mapping for the container itself, elsewhere. + if !createMappedLayer { return layer, nil } // The top layer's mappings don't match the ones we want, and it's in an image store // that lets us edit image metadata... if istore, ok := ristore.(*imageStore); ok { - // ... so extract the layer's contents, create a new copy of it with the - // desired mappings, and register it as an alternate top layer in the image. - noCompression := archive.Uncompressed - diffOptions := DiffOptions{ - Compression: &noCompression, - } - rc, err := layerHomeStore.Diff("", layer.ID, &diffOptions) - if err != nil { - return nil, errors.Wrapf(err, "error reading layer %q to create an ID-mapped version of it", layer.ID) - } - defer rc.Close() - + // ... so create a duplicate of the layer with the desired mappings, and + // register it as an alternate top layer in the image. var layerOptions LayerOptions if s.graphDriver.SupportsShifting() { - layerOptions = LayerOptions{IDMappingOptions: IDMappingOptions{HostUIDMapping: true, HostGIDMapping: true, UIDMap: nil, GIDMap: nil}} + layerOptions = LayerOptions{ + IDMappingOptions: IDMappingOptions{ + HostUIDMapping: true, + HostGIDMapping: true, + UIDMap: nil, + GIDMap: nil, + }, + } } else { layerOptions = LayerOptions{ IDMappingOptions: IDMappingOptions{ @@ -1068,9 +1068,10 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, read }, } } - mappedLayer, _, err := rlstore.Put("", parentLayer, nil, layer.MountLabel, nil, &layerOptions, false, nil, rc) + layerOptions.TemplateLayer = layer.ID + mappedLayer, _, err := rlstore.Put("", parentLayer, nil, layer.MountLabel, nil, &layerOptions, false, nil, nil) if err != nil { - return nil, errors.Wrapf(err, "error creating ID-mapped copy of layer %q", layer.ID) + return nil, errors.Wrapf(err, "error creating an ID-mapped copy of layer %q", layer.ID) } if err = istore.addMappedTopLayer(image.ID, mappedLayer.ID); err != nil { if err2 := rlstore.Delete(mappedLayer.ID); err2 != nil { @@ -1144,7 +1145,9 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat } imageID = cimage.ID - ilayer, err := s.imageTopLayerForMapping(cimage, imageHomeStore, imageHomeStore == istore, rlstore, lstores, idMappingsOptions) + createMappedLayer := imageHomeStore == istore + + ilayer, err := s.imageTopLayerForMapping(cimage, imageHomeStore, createMappedLayer, rlstore, lstores, idMappingsOptions) if err != nil { return nil, err } @@ -1170,7 +1173,14 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat } var layerOptions *LayerOptions if s.graphDriver.SupportsShifting() { - layerOptions = &LayerOptions{IDMappingOptions: IDMappingOptions{HostUIDMapping: true, HostGIDMapping: true, UIDMap: nil, GIDMap: nil}} + layerOptions = &LayerOptions{ + IDMappingOptions: IDMappingOptions{ + HostUIDMapping: true, + HostGIDMapping: true, + UIDMap: nil, + GIDMap: nil, + }, + } } else { layerOptions = &LayerOptions{ IDMappingOptions: IDMappingOptions{ @@ -2091,10 +2101,10 @@ func (s *store) DeleteImage(id string, commit bool) (layers []string, err error) break } lastRemoved = layer - layersToRemove = append(layersToRemove, lastRemoved) if layer == image.TopLayer { layersToRemove = append(layersToRemove, image.MappedTopLayers...) } + layersToRemove = append(layersToRemove, lastRemoved) layer = parent } } else { @@ -3064,9 +3074,6 @@ type OptionsConfig struct { // Size Size string `toml:"size"` - // OverrideKernelCheck - OverrideKernelCheck string `toml:"override_kernel_check"` - // RemapUIDs is a list of default UID mappings to use for layers. RemapUIDs string `toml:"remap-uids"` // RemapGIDs is a list of default GID mappings to use for layers. @@ -3191,9 +3198,6 @@ func ReloadConfigurationFile(configFile string, storeOptions *StoreOptions) { if config.Storage.Options.MountOpt != "" { storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.mountopt=%s", config.Storage.Driver, config.Storage.Options.MountOpt)) } - if config.Storage.Options.OverrideKernelCheck != "" { - storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.override_kernel_check=%s", config.Storage.Driver, config.Storage.Options.OverrideKernelCheck)) - } if config.Storage.Options.RemapUser != "" && config.Storage.Options.RemapGroup == "" { config.Storage.Options.RemapGroup = config.Storage.Options.RemapUser } diff --git a/vendor/github.com/containers/storage/vendor.conf b/vendor/github.com/containers/storage/vendor.conf index 936321b12..04af9010b 100644 --- a/vendor/github.com/containers/storage/vendor.conf +++ b/vendor/github.com/containers/storage/vendor.conf @@ -8,7 +8,7 @@ github.com/mattn/go-shellwords 753a2322a99f87c0eff284980e77f53041555bc6 github.com/mistifyio/go-zfs c0224de804d438efd11ea6e52ada8014537d6062 github.com/opencontainers/go-digest master github.com/opencontainers/runc 6c22e77604689db8725fa866f0f2ec0b3e8c3a07 -github.com/opencontainers/selinux 36a9bc45a08c85f2c52bd9eb32e20267876773bd +github.com/opencontainers/selinux v1.1 github.com/ostreedev/ostree-go master github.com/pborman/uuid 1b00554d822231195d1babd97ff4a781231955c9 github.com/pkg/errors master diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go index bb27ac936..4e9a8c54f 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go @@ -75,8 +75,8 @@ func ReleaseLabel(label string) error { // DupSecOpt takes a process label and returns security options that // can be used to set duplicate labels on future container processes -func DupSecOpt(src string) []string { - return nil +func DupSecOpt(src string) ([]string, error) { + return nil, nil } // DisableSecOpt returns a security opt that can disable labeling diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go index de214b2d5..d4e26909d 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go @@ -4,6 +4,8 @@ package label import ( "fmt" + "os" + "os/user" "strings" "github.com/opencontainers/selinux/go-selinux" @@ -35,8 +37,15 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) { ReleaseLabel(mountLabel) } }() - pcon := selinux.NewContext(processLabel) - mcon := selinux.NewContext(mountLabel) + pcon, err := selinux.NewContext(processLabel) + if err != nil { + return "", "", err + } + + mcon, err := selinux.NewContext(mountLabel) + if err != nil { + return "", "", err + } for _, opt := range options { if opt == "disable" { return "", mountLabel, nil @@ -146,13 +155,56 @@ func Relabel(path string, fileLabel string, shared bool) error { return nil } - exclude_paths := map[string]bool{"/": true, "/usr": true, "/etc": true, "/tmp": true, "/home": true, "/run": true, "/var": true, "/root": true} + exclude_paths := map[string]bool{ + "/": true, + "/bin": true, + "/boot": true, + "/dev": true, + "/etc": true, + "/etc/passwd": true, + "/etc/pki": true, + "/etc/shadow": true, + "/home": true, + "/lib": true, + "/lib64": true, + "/media": true, + "/opt": true, + "/proc": true, + "/root": true, + "/run": true, + "/sbin": true, + "/srv": true, + "/sys": true, + "/tmp": true, + "/usr": true, + "/var": true, + "/var/lib": true, + "/var/log": true, + } + + if home := os.Getenv("HOME"); home != "" { + exclude_paths[home] = true + } + + if sudoUser := os.Getenv("SUDO_USER"); sudoUser != "" { + if usr, err := user.Lookup(sudoUser); err == nil { + exclude_paths[usr.HomeDir] = true + } + } + + if path != "/" { + path = strings.TrimSuffix(path, "/") + } if exclude_paths[path] { return fmt.Errorf("SELinux relabeling of %s is not allowed", path) } if shared { - c := selinux.NewContext(fileLabel) + c, err := selinux.NewContext(fileLabel) + if err != nil { + return err + } + c["level"] = "s0" fileLabel = c.Get() } @@ -195,7 +247,7 @@ func ReleaseLabel(label string) error { // DupSecOpt takes a process label and returns security options that // can be used to set duplicate labels on future container processes -func DupSecOpt(src string) []string { +func DupSecOpt(src string) ([]string, error) { return selinux.DupSecOpt(src) } diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go index 7832f7497..5adafd317 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go @@ -52,6 +52,8 @@ var ( ErrMCSAlreadyExists = errors.New("MCS label already exists") // ErrEmptyPath is returned when an empty path has been specified. ErrEmptyPath = errors.New("empty path") + // InvalidLabel is returned when an invalid label is specified. + InvalidLabel = errors.New("Invalid Label") assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`) roFileLabel string @@ -405,11 +407,14 @@ func (c Context) Get() string { } // NewContext creates a new Context struct from the specified label -func NewContext(label string) Context { +func NewContext(label string) (Context, error) { c := make(Context) if len(label) != 0 { con := strings.SplitN(label, ":", 4) + if len(con) < 3 { + return c, InvalidLabel + } c["user"] = con[0] c["role"] = con[1] c["type"] = con[2] @@ -417,7 +422,7 @@ func NewContext(label string) Context { c["level"] = con[3] } } - return c + return c, nil } // ClearLabels clears all reserved labels @@ -630,12 +635,12 @@ func ContainerLabels() (processLabel string, fileLabel string) { roFileLabel = fileLabel } exit: - scon := NewContext(processLabel) + scon, _ := NewContext(processLabel) if scon["level"] != "" { mcs := uniqMcs(1024) scon["level"] = mcs processLabel = scon.Get() - scon = NewContext(fileLabel) + scon, _ = NewContext(fileLabel) scon["level"] = mcs fileLabel = scon.Get() } @@ -661,8 +666,14 @@ func CopyLevel(src, dest string) (string, error) { if err := SecurityCheckContext(dest); err != nil { return "", err } - scon := NewContext(src) - tcon := NewContext(dest) + scon, err := NewContext(src) + if err != nil { + return "", err + } + tcon, err := NewContext(dest) + if err != nil { + return "", err + } mcsDelete(tcon["level"]) mcsAdd(scon["level"]) tcon["level"] = scon["level"] @@ -714,15 +725,18 @@ func Chcon(fpath string, label string, recurse bool) error { // DupSecOpt takes an SELinux process label and returns security options that // can be used to set the SELinux Type and Level for future container processes. -func DupSecOpt(src string) []string { +func DupSecOpt(src string) ([]string, error) { if src == "" { - return nil + return nil, nil + } + con, err := NewContext(src) + if err != nil { + return nil, err } - con := NewContext(src) if con["user"] == "" || con["role"] == "" || con["type"] == "" { - return nil + return nil, nil } dup := []string{"user:" + con["user"], "role:" + con["role"], @@ -733,7 +747,7 @@ func DupSecOpt(src string) []string { dup = append(dup, "level:"+con["level"]) } - return dup + return dup, nil } // DisableSecOpt returns a security opt that can be used to disable SELinux diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go index 99efa155a..9497acbd0 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go @@ -115,9 +115,9 @@ func (c Context) Get() string { } // NewContext creates a new Context struct from the specified label -func NewContext(label string) Context { +func NewContext(label string) (Context, error) { c := make(Context) - return c + return c, nil } // ClearLabels clears all reserved MLS/MCS levels @@ -195,8 +195,8 @@ func Chcon(fpath string, label string, recurse bool) error { // DupSecOpt takes an SELinux process label and returns security options that // can be used to set the SELinux Type and Level for future container processes. -func DupSecOpt(src string) []string { - return nil +func DupSecOpt(src string) ([]string, error) { + return nil, nil } // DisableSecOpt returns a security opt that can be used to disable SELinux diff --git a/vendor/github.com/urfave/cli/help.go b/vendor/github.com/urfave/cli/help.go index 65874fa2f..a0e949f72 100644 --- a/vendor/github.com/urfave/cli/help.go +++ b/vendor/github.com/urfave/cli/help.go @@ -82,7 +82,7 @@ OPTIONS: var helpCommand = Command{ Name: "help", Aliases: []string{"h"}, - Usage: "Shows a list of commands or help for one command", + Usage: "Show a list of commands or help for one command", ArgsUsage: "[command]", Action: func(c *Context) error { args := c.Args() diff --git a/vendor/github.com/varlink/go/.gitignore b/vendor/github.com/varlink/go/.gitignore index 69e30cff1..a43b0e2d3 100644 --- a/vendor/github.com/varlink/go/.gitignore +++ b/vendor/github.com/varlink/go/.gitignore @@ -1 +1,2 @@ /cmd/varlink-go-certification/orgvarlinkcertification/orgvarlinkcertification.go +/.idea diff --git a/vendor/github.com/varlink/go/.travis.yml b/vendor/github.com/varlink/go/.travis.yml index c090a924f..fa9963500 100644 --- a/vendor/github.com/varlink/go/.travis.yml +++ b/vendor/github.com/varlink/go/.travis.yml @@ -1,11 +1,13 @@ language: go sudo: false go: -- '1.9' -- 1.10.x +- '1.10' +- 1.11.x install: - go get golang.org/x/tools/cmd/cover - go get github.com/mattn/goveralls +- go get github.com/TylerBrock/colorjson +- go get github.com/fatih/color script: - go generate ./... - '"$HOME/gopath/bin/goveralls" -v -show -service=travis-ci -repotoken "$COVERALLS_TOKEN"' diff --git a/vendor/github.com/varlink/go/cmd/varlink/main.go b/vendor/github.com/varlink/go/cmd/varlink/main.go new file mode 100644 index 000000000..1de4e1a45 --- /dev/null +++ b/vendor/github.com/varlink/go/cmd/varlink/main.go @@ -0,0 +1,295 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "github.com/TylerBrock/colorjson" + "github.com/fatih/color" + "github.com/varlink/go/varlink" + "os" + "strings" +) + +var bold = color.New(color.Bold) +var errorBoldRed = bold.Sprint(color.New(color.FgRed).Sprint("Error:")) +var bridge string + +func ErrPrintf(format string, a ...interface{}) { + fmt.Fprintf(os.Stderr, "%s ", errorBoldRed) + fmt.Fprintf(os.Stderr, format, a...) +} + +func print_usage(set *flag.FlagSet, arg_help string) { + if set == nil { + fmt.Fprintf(os.Stderr, "Usage: %s [GLOBAL OPTIONS] COMMAND ...\n", os.Args[0]) + } else { + fmt.Fprintf(os.Stderr, "Usage: %s [GLOBAL OPTIONS] %s [OPTIONS] %s\n", os.Args[0], set.Name(), arg_help) + } + + fmt.Fprintln(os.Stderr, "\nGlobal Options:") + flag.PrintDefaults() + + if set == nil { + fmt.Fprintln(os.Stderr, "\nCommands:") + fmt.Fprintln(os.Stderr, " info\tPrint information about a service") + fmt.Fprintln(os.Stderr, " help\tPrint interface description or service information") + fmt.Fprintln(os.Stderr, " call\tCall a method") + } else { + fmt.Fprintln(os.Stderr, "\nOptions:") + set.PrintDefaults() + } + os.Exit(1) +} + +func varlink_call(args []string) { + var err error + var oneway bool + + callFlags := flag.NewFlagSet("help", flag.ExitOnError) + callFlags.BoolVar(&oneway, "-oneway", false, "Use bridge for connection") + var help bool + callFlags.BoolVar(&help, "help", false, "Prints help information") + var usage = func() { print_usage(callFlags, "<[ADDRESS/]INTERFACE.METHOD> [ARGUMENTS]") } + callFlags.Usage = usage + + _ = callFlags.Parse(args) + + if help { + usage() + } + + var con *varlink.Connection + var address string + var methodName string + + if len(bridge) != 0 { + con, err = varlink.NewBridge(bridge) + + if err != nil { + ErrPrintf("Cannot connect with bridge '%s': %v\n", bridge, err) + os.Exit(2) + } + address = "bridge:" + bridge + methodName = callFlags.Arg(0) + } else { + uri := callFlags.Arg(0) + if uri == "" { + usage() + } + + li := strings.LastIndex(uri, "/") + + if li == -1 { + ErrPrintf("Invalid address '%s'\n", uri) + os.Exit(2) + } + + address = uri[:li] + methodName = uri[li+1:] + + con, err = varlink.NewConnection(address) + + if err != nil { + ErrPrintf("Cannot connect to '%s': %v\n", address, err) + os.Exit(2) + } + } + var parameters string + var params json.RawMessage + + parameters = callFlags.Arg(1) + if parameters == "" { + params = nil + } else { + json.Unmarshal([]byte(parameters), ¶ms) + } + + var flags uint64 + flags = 0 + if oneway { + flags |= varlink.Oneway + } + recv, err := con.Send(methodName, params, flags) + + var retval map[string]interface{} + + // FIXME: Use cont + _, err = recv(&retval) + + f := colorjson.NewFormatter() + f.Indent = 2 + f.KeyColor = color.New(color.FgCyan) + f.StringColor = color.New(color.FgMagenta) + f.NumberColor = color.New(color.FgMagenta) + f.BoolColor = color.New(color.FgMagenta) + f.NullColor = color.New(color.FgMagenta) + + if err != nil { + ErrPrintf("Error calling '%s': %v\n", methodName, err) + switch e := err.(type) { + case *varlink.Error: + println(e.Name) + errorRawParameters := e.Parameters.(*json.RawMessage) + + if errorRawParameters == nil { + break + } + var param map[string]interface{} + _ = json.Unmarshal(*errorRawParameters, ¶m) + c, _ := f.Marshal(param) + ErrPrintf("%v\n", string(c)) + } + os.Exit(2) + } + c, _ := f.Marshal(retval) + fmt.Println(string(c)) +} + +func varlink_help(args []string) { + var err error + + helpFlags := flag.NewFlagSet("help", flag.ExitOnError) + var help bool + helpFlags.BoolVar(&help, "help", false, "Prints help information") + var usage = func() { print_usage(helpFlags, "<[ADDRESS/]INTERFACE>") } + helpFlags.Usage = usage + + _ = helpFlags.Parse(args) + + if help { + usage() + } + + var con *varlink.Connection + var address string + var interfaceName string + + if len(bridge) != 0 { + con, err = varlink.NewBridge(bridge) + + if err != nil { + ErrPrintf("Cannot connect with bridge '%s': %v\n", bridge, err) + os.Exit(2) + } + address = "bridge:" + bridge + interfaceName = helpFlags.Arg(0) + } else { + uri := helpFlags.Arg(0) + if uri == "" && bridge == "" { + ErrPrintf("No ADDRESS or activation or bridge\n\n") + usage() + } + + li := strings.LastIndex(uri, "/") + + if li == -1 { + ErrPrintf("Invalid address '%s'\n", uri) + os.Exit(2) + } + + address = uri[:li] + + con, err = varlink.NewConnection(address) + + if err != nil { + ErrPrintf("Cannot connect to '%s': %v\n", address, err) + os.Exit(2) + } + + interfaceName = uri[li+1:] + } + description, err := con.GetInterfaceDescription(interfaceName) + + if err != nil { + ErrPrintf("Cannot get interface description for '%s': %v\n", interfaceName, err) + os.Exit(2) + } + + fmt.Println(description) +} + +func varlink_info(args []string) { + var err error + infoFlags := flag.NewFlagSet("info", flag.ExitOnError) + var help bool + infoFlags.BoolVar(&help, "help", false, "Prints help information") + var usage = func() { print_usage(infoFlags, "[ADDRESS]") } + infoFlags.Usage = usage + + _ = infoFlags.Parse(args) + + if help { + usage() + } + + var con *varlink.Connection + var address string + + if len(bridge) != 0 { + con, err = varlink.NewBridge(bridge) + + if err != nil { + ErrPrintf("Cannot connect with bridge '%s': %v\n", bridge, err) + os.Exit(2) + } + address = "bridge:" + bridge + } else { + address = infoFlags.Arg(0) + + if address == "" && bridge == "" { + ErrPrintf("No ADDRESS or activation or bridge\n\n") + usage() + } + + con, err = varlink.NewConnection(address) + + if err != nil { + ErrPrintf("Cannot connect to '%s': %v\n", address, err) + os.Exit(2) + } + } + + var vendor, product, version, url string + var interfaces []string + + err = con.GetInfo(&vendor, &product, &version, &url, &interfaces) + + if err != nil { + ErrPrintf("Cannot get info for '%s': %v\n", address, err) + os.Exit(2) + } + + fmt.Printf("%s %s\n", bold.Sprint("Vendor:"), vendor) + fmt.Printf("%s %s\n", bold.Sprint("Product:"), product) + fmt.Printf("%s %s\n", bold.Sprint("Version:"), version) + fmt.Printf("%s %s\n", bold.Sprint("URL:"), url) + fmt.Printf("%s\n %s\n\n", bold.Sprint("Interfaces:"), strings.Join(interfaces[:], "\n ")) +} + +func main() { + var debug bool + var colorMode string + + flag.CommandLine.Usage = func() { print_usage(nil, "") } + flag.BoolVar(&debug, "debug", false, "Enable debug output") + flag.StringVar(&bridge, "bridge", "", "Use bridge for connection") + flag.StringVar(&colorMode, "color", "auto", "colorize output [default: auto] [possible values: on, off, auto]") + + flag.Parse() + + if colorMode != "on" && (os.Getenv("TERM") == "" || colorMode == "off") { + color.NoColor = true // disables colorized output + } + + switch flag.Arg(0) { + case "info": + varlink_info(flag.Args()[1:]) + case "help": + varlink_help(flag.Args()[1:]) + case "call": + varlink_call(flag.Args()[1:]) + default: + print_usage(nil, "") + } +} diff --git a/vendor/github.com/varlink/go/varlink/bridge.go b/vendor/github.com/varlink/go/varlink/bridge.go new file mode 100644 index 000000000..b20c0925a --- /dev/null +++ b/vendor/github.com/varlink/go/varlink/bridge.go @@ -0,0 +1,59 @@ +// +build !windows + +package varlink + +import ( + "bufio" + "io" + "log" + "net" + "os/exec" +) + +type PipeCon struct { + net.Conn + reader *io.ReadCloser + writer *io.WriteCloser +} + +func (p PipeCon) Close() error { + err1 := (*p.reader).Close() + err2 := (*p.writer).Close() + if err1 != nil { + return err1 + } + if err2 != nil { + return err2 + } + return nil +} + +// NewConnection returns a new connection to the given address. +func NewBridge(bridge string) (*Connection, error) { + //var err error + + c := Connection{} + cmd := exec.Command("sh", "-c", bridge) + r, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + w, err := cmd.StdinPipe() + if err != nil { + return nil, err + } + c.conn = PipeCon{nil, &r, &w} + c.address = "" + c.reader = bufio.NewReader(r) + c.writer = bufio.NewWriter(w) + + go func() { + err := cmd.Run() + if err != nil { + log.Fatal(err) + } + }() + + return &c, nil +} + diff --git a/vendor/github.com/varlink/go/varlink/bridge_windows.go b/vendor/github.com/varlink/go/varlink/bridge_windows.go new file mode 100644 index 000000000..692367a1a --- /dev/null +++ b/vendor/github.com/varlink/go/varlink/bridge_windows.go @@ -0,0 +1,57 @@ +package varlink + +import ( + "bufio" + "io" + "log" + "net" + "os/exec" +) + +type PipeCon struct { + net.Conn + reader *io.ReadCloser + writer *io.WriteCloser +} + +func (p PipeCon) Close() error { + err1 := (*p.reader).Close() + err2 := (*p.writer).Close() + if err1 != nil { + return err1 + } + if err2 != nil { + return err2 + } + return nil +} + +// NewConnection returns a new connection to the given address. +func NewBridge(bridge string) (*Connection, error) { + //var err error + + c := Connection{} + cmd := exec.Command("cmd", "/C", bridge) + r, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + w, err := cmd.StdinPipe() + if err != nil { + return nil, err + } + c.conn = PipeCon{nil, &r, &w} + c.address = "" + c.reader = bufio.NewReader(r) + c.writer = bufio.NewWriter(w) + + go func() { + err := cmd.Run() + if err != nil { + log.Fatal(err) + } + }() + + return &c, nil +} + diff --git a/vendor/github.com/varlink/go/varlink/connection.go b/vendor/github.com/varlink/go/varlink/connection.go index 43bec6393..ac9542408 100644 --- a/vendor/github.com/varlink/go/varlink/connection.go +++ b/vendor/github.com/varlink/go/varlink/connection.go @@ -3,6 +3,7 @@ package varlink import ( "bufio" "encoding/json" + "fmt" "net" "strings" ) @@ -18,6 +19,7 @@ const ( // Error is a varlink error returned from a method call. type Error struct { + error Name string Parameters interface{} } @@ -189,6 +191,11 @@ func NewConnection(address string) (*Connection, error) { var err error words := strings.SplitN(address, ":", 2) + + if len(words) != 2 { + return nil, fmt.Errorf("Protocol missing") + } + protocol := words[0] addr := words[1] diff --git a/vendor/github.com/varlink/go/varlink/service.go b/vendor/github.com/varlink/go/varlink/service.go index 551ba4e53..cb461f917 100644 --- a/vendor/github.com/varlink/go/varlink/service.go +++ b/vendor/github.com/varlink/go/varlink/service.go @@ -6,10 +6,8 @@ import ( "fmt" "net" "os" - "strconv" "strings" "sync" - "syscall" "time" ) @@ -110,58 +108,6 @@ func (s *Service) handleMessage(writer *bufio.Writer, request []byte) error { return iface.VarlinkDispatch(c, methodname) } -func activationListener() net.Listener { - pid, err := strconv.Atoi(os.Getenv("LISTEN_PID")) - if err != nil || pid != os.Getpid() { - return nil - } - - nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS")) - if err != nil || nfds < 1 { - return nil - } - - fd := -1 - - // If more than one file descriptor is passed, find the - // "varlink" tag. The first file descriptor is always 3. - if nfds > 1 { - fdnames, set := os.LookupEnv("LISTEN_FDNAMES") - if !set { - return nil - } - - names := strings.Split(fdnames, ":") - if len(names) != nfds { - return nil - } - - for i, name := range names { - if name == "varlink" { - fd = 3 + i - break - } - } - - if fd < 0 { - return nil - } - - } else { - fd = 3 - } - - syscall.CloseOnExec(fd) - - file := os.NewFile(uintptr(fd), "varlink") - listener, err := net.FileListener(file) - if err != nil { - return nil - } - - return listener -} - // Shutdown shuts down the listener of a running service. func (s *Service) Shutdown() { s.running = false @@ -253,18 +199,17 @@ func getListener(protocol string, address string) (net.Listener, error) { } func (s *Service) refreshTimeout(timeout time.Duration) error { - switch s.protocol { - case "unix": - if err := s.listener.(*net.UnixListener).SetDeadline(time.Now().Add(timeout)); err != nil { + switch l := s.listener.(type) { + case *net.UnixListener: + if err:= l.SetDeadline(time.Now().Add(timeout)); err != nil { return err } - - case "tcp": - if err := s.listener.(*net.TCPListener).SetDeadline(time.Now().Add(timeout)); err != nil { + case *net.TCPListener: + if err:= l.SetDeadline(time.Now().Add(timeout)); err != nil { return err } - } + } return nil } diff --git a/vendor/github.com/varlink/go/varlink/socketactivation.go b/vendor/github.com/varlink/go/varlink/socketactivation.go new file mode 100644 index 000000000..a64c0dc8e --- /dev/null +++ b/vendor/github.com/varlink/go/varlink/socketactivation.go @@ -0,0 +1,63 @@ +// +build !windows + +package varlink + +import ( + "net" + "os" + "strconv" + "strings" + "syscall" +) + +func activationListener() net.Listener { + pid, err := strconv.Atoi(os.Getenv("LISTEN_PID")) + if err != nil || pid != os.Getpid() { + return nil + } + + nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS")) + if err != nil || nfds < 1 { + return nil + } + + fd := -1 + + // If more than one file descriptor is passed, find the + // "varlink" tag. The first file descriptor is always 3. + if nfds > 1 { + fdnames, set := os.LookupEnv("LISTEN_FDNAMES") + if !set { + return nil + } + + names := strings.Split(fdnames, ":") + if len(names) != nfds { + return nil + } + + for i, name := range names { + if name == "varlink" { + fd = 3 + i + break + } + } + + if fd < 0 { + return nil + } + + } else { + fd = 3 + } + + syscall.CloseOnExec(fd) + + file := os.NewFile(uintptr(fd), "varlink") + listener, err := net.FileListener(file) + if err != nil { + return nil + } + + return listener +} diff --git a/vendor/github.com/varlink/go/varlink/socketactivation_windows.go b/vendor/github.com/varlink/go/varlink/socketactivation_windows.go new file mode 100644 index 000000000..fb0894531 --- /dev/null +++ b/vendor/github.com/varlink/go/varlink/socketactivation_windows.go @@ -0,0 +1,7 @@ +package varlink + +import "net" + +func activationListener() net.Listener { + return nil +} |