diff --git a/vendor/github.com/containers/storage/containers.go b/vendor/github.com/containers/storage/containers.go index 90a0bc0b..a6a4f77b 100644 --- a/vendor/github.com/containers/storage/containers.go +++ b/vendor/github.com/containers/storage/containers.go @@ -93,7 +93,7 @@ type ContainerStore interface { type containerStore struct { lockfile Locker dir string - containers []Container + containers []*Container idindex *truncindex.TruncIndex byid map[string]*Container bylayer map[string]*Container @@ -101,7 +101,11 @@ type containerStore struct { } func (r *containerStore) Containers() ([]Container, error) { - return r.containers, nil + containers := make([]Container, len(r.containers)) + for i := range r.containers { + containers[i] = *(r.containers[i]) + } + return containers, nil } func (r *containerStore) containerspath() string { @@ -123,7 +127,7 @@ func (r *containerStore) Load() error { if err != nil && !os.IsNotExist(err) { return err } - containers := []Container{} + containers := []*Container{} layers := make(map[string]*Container) idlist := []string{} ids := make(map[string]*Container) @@ -131,14 +135,14 @@ func (r *containerStore) Load() error { if err = json.Unmarshal(data, &containers); len(data) == 0 || err == nil { for n, container := range containers { idlist = append(idlist, container.ID) - ids[container.ID] = &containers[n] - layers[container.LayerID] = &containers[n] + ids[container.ID] = containers[n] + layers[container.LayerID] = containers[n] for _, name := range container.Names { if conflict, ok := names[name]; ok { r.removeName(conflict, name) needSave = true } - names[name] = &containers[n] + names[name] = containers[n] } } } @@ -148,7 +152,6 @@ func (r *containerStore) Load() error { r.bylayer = layers r.byname = names if needSave { - r.Touch() return r.Save() } return nil @@ -163,6 +166,7 @@ func (r *containerStore) Save() error { if err != nil { return err } + defer r.Touch() return ioutils.AtomicWriteFile(rpath, jdata, 0600) } @@ -179,7 +183,7 @@ func newContainerStore(dir string) (ContainerStore, error) { cstore := containerStore{ lockfile: lockfile, dir: dir, - containers: []Container{}, + containers: []*Container{}, byid: make(map[string]*Container), bylayer: make(map[string]*Container), byname: make(map[string]*Container), @@ -241,7 +245,7 @@ func (r *containerStore) Create(id string, names []string, image, layer, metadat } } if err == nil { - newContainer := Container{ + container = &Container{ ID: id, Names: names, ImageID: image, @@ -251,8 +255,7 @@ func (r *containerStore) Create(id string, names []string, image, layer, metadat BigDataSizes: make(map[string]int64), Flags: make(map[string]interface{}), } - r.containers = append(r.containers, newContainer) - container = &r.containers[len(r.containers)-1] + r.containers = append(r.containers, container) r.byid[id] = container r.idindex.Add(id) r.bylayer[layer] = container @@ -306,7 +309,7 @@ func (r *containerStore) Delete(id string) error { return ErrContainerUnknown } id = container.ID - newContainers := []Container{} + newContainers := []*Container{} for _, candidate := range r.containers { if candidate.ID != id { newContainers = append(newContainers, candidate) @@ -437,6 +440,10 @@ func (r *containerStore) Modified() (bool, error) { return r.lockfile.Modified() } +func (r *containerStore) IsReadWrite() bool { + return r.lockfile.IsReadWrite() +} + func (r *containerStore) TouchedSince(when time.Time) bool { return r.lockfile.TouchedSince(when) } diff --git a/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go b/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go index caa7474c..b2332b7f 100644 --- a/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go +++ b/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go @@ -28,7 +28,6 @@ import ( "github.com/containers/storage/pkg/loopback" "github.com/containers/storage/pkg/mount" "github.com/containers/storage/pkg/parsers" - "github.com/containers/storage/storageversion" "github.com/docker/go-units" "github.com/opencontainers/selinux/go-selinux/label" @@ -1668,17 +1667,17 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error { } // https://github.com/docker/docker/issues/4036 - if supported := devicemapper.UdevSetSyncSupport(true); !supported { - if storageversion.IAmStatic == "true" { - logrus.Errorf("devmapper: Udev sync is not supported. This will lead to data loss and unexpected behavior. Install a dynamic binary to use devicemapper or select a different storage driver. For more information, see https://docs.docker.com/engine/reference/commandline/daemon/#daemon-storage-driver-option") - } else { - logrus.Errorf("devmapper: Udev sync is not supported. This will lead to data loss and unexpected behavior. Install a more recent version of libdevmapper or select a different storage driver. For more information, see https://docs.docker.com/engine/reference/commandline/daemon/#daemon-storage-driver-option") - } - - if !devices.overrideUdevSyncCheck { - return graphdriver.ErrNotSupported - } - } + // if supported := devicemapper.UdevSetSyncSupport(true); !supported { + // if storageversion.IAmStatic == "true" { + // logrus.Errorf("devmapper: Udev sync is not supported. This will lead to data loss and unexpected behavior. Install a dynamic binary to use devicemapper or select a different storage driver. For more information, see https://docs.docker.com/engine/reference/commandline/daemon/#daemon-storage-driver-option") + // } else { + // logrus.Errorf("devmapper: Udev sync is not supported. This will lead to data loss and unexpected behavior. Install a more recent version of libdevmapper or select a different storage driver. For more information, see https://docs.docker.com/engine/reference/commandline/daemon/#daemon-storage-driver-option") + // } + // + // if !devices.overrideUdevSyncCheck { + // return graphdriver.ErrNotSupported + // } + // } //create the root dir of the devmapper driver ownership to match this //daemon's remapped root uid/gid so containers can start properly diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go index 28c11b4e..d0f73e3e 100644 --- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go +++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go @@ -377,8 +377,18 @@ func (d *Driver) getLower(parent string) (string, error) { return strings.Join(lowers, ":"), nil } -func (d *Driver) dir(id string) string { - return path.Join(d.home, id) +func (d *Driver) dir(val string) string { + newpath := path.Join(d.home, val) + if _, err := os.Stat(newpath); err != nil { + for _, p := range d.AdditionalImageStores() { + l := path.Join(p, d.name, val) + _, err = os.Stat(l) + if err == nil { + return l + } + } + } + return newpath } func (d *Driver) getLowerDirs(id string) ([]string, error) { @@ -386,11 +396,12 @@ func (d *Driver) getLowerDirs(id string) ([]string, error) { lowers, err := ioutil.ReadFile(path.Join(d.dir(id), lowerFile)) if err == nil { for _, s := range strings.Split(string(lowers), ":") { - lp, err := os.Readlink(path.Join(d.home, s)) + lower := d.dir(s) + lp, err := os.Readlink(lower) if err != nil { return nil, err } - lowersArray = append(lowersArray, path.Clean(path.Join(d.home, "link", lp))) + lowersArray = append(lowersArray, path.Clean(d.dir(path.Join("link", lp)))) } } else if !os.IsNotExist(err) { return nil, err @@ -431,6 +442,31 @@ func (d *Driver) Get(id string, mountLabel string) (s string, err error) { return "", err } + newlowers := "" + for _, l := range strings.Split(string(lowers), ":") { + lower := "" + newpath := path.Join(d.home, l) + if _, err := os.Stat(newpath); err != nil { + for _, p := range d.AdditionalImageStores() { + lower = path.Join(p, d.name, l) + if _, err2 := os.Stat(lower); err2 == nil { + break + } + lower = "" + } + if lower == "" { + return "", fmt.Errorf("Can't stat lower layer %q: %v", newpath, err) + } + } else { + lower = l + } + if newlowers == "" { + newlowers = lower + } else { + newlowers = newlowers + ":" + lower + } + } + mergedDir := path.Join(dir, "merged") if count := d.ctr.Increment(mergedDir); count > 1 { return mergedDir, nil @@ -444,7 +480,7 @@ func (d *Driver) Get(id string, mountLabel string) (s string, err error) { }() workDir := path.Join(dir, "work") - opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", string(lowers), path.Join(id, "diff"), path.Join(id, "work")) + opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", newlowers, path.Join(id, "diff"), path.Join(id, "work")) mountLabel = label.FormatMountLabel(opts, mountLabel) if len(mountLabel) > syscall.Getpagesize() { return "", fmt.Errorf("cannot mount layer, mount label too large %d", len(mountLabel)) diff --git a/vendor/github.com/containers/storage/images.go b/vendor/github.com/containers/storage/images.go index 6d9a7b58..4843b213 100644 --- a/vendor/github.com/containers/storage/images.go +++ b/vendor/github.com/containers/storage/images.go @@ -2,7 +2,6 @@ package storage import ( "encoding/json" - "errors" "io/ioutil" "os" "path/filepath" @@ -11,6 +10,7 @@ import ( "github.com/containers/storage/pkg/ioutils" "github.com/containers/storage/pkg/stringid" "github.com/containers/storage/pkg/truncindex" + "github.com/pkg/errors" ) var ( @@ -49,11 +49,32 @@ type Image struct { Flags map[string]interface{} `json:"flags,omitempty"` } +// ROImageStore provides bookkeeping for information about Images. +type ROImageStore interface { + ROFileBasedStore + ROMetadataStore + ROBigDataStore + + // Exists checks if there is an image with the given ID or name. + Exists(id string) bool + + // Get retrieves information about an image given an ID or name. + Get(id string) (*Image, error) + + // Lookup attempts to translate a name to an ID. Most methods do this + // implicitly. + Lookup(name string) (string, error) + + // Images returns a slice enumerating the known images. + Images() ([]Image, error) +} + // ImageStore provides bookkeeping for information about Images. type ImageStore interface { - FileBasedStore - MetadataStore - BigDataStore + ROImageStore + RWFileBasedStore + RWMetadataStore + RWBigDataStore FlaggableStore // Create creates an image that has a specified ID (or a random one) and @@ -65,37 +86,28 @@ type ImageStore interface { // supplied values. SetNames(id string, names []string) error - // Exists checks if there is an image with the given ID or name. - Exists(id string) bool - - // Get retrieves information about an image given an ID or name. - Get(id string) (*Image, error) - // Delete removes the record of the image. Delete(id string) error // Wipe removes records of all images. Wipe() error - - // Lookup attempts to translate a name to an ID. Most methods do this - // implicitly. - Lookup(name string) (string, error) - - // Images returns a slice enumerating the known images. - Images() ([]Image, error) } type imageStore struct { lockfile Locker dir string - images []Image + images []*Image idindex *truncindex.TruncIndex byid map[string]*Image byname map[string]*Image } func (r *imageStore) Images() ([]Image, error) { - return r.images, nil + images := make([]Image, len(r.images)) + for i := range r.images { + images[i] = *(r.images[i]) + } + return images, nil } func (r *imageStore) imagespath() string { @@ -111,41 +123,46 @@ func (r *imageStore) datapath(id, key string) string { } func (r *imageStore) Load() error { - needSave := false + shouldSave := false rpath := r.imagespath() data, err := ioutil.ReadFile(rpath) if err != nil && !os.IsNotExist(err) { return err } - images := []Image{} + images := []*Image{} idlist := []string{} ids := make(map[string]*Image) names := make(map[string]*Image) if err = json.Unmarshal(data, &images); len(data) == 0 || err == nil { for n, image := range images { - ids[image.ID] = &images[n] + ids[image.ID] = images[n] idlist = append(idlist, image.ID) for _, name := range image.Names { if conflict, ok := names[name]; ok { r.removeName(conflict, name) - needSave = true + shouldSave = true } - names[name] = &images[n] + names[name] = images[n] } } } + if shouldSave && !r.IsReadWrite() { + return errors.New("image store assigns the same name to multiple images") + } r.images = images r.idindex = truncindex.NewTruncIndex(idlist) r.byid = ids r.byname = names - if needSave { - r.Touch() + if shouldSave { return r.Save() } return nil } func (r *imageStore) Save() error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to modify the image store at %q", r.imagespath()) + } rpath := r.imagespath() if err := os.MkdirAll(filepath.Dir(rpath), 0700); err != nil { return err @@ -154,6 +171,7 @@ func (r *imageStore) Save() error { if err != nil { return err } + defer r.Touch() return ioutils.AtomicWriteFile(rpath, jdata, 0600) } @@ -170,7 +188,27 @@ func newImageStore(dir string) (ImageStore, error) { istore := imageStore{ lockfile: lockfile, dir: dir, - images: []Image{}, + images: []*Image{}, + byid: make(map[string]*Image), + byname: make(map[string]*Image), + } + if err := istore.Load(); err != nil { + return nil, err + } + return &istore, nil +} + +func newROImageStore(dir string) (ROImageStore, error) { + lockfile, err := GetROLockfile(filepath.Join(dir, "images.lock")) + if err != nil { + return nil, err + } + lockfile.Lock() + defer lockfile.Unlock() + istore := imageStore{ + lockfile: lockfile, + dir: dir, + images: []*Image{}, byid: make(map[string]*Image), byname: make(map[string]*Image), } @@ -193,6 +231,9 @@ func (r *imageStore) lookup(id string) (*Image, bool) { } func (r *imageStore) ClearFlag(id string, flag string) error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to clear flags on images at %q", r.imagespath()) + } image, ok := r.lookup(id) if !ok { return ErrImageUnknown @@ -202,6 +243,9 @@ func (r *imageStore) ClearFlag(id string, flag string) error { } func (r *imageStore) SetFlag(id string, flag string, value interface{}) error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to set flags on images at %q", r.imagespath()) + } image, ok := r.lookup(id) if !ok { return ErrImageUnknown @@ -211,6 +255,9 @@ func (r *imageStore) SetFlag(id string, flag string, value interface{}) error { } func (r *imageStore) Create(id string, names []string, layer, metadata string) (image *Image, err error) { + if !r.IsReadWrite() { + return nil, errors.Wrapf(ErrStoreIsReadOnly, "not allowed to create new images at %q", r.imagespath()) + } if id == "" { id = stringid.GenerateRandomID() _, idInUse := r.byid[id] @@ -228,7 +275,7 @@ func (r *imageStore) Create(id string, names []string, layer, metadata string) ( } } if err == nil { - newImage := Image{ + image = &Image{ ID: id, Names: names, TopLayer: layer, @@ -237,8 +284,7 @@ func (r *imageStore) Create(id string, names []string, layer, metadata string) ( BigDataSizes: make(map[string]int64), Flags: make(map[string]interface{}), } - r.images = append(r.images, newImage) - image = &r.images[len(r.images)-1] + r.images = append(r.images, image) r.idindex.Add(id) r.byid[id] = image for _, name := range names { @@ -257,6 +303,9 @@ func (r *imageStore) Metadata(id string) (string, error) { } func (r *imageStore) SetMetadata(id, metadata string) error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to modify image metadata at %q", r.imagespath()) + } if image, ok := r.lookup(id); ok { image.Metadata = metadata return r.Save() @@ -269,6 +318,9 @@ func (r *imageStore) removeName(image *Image, name string) { } func (r *imageStore) SetNames(id string, names []string) error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to change image name assignments at %q", r.imagespath()) + } if image, ok := r.lookup(id); ok { for _, name := range image.Names { delete(r.byname, name) @@ -286,12 +338,15 @@ func (r *imageStore) SetNames(id string, names []string) error { } func (r *imageStore) Delete(id string) error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to delete images at %q", r.imagespath()) + } image, ok := r.lookup(id) if !ok { return ErrImageUnknown } id = image.ID - newImages := []Image{} + newImages := []*Image{} for _, candidate := range r.images { if candidate.ID != id { newImages = append(newImages, candidate) @@ -359,6 +414,9 @@ func (r *imageStore) BigDataNames(id string) ([]string, error) { } func (r *imageStore) SetBigData(id, key string, data []byte) error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to save data items associated with images at %q", r.imagespath()) + } image, ok := r.lookup(id) if !ok { return ErrImageUnknown @@ -393,6 +451,9 @@ func (r *imageStore) SetBigData(id, key string, data []byte) error { } func (r *imageStore) Wipe() error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to delete images at %q", r.imagespath()) + } ids := []string{} for id := range r.byid { ids = append(ids, id) @@ -421,6 +482,10 @@ func (r *imageStore) Modified() (bool, error) { return r.lockfile.Modified() } +func (r *imageStore) IsReadWrite() bool { + return r.lockfile.IsReadWrite() +} + func (r *imageStore) TouchedSince(when time.Time) bool { return r.lockfile.TouchedSince(when) } diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go index 9a5aac6f..691d84f6 100644 --- a/vendor/github.com/containers/storage/layers.go +++ b/vendor/github.com/containers/storage/layers.go @@ -4,7 +4,6 @@ import ( "bytes" "compress/gzip" "encoding/json" - "errors" "io" "io/ioutil" "os" @@ -16,6 +15,7 @@ import ( "github.com/containers/storage/pkg/ioutils" "github.com/containers/storage/pkg/stringid" "github.com/containers/storage/pkg/truncindex" + "github.com/pkg/errors" "github.com/vbatts/tar-split/tar/asm" "github.com/vbatts/tar-split/tar/storage" ) @@ -75,28 +75,12 @@ type layerMountPoint struct { MountCount int `json:"count"` } -// LayerStore wraps a graph driver, adding the ability to refer to layers by +// ROLayerStore wraps a graph driver, adding the ability to refer to layers by // name, and keeping track of parent-child relationships, along with a list of // all known layers. -type LayerStore interface { - FileBasedStore - MetadataStore - FlaggableStore - - // Create creates a new layer, optionally giving it a specified ID rather than - // a randomly-generated one, either inheriting data from another specified - // layer or the empty base layer. The new layer can optionally be given names - // and have an SELinux label specified for use when mounting it. Some - // underlying drivers can accept a "size" option. At this time, most - // underlying drivers do not themselves distinguish between writeable - // and read-only layers. - Create(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool) (*Layer, error) - - // CreateWithFlags combines the functions of Create and SetFlag. - CreateWithFlags(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool, flags map[string]interface{}) (layer *Layer, err error) - - // Put combines the functions of CreateWithFlags and ApplyDiff. - Put(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool, flags map[string]interface{}, diff archive.Reader) (*Layer, int64, error) +type ROLayerStore interface { + ROFileBasedStore + ROMetadataStore // Exists checks if a layer with the specified name or ID is known. Exists(id string) bool @@ -104,28 +88,10 @@ type LayerStore interface { // Get retrieves information about a layer given an ID or name. Get(id string) (*Layer, error) - // SetNames replaces the list of names associated with a layer with the - // supplied values. - SetNames(id string, names []string) error - // Status returns an slice of key-value pairs, suitable for human consumption, // relaying whatever status information the underlying driver can share. Status() ([][2]string, error) - // Delete deletes a layer with the specified name or ID. - Delete(id string) error - - // Wipe deletes all layers. - Wipe() error - - // Mount mounts a layer for use. If the specified layer is the parent of other - // layers, it should not be written to. An SELinux label to be applied to the - // mount can be specified to override the one configured for the layer. - Mount(id, mountLabel string) (string, error) - - // Unmount unmounts a layer when it is no longer in use. - Unmount(id string) error - // Changes returns a slice of Change structures, which contain a pathname // (Path) and a description of what sort of change (Kind) was made by the // layer (either ChangeModify, ChangeAdd, or ChangeDelete), relative to a @@ -142,10 +108,6 @@ type LayerStore interface { // produced by Diff. DiffSize(from, to string) (int64, error) - // ApplyDiff reads a tarstream which was created by a previous call to Diff and - // applies its changes to a specified layer. - ApplyDiff(to string, diff archive.Reader) (int64, error) - // Lookup attempts to translate a name to an ID. Most methods do this // implicitly. Lookup(name string) (string, error) @@ -154,12 +116,59 @@ type LayerStore interface { Layers() ([]Layer, error) } +// LayerStore wraps a graph driver, adding the ability to refer to layers by +// name, and keeping track of parent-child relationships, along with a list of +// all known layers. +type LayerStore interface { + ROLayerStore + RWFileBasedStore + RWMetadataStore + FlaggableStore + + // Create creates a new layer, optionally giving it a specified ID rather than + // a randomly-generated one, either inheriting data from another specified + // layer or the empty base layer. The new layer can optionally be given names + // and have an SELinux label specified for use when mounting it. Some + // underlying drivers can accept a "size" option. At this time, most + // underlying drivers do not themselves distinguish between writeable + // and read-only layers. + Create(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool) (*Layer, error) + + // CreateWithFlags combines the functions of Create and SetFlag. + CreateWithFlags(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool, flags map[string]interface{}) (layer *Layer, err error) + + // Put combines the functions of CreateWithFlags and ApplyDiff. + Put(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool, flags map[string]interface{}, diff archive.Reader) (*Layer, int64, error) + + // SetNames replaces the list of names associated with a layer with the + // supplied values. + SetNames(id string, names []string) error + + // Delete deletes a layer with the specified name or ID. + Delete(id string) error + + // Wipe deletes all layers. + Wipe() error + + // Mount mounts a layer for use. If the specified layer is the parent of other + // layers, it should not be written to. An SELinux label to be applied to the + // mount can be specified to override the one configured for the layer. + Mount(id, mountLabel string) (string, error) + + // Unmount unmounts a layer when it is no longer in use. + Unmount(id string) error + + // ApplyDiff reads a tarstream which was created by a previous call to Diff and + // applies its changes to a specified layer. + ApplyDiff(to string, diff archive.Reader) (int64, error) +} + type layerStore struct { lockfile Locker rundir string driver drivers.Driver layerdir string - layers []Layer + layers []*Layer idindex *truncindex.TruncIndex byid map[string]*Layer byname map[string]*Layer @@ -167,7 +176,11 @@ type layerStore struct { } func (r *layerStore) Layers() ([]Layer, error) { - return r.layers, nil + layers := make([]Layer, len(r.layers)) + for i := range r.layers { + layers[i] = *(r.layers[i]) + } + return layers, nil } func (r *layerStore) mountspath() string { @@ -179,13 +192,13 @@ func (r *layerStore) layerspath() string { } func (r *layerStore) Load() error { - needSave := false + shouldSave := false rpath := r.layerspath() data, err := ioutil.ReadFile(rpath) if err != nil && !os.IsNotExist(err) { return err } - layers := []Layer{} + layers := []*Layer{} idlist := []string{} ids := make(map[string]*Layer) names := make(map[string]*Layer) @@ -193,22 +206,25 @@ func (r *layerStore) Load() error { parents := make(map[string][]*Layer) if err = json.Unmarshal(data, &layers); len(data) == 0 || err == nil { for n, layer := range layers { - ids[layer.ID] = &layers[n] + ids[layer.ID] = layers[n] idlist = append(idlist, layer.ID) for _, name := range layer.Names { if conflict, ok := names[name]; ok { r.removeName(conflict, name) - needSave = true + shouldSave = true } - names[name] = &layers[n] + names[name] = layers[n] } if pslice, ok := parents[layer.Parent]; ok { - parents[layer.Parent] = append(pslice, &layers[n]) + parents[layer.Parent] = append(pslice, layers[n]) } else { - parents[layer.Parent] = []*Layer{&layers[n]} + parents[layer.Parent] = []*Layer{layers[n]} } } } + if shouldSave && !r.IsReadWrite() { + return errors.New("layer store assigns the same name to multiple layers") + } mpath := r.mountspath() data, err = ioutil.ReadFile(mpath) if err != nil && !os.IsNotExist(err) { @@ -232,28 +248,32 @@ func (r *layerStore) Load() error { r.byname = names r.bymount = mounts err = nil - // Last step: try to remove anything that a previous user of this - // storage area marked for deletion but didn't manage to actually - // delete. - for _, layer := range r.layers { - if cleanup, ok := layer.Flags[incompleteFlag]; ok { - if b, ok := cleanup.(bool); ok && b { - err = r.Delete(layer.ID) - if err != nil { - break + // Last step: if we're writable, try to remove anything that a previous + // user of this storage area marked for deletion but didn't manage to + // actually delete. + if r.IsReadWrite() { + for _, layer := range r.layers { + if cleanup, ok := layer.Flags[incompleteFlag]; ok { + if b, ok := cleanup.(bool); ok && b { + err = r.Delete(layer.ID) + if err != nil { + break + } + shouldSave = true } - needSave = true } } - } - if needSave { - r.Touch() - return r.Save() + if shouldSave { + return r.Save() + } } return err } func (r *layerStore) Save() error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to modify the layer store at %q", r.layerspath()) + } rpath := r.layerspath() if err := os.MkdirAll(filepath.Dir(rpath), 0700); err != nil { return err @@ -283,6 +303,7 @@ func (r *layerStore) Save() error { if err := ioutils.AtomicWriteFile(rpath, jldata, 0600); err != nil { return err } + defer r.Touch() return ioutils.AtomicWriteFile(mpath, jmdata, 0600) } @@ -314,6 +335,28 @@ func newLayerStore(rundir string, layerdir string, driver drivers.Driver) (Layer return &rlstore, nil } +func newROLayerStore(rundir string, layerdir string, driver drivers.Driver) (ROLayerStore, error) { + lockfile, err := GetROLockfile(filepath.Join(layerdir, "layers.lock")) + if err != nil { + return nil, err + } + lockfile.Lock() + defer lockfile.Unlock() + rlstore := layerStore{ + lockfile: lockfile, + driver: driver, + rundir: rundir, + layerdir: layerdir, + byid: make(map[string]*Layer), + bymount: make(map[string]*Layer), + byname: make(map[string]*Layer), + } + if err := rlstore.Load(); err != nil { + return nil, err + } + return &rlstore, nil +} + func (r *layerStore) lookup(id string) (*Layer, bool) { if layer, ok := r.byid[id]; ok { return layer, ok @@ -327,6 +370,9 @@ func (r *layerStore) lookup(id string) (*Layer, bool) { } func (r *layerStore) ClearFlag(id string, flag string) error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to clear flags on layers at %q", r.layerspath()) + } layer, ok := r.lookup(id) if !ok { return ErrLayerUnknown @@ -336,6 +382,9 @@ func (r *layerStore) ClearFlag(id string, flag string) error { } func (r *layerStore) SetFlag(id string, flag string, value interface{}) error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to set flags on layers at %q", r.layerspath()) + } layer, ok := r.lookup(id) if !ok { return ErrLayerUnknown @@ -349,6 +398,9 @@ func (r *layerStore) Status() ([][2]string, error) { } func (r *layerStore) Put(id, parent string, names []string, mountLabel string, options map[string]string, writeable bool, flags map[string]interface{}, diff archive.Reader) (layer *Layer, size int64, err error) { + if !r.IsReadWrite() { + return nil, -1, errors.Wrapf(ErrStoreIsReadOnly, "not allowed to create new layers at %q", r.layerspath()) + } size = -1 if err := os.MkdirAll(r.rundir, 0700); err != nil { return nil, -1, err @@ -383,15 +435,14 @@ func (r *layerStore) Put(id, parent string, names []string, mountLabel string, o err = r.driver.Create(id, parent, mountLabel, options) } if err == nil { - newLayer := Layer{ + layer = &Layer{ ID: id, Parent: parent, Names: names, MountLabel: mountLabel, Flags: make(map[string]interface{}), } - r.layers = append(r.layers, newLayer) - layer = &r.layers[len(r.layers)-1] + r.layers = append(r.layers, layer) r.idindex.Add(id) r.byid[id] = layer for _, name := range names { @@ -441,6 +492,9 @@ func (r *layerStore) Create(id, parent string, names []string, mountLabel string } func (r *layerStore) Mount(id, mountLabel string) (string, error) { + if !r.IsReadWrite() { + return "", errors.Wrapf(ErrStoreIsReadOnly, "not allowed to update mount locations for layers at %q", r.mountspath()) + } layer, ok := r.lookup(id) if !ok { return "", ErrLayerUnknown @@ -466,6 +520,9 @@ func (r *layerStore) Mount(id, mountLabel string) (string, error) { } func (r *layerStore) Unmount(id string) error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to update mount locations for layers at %q", r.mountspath()) + } layer, ok := r.lookup(id) if !ok { layerByMount, ok := r.bymount[filepath.Clean(id)] @@ -495,6 +552,9 @@ func (r *layerStore) removeName(layer *Layer, name string) { } func (r *layerStore) SetNames(id string, names []string) error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to change layer name assignments at %q", r.layerspath()) + } if layer, ok := r.lookup(id); ok { for _, name := range layer.Names { delete(r.byname, name) @@ -519,6 +579,9 @@ func (r *layerStore) Metadata(id string) (string, error) { } func (r *layerStore) SetMetadata(id, metadata string) error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to modify layer metadata at %q", r.layerspath()) + } if layer, ok := r.lookup(id); ok { layer.Metadata = metadata return r.Save() @@ -531,6 +594,9 @@ func (r *layerStore) tspath(id string) string { } func (r *layerStore) Delete(id string) error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to delete layers at %q", r.layerspath()) + } layer, ok := r.lookup(id) if !ok { return ErrLayerUnknown @@ -549,7 +615,7 @@ func (r *layerStore) Delete(id string) error { if layer.MountPoint != "" { delete(r.bymount, layer.MountPoint) } - newLayers := []Layer{} + newLayers := []*Layer{} for _, candidate := range r.layers { if candidate.ID != id { newLayers = append(newLayers, candidate) @@ -583,6 +649,9 @@ func (r *layerStore) Get(id string) (*Layer, error) { } func (r *layerStore) Wipe() error { + if !r.IsReadWrite() { + return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to delete layers at %q", r.layerspath()) + } ids := []string{} for id := range r.byid { ids = append(ids, id) @@ -822,6 +891,10 @@ func (r *layerStore) Modified() (bool, error) { return r.lockfile.Modified() } +func (r *layerStore) IsReadWrite() bool { + return r.lockfile.IsReadWrite() +} + func (r *layerStore) TouchedSince(when time.Time) bool { return r.lockfile.TouchedSince(when) } diff --git a/vendor/github.com/containers/storage/lockfile.go b/vendor/github.com/containers/storage/lockfile.go index 33f5822f..6e09b526 100644 --- a/vendor/github.com/containers/storage/lockfile.go +++ b/vendor/github.com/containers/storage/lockfile.go @@ -1,14 +1,15 @@ package storage import ( + "fmt" "os" "path/filepath" "sync" "time" - "golang.org/x/sys/unix" - "github.com/containers/storage/pkg/stringid" + "github.com/pkg/errors" + "golang.org/x/sys/unix" ) // A Locker represents a file lock where the file is used to cache an @@ -27,43 +28,80 @@ type Locker interface { // TouchedSince() checks if the most recent writer modified the file (likely using Touch()) after the specified time. TouchedSince(when time.Time) bool + + // IsReadWrite() checks if the lock file is read-write + IsReadWrite() bool } type lockfile struct { - mu sync.Mutex - file string - fd uintptr - lw string + mu sync.Mutex + file string + fd uintptr + lw string + locktype int16 } var ( lockfiles map[string]*lockfile lockfilesLock sync.Mutex + // ErrLockReadOnly indicates that the caller only took a read-only lock, and is not allowed to write + ErrLockReadOnly = errors.New("lock is not a read-write lock") ) -// GetLockfile opens a lock file, creating it if necessary. The Locker object -// return will be returned unlocked. +// GetLockfile opens a read-write lock file, creating it if necessary. The +// Locker object it returns will be returned unlocked. func GetLockfile(path string) (Locker, error) { lockfilesLock.Lock() defer lockfilesLock.Unlock() if lockfiles == nil { lockfiles = make(map[string]*lockfile) } - if locker, ok := lockfiles[filepath.Clean(path)]; ok { + cleanPath := filepath.Clean(path) + if locker, ok := lockfiles[cleanPath]; ok { + if !locker.IsReadWrite() { + return nil, errors.Wrapf(ErrLockReadOnly, "lock %q is a read-only lock", cleanPath) + } return locker, nil } - fd, err := unix.Open(filepath.Clean(path), os.O_RDWR|os.O_CREATE, unix.S_IRUSR|unix.S_IWUSR) + fd, err := unix.Open(cleanPath, os.O_RDWR|os.O_CREATE, unix.S_IRUSR|unix.S_IWUSR) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "error opening %q", cleanPath) } - locker := &lockfile{file: path, fd: uintptr(fd), lw: stringid.GenerateRandomID()} + unix.CloseOnExec(fd) + locker := &lockfile{file: path, fd: uintptr(fd), lw: stringid.GenerateRandomID(), locktype: unix.F_WRLCK} lockfiles[filepath.Clean(path)] = locker return locker, nil } +// GetROLockfile opens a read-only lock file. The Locker object it returns +// will be returned unlocked. +func GetROLockfile(path string) (Locker, error) { + lockfilesLock.Lock() + defer lockfilesLock.Unlock() + if lockfiles == nil { + lockfiles = make(map[string]*lockfile) + } + cleanPath := filepath.Clean(path) + if locker, ok := lockfiles[cleanPath]; ok { + if locker.IsReadWrite() { + return nil, fmt.Errorf("lock %q is a read-write lock", cleanPath) + } + return locker, nil + } + fd, err := unix.Open(cleanPath, os.O_RDONLY, 0) + if err != nil { + return nil, errors.Wrapf(err, "error opening %q", cleanPath) + } + unix.CloseOnExec(fd) + locker := &lockfile{file: path, fd: uintptr(fd), lw: stringid.GenerateRandomID(), locktype: unix.F_RDLCK} + lockfiles[filepath.Clean(path)] = locker + return locker, nil +} + +// Lock locks the lock file func (l *lockfile) Lock() { lk := unix.Flock_t{ - Type: unix.F_WRLCK, + Type: l.locktype, Whence: int16(os.SEEK_SET), Start: 0, Len: 0, @@ -75,6 +113,7 @@ func (l *lockfile) Lock() { } } +// Unlock unlocks the lock file func (l *lockfile) Unlock() { lk := unix.Flock_t{ Type: unix.F_UNLCK, @@ -89,6 +128,7 @@ func (l *lockfile) Unlock() { l.mu.Unlock() } +// Touch updates the lock file with the UID of the user func (l *lockfile) Touch() error { l.lw = stringid.GenerateRandomID() id := []byte(l.lw) @@ -110,6 +150,7 @@ func (l *lockfile) Touch() error { return nil } +// Modified indicates if the lock file has been updated since the last time it was loaded func (l *lockfile) Modified() (bool, error) { id := []byte(l.lw) _, err := unix.Seek(int(l.fd), 0, os.SEEK_SET) @@ -128,6 +169,7 @@ func (l *lockfile) Modified() (bool, error) { return l.lw != lw, nil } +// TouchedSince indicates if the lock file has been touched since the specified time func (l *lockfile) TouchedSince(when time.Time) bool { st := unix.Stat_t{} err := unix.Fstat(int(l.fd), &st) @@ -137,3 +179,8 @@ func (l *lockfile) TouchedSince(when time.Time) bool { touched := time.Unix(statTMtimeUnix(st)) return when.Before(touched) } + +// IsRWLock indicates if the lock file is a read-write lock +func (l *lockfile) IsReadWrite() bool { + return (l.locktype == unix.F_WRLCK) +} diff --git a/vendor/github.com/containers/storage/storageversion/version_lib.go b/vendor/github.com/containers/storage/storageversion/version_lib.go deleted file mode 100644 index 34a531a9..00000000 --- a/vendor/github.com/containers/storage/storageversion/version_lib.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build !containersstorageautogen - -// Package storageversion is auto-generated at build-time -package storageversion - -// Default build-time variable for library-import. -// This file is overridden on build with build-time informations. -const ( - GitCommit string = "library-import" - Version string = "library-import" - BuildTime string = "library-import" - IAmStatic string = "library-import" -) diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go index 5bda69ae..7a2d29db 100644 --- a/vendor/github.com/containers/storage/store.go +++ b/vendor/github.com/containers/storage/store.go @@ -2,7 +2,6 @@ package storage import ( "encoding/base64" - "errors" "fmt" "io" "io/ioutil" @@ -21,7 +20,7 @@ import ( "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/ioutils" "github.com/containers/storage/pkg/stringid" - "github.com/containers/storage/storageversion" + "github.com/pkg/errors" ) var ( @@ -53,43 +52,62 @@ var ( ErrIncompleteOptions = errors.New("missing necessary StoreOptions") // ErrSizeUnknown is returned when the caller asks for the size of a big data item, but the Store couldn't determine the answer. ErrSizeUnknown = errors.New("size is not known") + // ErrStoreIsReadOnly is returned when the caller makes a call to a read-only store that would require modifying its contents. + ErrStoreIsReadOnly = errors.New("called a write method on a read-only store") // DefaultStoreOptions is a reasonable default set of options. DefaultStoreOptions StoreOptions stores []*store storesLock sync.Mutex ) -// FileBasedStore wraps up the most common methods of the various types of file-based -// data stores that we implement. -type FileBasedStore interface { +// ROFileBasedStore wraps up the methods of the various types of file-based +// data stores that we implement which are needed for both read-only and +// read-write files. +type ROFileBasedStore interface { Locker // Load reloads the contents of the store from disk. It should be called // with the lock held. Load() error +} +// RWFileBasedStore wraps up the methods of various types of file-based data +// stores that we implement using read-write files. +type RWFileBasedStore interface { // Save saves the contents of the store to disk. It should be called with // the lock held, and Touch() should be called afterward before releasing the // lock. Save() error } -// MetadataStore wraps up methods for getting and setting metadata associated with IDs. -type MetadataStore interface { +// FileBasedStore wraps up the common methods of various types of file-based +// data stores that we implement. +type FileBasedStore interface { + ROFileBasedStore + RWFileBasedStore +} + +// ROMetadataStore wraps a method for reading metadata associated with an ID. +type ROMetadataStore interface { // Metadata reads metadata associated with an item with the specified ID. Metadata(id string) (string, error) +} +// RWMetadataStore wraps a method for setting metadata associated with an ID. +type RWMetadataStore interface { // SetMetadata updates the metadata associated with the item with the specified ID. SetMetadata(id, metadata string) error } -// A BigDataStore wraps up the most common methods of the various types of -// file-based lookaside stores that we implement. -type BigDataStore interface { - // SetBigData stores a (potentially large) piece of data associated with this - // ID. - SetBigData(id, key string, data []byte) error +// MetadataStore wraps up methods for getting and setting metadata associated with IDs. +type MetadataStore interface { + ROMetadataStore + RWMetadataStore +} +// An ROBigDataStore wraps up the read-only big-data related methods of the +// various types of file-based lookaside stores that we implement. +type ROBigDataStore interface { // BigData retrieves a (potentially large) piece of data associated with // this ID, if it has previously been set. BigData(id, key string) ([]byte, error) @@ -103,6 +121,21 @@ type BigDataStore interface { BigDataNames(id string) ([]string, error) } +// A RWBigDataStore wraps up the read-write big-data related methods of the +// various types of file-based lookaside stores that we implement. +type RWBigDataStore interface { + // SetBigData stores a (potentially large) piece of data associated with this + // ID. + SetBigData(id, key string, data []byte) error +} + +// A BigDataStore wraps up the most common big-data related methods of the +// various types of file-based lookaside stores that we implement. +type BigDataStore interface { + ROBigDataStore + RWBigDataStore +} + // A FlaggableStore can have flags set and cleared on items which it manages. type FlaggableStore interface { // ClearFlag removes a named flag from an item in the store. @@ -149,14 +182,22 @@ type Store interface { // by the Store. GraphDriver() (drivers.Driver, error) - // LayerStore obtains and returns a handle to the layer store object used by + // LayerStore obtains and returns a handle to the writeable layer store object used by // the Store. LayerStore() (LayerStore, error) - // ImageStore obtains and returns a handle to the image store object used by + // ROLayerStore obtains additional read/only layer store objects used by + // the Store. + ROLayerStores() ([]ROLayerStore, error) + + // ImageStore obtains and returns a handle to the writable image store object used by // the Store. ImageStore() (ImageStore, error) + // ROImageStores obtains additional read/only image store objects used by + // the Store. + ROImageStores() ([]ROImageStore, error) + // ContainerStore obtains and returns a handle to the container store object // used by the Store. ContainerStore() (ContainerStore, error) @@ -398,7 +439,9 @@ type store struct { gidMap []idtools.IDMap graphDriver drivers.Driver layerStore LayerStore + roLayerStores []ROLayerStore imageStore ImageStore + roImageStores []ROImageStore containerStore ContainerStore } @@ -514,6 +557,9 @@ func (s *store) load() error { return err } s.layerStore = rls + if _, err := s.ROLayerStores(); err != nil { + return err + } gipath := filepath.Join(s.graphRoot, driverPrefix+"images") if err := os.MkdirAll(gipath, 0700); err != nil { @@ -524,6 +570,10 @@ func (s *store) load() error { return err } s.imageStore = ris + if _, err := s.ROImageStores(); err != nil { + return err + } + gcpath := filepath.Join(s.graphRoot, driverPrefix+"containers") if err := os.MkdirAll(gcpath, 0700); err != nil { return err @@ -596,6 +646,32 @@ func (s *store) LayerStore() (LayerStore, error) { return s.layerStore, nil } +func (s *store) ROLayerStores() ([]ROLayerStore, error) { + s.graphLock.Lock() + defer s.graphLock.Unlock() + if s.roLayerStores != nil { + return s.roLayerStores, nil + } + driver, err := s.getGraphDriver() + if err != nil { + return nil, err + } + driverPrefix := s.graphDriverName + "-" + rlpath := filepath.Join(s.runRoot, driverPrefix+"layers") + if err := os.MkdirAll(rlpath, 0700); err != nil { + return nil, err + } + for _, store := range driver.AdditionalImageStores() { + glpath := filepath.Join(store, driverPrefix+"layers") + rls, err := newROLayerStore(rlpath, glpath, driver) + if err != nil { + return nil, err + } + s.roLayerStores = append(s.roLayerStores, rls) + } + return s.roLayerStores, nil +} + func (s *store) ImageStore() (ImageStore, error) { if s.imageStore != nil { return s.imageStore, nil @@ -603,6 +679,26 @@ func (s *store) ImageStore() (ImageStore, error) { return nil, ErrLoadError } +func (s *store) ROImageStores() ([]ROImageStore, error) { + if len(s.roImageStores) != 0 { + return s.roImageStores, nil + } + driver, err := s.getGraphDriver() + if err != nil { + return nil, err + } + driverPrefix := s.graphDriverName + "-" + for _, store := range driver.AdditionalImageStores() { + gipath := filepath.Join(store, driverPrefix+"images") + ris, err := newROImageStore(gipath) + if err != nil { + return nil, err + } + s.roImageStores = append(s.roImageStores, ris) + } + return s.roImageStores, nil +} + func (s *store) ContainerStore() (ContainerStore, error) { if s.containerStore != nil { return s.containerStore, nil @@ -622,13 +718,11 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w rlstore.Lock() defer rlstore.Unlock() - defer rlstore.Touch() if modified, err := rlstore.Modified(); modified || err != nil { rlstore.Load() } rcstore.Lock() defer rcstore.Unlock() - defer rcstore.Touch() if modified, err := rcstore.Modified(); modified || err != nil { rcstore.Load() } @@ -660,37 +754,45 @@ func (s *store) CreateLayer(id, parent string, names []string, mountLabel string } func (s *store) CreateImage(id string, names []string, layer, metadata string, options *ImageOptions) (*Image, error) { - rlstore, err := s.LayerStore() - if err != nil { - return nil, err - } - ristore, err := s.ImageStore() - if err != nil { - return nil, err - } - rlstore.Lock() - defer rlstore.Unlock() - if modified, err := rlstore.Modified(); modified || err != nil { - rlstore.Load() - } - ristore.Lock() - defer ristore.Unlock() - defer ristore.Touch() - if modified, err := ristore.Modified(); modified || err != nil { - ristore.Load() - } if id == "" { id = stringid.GenerateRandomID() } - ilayer, err := rlstore.Get(layer) + rlstore, err := s.LayerStore() if err != nil { return nil, err } + stores, err := s.ROLayerStores() + if err != nil { + return nil, err + } + stores = append([]ROLayerStore{rlstore}, stores...) + var ilayer *Layer + for _, rlstore := range stores { + rlstore.Lock() + defer rlstore.Unlock() + if modified, err := rlstore.Modified(); modified || err != nil { + rlstore.Load() + } + ilayer, err = rlstore.Get(layer) + if err == nil { + break + } + } if ilayer == nil { return nil, ErrLayerUnknown } layer = ilayer.ID + + ristore, err := s.ImageStore() + if err != nil { + return nil, err + } + ristore.Lock() + defer ristore.Unlock() + if modified, err := ristore.Modified(); modified || err != nil { + ristore.Load() + } return ristore.Create(id, names, layer, metadata) } @@ -699,33 +801,11 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat if err != nil { return nil, err } - ristore, err := s.ImageStore() - if err != nil { - return nil, err - } - rcstore, err := s.ContainerStore() - if err != nil { - return nil, err - } - rlstore.Lock() defer rlstore.Unlock() - defer rlstore.Touch() if modified, err := rlstore.Modified(); modified || err != nil { rlstore.Load() } - ristore.Lock() - defer ristore.Unlock() - if modified, err := ristore.Modified(); modified || err != nil { - ristore.Load() - } - rcstore.Lock() - defer rcstore.Unlock() - defer rcstore.Touch() - if modified, err := rcstore.Modified(); modified || err != nil { - rcstore.Load() - } - if id == "" { id = stringid.GenerateRandomID() } @@ -733,10 +813,27 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat imageTopLayer := "" imageID := "" if image != "" { - cimage, err := ristore.Get(image) + ristore, err := s.ImageStore() if err != nil { return nil, err } + stores, err := s.ROImageStores() + if err != nil { + return nil, err + } + stores = append([]ROImageStore{ristore}, stores...) + var cimage *Image + for _, ristore := range stores { + ristore.Lock() + defer ristore.Unlock() + if modified, err := ristore.Modified(); modified || err != nil { + ristore.Load() + } + cimage, err = ristore.Get(image) + if err == nil { + break + } + } if cimage == nil { return nil, ErrImageUnknown } @@ -748,6 +845,15 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat return nil, err } layer = clayer.ID + rcstore, err := s.ContainerStore() + if err != nil { + return nil, err + } + rcstore.Lock() + defer rcstore.Unlock() + if modified, err := rcstore.Modified(); modified || err != nil { + rcstore.Load() + } container, err := rcstore.Create(id, names, imageID, layer, metadata) if err != nil || container == nil { rlstore.Delete(layer) @@ -786,15 +892,12 @@ func (s *store) SetMetadata(id, metadata string) error { } if rlstore.Exists(id) { - defer rlstore.Touch() return rlstore.SetMetadata(id, metadata) } if ristore.Exists(id) { - defer ristore.Touch() return ristore.SetMetadata(id, metadata) } if rcstore.Exists(id) { - defer rcstore.Touch() return rcstore.SetMetadata(id, metadata) } return ErrNotAnID @@ -805,37 +908,51 @@ func (s *store) Metadata(id string) (string, error) { if err != nil { return "", err } - ristore, err := s.ImageStore() + stores, err := s.ROLayerStores() if err != nil { return "", err } + stores = append([]ROLayerStore{rlstore}, stores...) + for _, rlstore := range stores { + rlstore.Lock() + defer rlstore.Unlock() + if modified, err := rlstore.Modified(); modified || err != nil { + rlstore.Load() + } + if rlstore.Exists(id) { + return rlstore.Metadata(id) + } + } + + istore, err := s.ImageStore() + if err != nil { + return "", err + } + istores, err := s.ROImageStores() + if err != nil { + return "", err + } + istores = append([]ROImageStore{istore}, istores...) + for _, ristore := range istores { + ristore.Lock() + defer ristore.Unlock() + if modified, err := ristore.Modified(); modified || err != nil { + ristore.Load() + } + if ristore.Exists(id) { + return ristore.Metadata(id) + } + } + rcstore, err := s.ContainerStore() if err != nil { return "", err } - - rlstore.Lock() - defer rlstore.Unlock() - if modified, err := rlstore.Modified(); modified || err != nil { - rlstore.Load() - } - ristore.Lock() - defer ristore.Unlock() - if modified, err := ristore.Modified(); modified || err != nil { - ristore.Load() - } rcstore.Lock() defer rcstore.Unlock() if modified, err := rcstore.Modified(); modified || err != nil { rcstore.Load() } - - if rlstore.Exists(id) { - return rlstore.Metadata(id) - } - if ristore.Exists(id) { - return ristore.Metadata(id) - } if rcstore.Exists(id) { return rcstore.Metadata(id) } @@ -847,13 +964,23 @@ func (s *store) ListImageBigData(id string) ([]string, error) { if err != nil { return nil, err } - ristore.Lock() - defer ristore.Unlock() - if modified, err := ristore.Modified(); modified || err != nil { - ristore.Load() + stores, err := s.ROImageStores() + if err != nil { + return nil, err } - - return ristore.BigDataNames(id) + stores = append([]ROImageStore{ristore}, stores...) + for _, ristore := range stores { + ristore.Lock() + defer ristore.Unlock() + if modified, err := ristore.Modified(); modified || err != nil { + ristore.Load() + } + bigDataNames, err := ristore.BigDataNames(id) + if err == nil { + return bigDataNames, err + } + } + return nil, ErrImageUnknown } func (s *store) ImageBigDataSize(id, key string) (int64, error) { @@ -861,13 +988,23 @@ func (s *store) ImageBigDataSize(id, key string) (int64, error) { if err != nil { return -1, err } - ristore.Lock() - defer ristore.Unlock() - if modified, err := ristore.Modified(); modified || err != nil { - ristore.Load() + stores, err := s.ROImageStores() + if err != nil { + return -1, err } - - return ristore.BigDataSize(id, key) + stores = append([]ROImageStore{ristore}, stores...) + for _, ristore := range stores { + ristore.Lock() + defer ristore.Unlock() + if modified, err := ristore.Modified(); modified || err != nil { + ristore.Load() + } + size, err := ristore.BigDataSize(id, key) + if err == nil { + return size, nil + } + } + return -1, ErrSizeUnknown } func (s *store) ImageBigData(id, key string) ([]byte, error) { @@ -875,30 +1012,32 @@ func (s *store) ImageBigData(id, key string) ([]byte, error) { if err != nil { return nil, err } - ristore.Lock() - defer ristore.Unlock() - if modified, err := ristore.Modified(); modified || err != nil { - ristore.Load() + stores, err := s.ROImageStores() + if err != nil { + return nil, err + } + stores = append([]ROImageStore{ristore}, stores...) + for _, ristore := range stores { + ristore.Lock() + defer ristore.Unlock() + if modified, err := ristore.Modified(); modified || err != nil { + ristore.Load() + } + data, err := ristore.BigData(id, key) + if err == nil { + return data, nil + } } - return ristore.BigData(id, key) + return nil, ErrImageUnknown } func (s *store) SetImageBigData(id, key string, data []byte) error { - rlstore, err := s.LayerStore() - if err != nil { - return err - } ristore, err := s.ImageStore() if err != nil { return err } - rlstore.Lock() - defer rlstore.Unlock() - if modified, err := rlstore.Modified(); modified || err != nil { - rlstore.Load() - } ristore.Lock() defer ristore.Unlock() if modified, err := ristore.Modified(); modified || err != nil { @@ -966,74 +1105,63 @@ func (s *store) SetContainerBigData(id, key string, data []byte) error { } func (s *store) Exists(id string) bool { - rcstore, err := s.ContainerStore() + lstore, err := s.LayerStore() if err != nil { return false } + lstores, err := s.ROLayerStores() + if err != nil { + return false + } + lstores = append([]ROLayerStore{lstore}, lstores...) + for _, rlstore := range lstores { + rlstore.Lock() + defer rlstore.Unlock() + if modified, err := rlstore.Modified(); modified || err != nil { + rlstore.Load() + } + if rlstore.Exists(id) { + return true + } + } + ristore, err := s.ImageStore() if err != nil { return false } - rlstore, err := s.LayerStore() + stores, err := s.ROImageStores() if err != nil { return false } - - rlstore.Lock() - defer rlstore.Unlock() - if modified, err := rlstore.Modified(); modified || err != nil { - rlstore.Load() + stores = append([]ROImageStore{ristore}, stores...) + for _, ristore := range stores { + ristore.Lock() + defer ristore.Unlock() + if modified, err := ristore.Modified(); modified || err != nil { + ristore.Load() + } + if ristore.Exists(id) { + return true + } } - ristore.Lock() - defer ristore.Unlock() - if modified, err := ristore.Modified(); modified || err != nil { - ristore.Load() + + rcstore, err := s.ContainerStore() + if err != nil { + return false } rcstore.Lock() defer rcstore.Unlock() if modified, err := rcstore.Modified(); modified || err != nil { rcstore.Load() } - if rcstore.Exists(id) { return true } - if ristore.Exists(id) { - return true - } - return rlstore.Exists(id) + + return false } func (s *store) SetNames(id string, names []string) error { - rcstore, err := s.ContainerStore() - if err != nil { - return err - } - ristore, err := s.ImageStore() - if err != nil { - return err - } - rlstore, err := s.LayerStore() - if err != nil { - return err - } - - rlstore.Lock() - defer rlstore.Unlock() - if modified, err := rlstore.Modified(); modified || err != nil { - rlstore.Load() - } - ristore.Lock() - defer ristore.Unlock() - if modified, err := ristore.Modified(); modified || err != nil { - ristore.Load() - } - rcstore.Lock() - defer rcstore.Unlock() - if modified, err := rcstore.Modified(); modified || err != nil { - rcstore.Load() - } - deduped := []string{} seen := make(map[string]bool) for _, name := range names { @@ -1043,12 +1171,41 @@ func (s *store) SetNames(id string, names []string) error { } } + rlstore, err := s.LayerStore() + if err != nil { + return err + } + rlstore.Lock() + defer rlstore.Unlock() + if modified, err := rlstore.Modified(); modified || err != nil { + rlstore.Load() + } if rlstore.Exists(id) { return rlstore.SetNames(id, deduped) } + + ristore, err := s.ImageStore() + if err != nil { + return err + } + ristore.Lock() + defer ristore.Unlock() + if modified, err := ristore.Modified(); modified || err != nil { + ristore.Load() + } if ristore.Exists(id) { return ristore.SetNames(id, deduped) } + + rcstore, err := s.ContainerStore() + if err != nil { + return err + } + rcstore.Lock() + defer rcstore.Unlock() + if modified, err := rcstore.Modified(); modified || err != nil { + rcstore.Load() + } if rcstore.Exists(id) { return rcstore.SetNames(id, deduped) } @@ -1056,41 +1213,55 @@ func (s *store) SetNames(id string, names []string) error { } func (s *store) Names(id string) ([]string, error) { - rcstore, err := s.ContainerStore() - if err != nil { - return nil, err - } - ristore, err := s.ImageStore() - if err != nil { - return nil, err - } rlstore, err := s.LayerStore() if err != nil { return nil, err } - - rlstore.Lock() - defer rlstore.Unlock() - if modified, err := rlstore.Modified(); modified || err != nil { - rlstore.Load() + stores, err := s.ROLayerStores() + if err != nil { + return nil, err } - ristore.Lock() - defer ristore.Unlock() - if modified, err := ristore.Modified(); modified || err != nil { - ristore.Load() + stores = append([]ROLayerStore{rlstore}, stores...) + for _, rlstore := range stores { + rlstore.Lock() + defer rlstore.Unlock() + if modified, err := rlstore.Modified(); modified || err != nil { + rlstore.Load() + } + if l, err := rlstore.Get(id); l != nil && err == nil { + return l.Names, nil + } + } + + ristore, err := s.ImageStore() + if err != nil { + return nil, err + } + ristores, err := s.ROImageStores() + if err != nil { + return nil, err + } + ristores = append([]ROImageStore{ristore}, ristores...) + for _, ristore := range stores { + ristore.Lock() + defer ristore.Unlock() + if modified, err := ristore.Modified(); modified || err != nil { + ristore.Load() + } + if i, err := ristore.Get(id); i != nil && err == nil { + return i.Names, nil + } + } + + rcstore, err := s.ContainerStore() + if err != nil { + return nil, err } rcstore.Lock() defer rcstore.Unlock() if modified, err := rcstore.Modified(); modified || err != nil { rcstore.Load() } - - if l, err := rlstore.Get(id); l != nil && err == nil { - return l.Names, nil - } - if i, err := ristore.Get(id); i != nil && err == nil { - return i.Names, nil - } if c, err := rcstore.Get(id); c != nil && err == nil { return c.Names, nil } @@ -1170,8 +1341,6 @@ func (s *store) DeleteLayer(id string) error { } if rlstore.Exists(id) { - defer rlstore.Touch() - defer rcstore.Touch() if l, err := rlstore.Get(id); err != nil { id = l.ID } @@ -1190,7 +1359,7 @@ func (s *store) DeleteLayer(id string) error { } for _, image := range images { if image.TopLayer == id { - return ErrLayerUsedByImage + return errors.Wrapf(ErrLayerUsedByImage, "Layer %v used by image %v", id, image.ID) } } containers, err := rcstore.Containers() @@ -1199,7 +1368,7 @@ func (s *store) DeleteLayer(id string) error { } for _, container := range containers { if container.LayerID == id { - return ErrLayerUsedByContainer + return errors.Wrapf(ErrLayerUsedByContainer, "Layer %v used by container %v", id, container.ID) } } return rlstore.Delete(id) @@ -1243,8 +1412,6 @@ func (s *store) DeleteImage(id string, commit bool) (layers []string, err error) return nil, err } id = image.ID - defer rlstore.Touch() - defer ristore.Touch() containers, err := rcstore.Containers() if err != nil { return nil, err @@ -1253,8 +1420,8 @@ func (s *store) DeleteImage(id string, commit bool) (layers []string, err error) for _, container := range containers { aContainerByImage[container.ImageID] = container.ID } - if _, ok := aContainerByImage[id]; ok { - return nil, ErrImageUsedByContainer + if container, ok := aContainerByImage[id]; ok { + return nil, errors.Wrapf(ErrImageUsedByContainer, "Image used by %v", container) } images, err := ristore.Images() if err != nil { @@ -1358,8 +1525,6 @@ func (s *store) DeleteContainer(id string) error { } if rcstore.Exists(id) { - defer rlstore.Touch() - defer rcstore.Touch() if container, err := rcstore.Get(id); err == nil { if rlstore.Exists(container.LayerID) { if err = rlstore.Delete(container.LayerID); err != nil { @@ -1416,8 +1581,6 @@ func (s *store) Delete(id string) error { } if rcstore.Exists(id) { - defer rlstore.Touch() - defer rcstore.Touch() if container, err := rcstore.Get(id); err == nil { if rlstore.Exists(container.LayerID) { if err = rlstore.Delete(container.LayerID); err != nil { @@ -1441,11 +1604,9 @@ func (s *store) Delete(id string) error { } } if ristore.Exists(id) { - defer ristore.Touch() return ristore.Delete(id) } if rlstore.Exists(id) { - defer rlstore.Touch() return rlstore.Delete(id) } return ErrLayerUnknown @@ -1467,19 +1628,16 @@ func (s *store) Wipe() error { rlstore.Lock() defer rlstore.Unlock() - defer rlstore.Touch() if modified, err := rlstore.Modified(); modified || err != nil { rlstore.Load() } ristore.Lock() defer ristore.Unlock() - defer ristore.Touch() if modified, err := ristore.Modified(); modified || err != nil { ristore.Load() } rcstore.Lock() defer rcstore.Unlock() - defer rcstore.Touch() if modified, err := rcstore.Modified(); modified || err != nil { rcstore.Load() } @@ -1502,67 +1660,45 @@ func (s *store) Status() ([][2]string, error) { } func (s *store) Version() ([][2]string, error) { - return [][2]string{ - {"GitCommit", storageversion.GitCommit}, - {"Version", storageversion.Version}, - {"BuildTime", storageversion.BuildTime}, - }, nil + return [][2]string{}, nil } func (s *store) Mount(id, mountLabel string) (string, error) { - rcstore, err := s.ContainerStore() - if err != nil { - return "", err + if layerID, err := s.ContainerLayerID(id); err == nil { + id = layerID } rlstore, err := s.LayerStore() if err != nil { return "", err } - rlstore.Lock() defer rlstore.Unlock() - defer rlstore.Touch() if modified, err := rlstore.Modified(); modified || err != nil { rlstore.Load() } - rcstore.Lock() - defer rcstore.Unlock() - if modified, err := rcstore.Modified(); modified || err != nil { - rcstore.Load() + if rlstore.Exists(id) { + return rlstore.Mount(id, mountLabel) } - - if c, err := rcstore.Get(id); c != nil && err == nil { - id = c.LayerID - } - return rlstore.Mount(id, mountLabel) + return "", ErrLayerUnknown } func (s *store) Unmount(id string) error { - rcstore, err := s.ContainerStore() - if err != nil { - return err + if layerID, err := s.ContainerLayerID(id); err == nil { + id = layerID } rlstore, err := s.LayerStore() if err != nil { return err } - rlstore.Lock() defer rlstore.Unlock() - defer rlstore.Touch() if modified, err := rlstore.Modified(); modified || err != nil { rlstore.Load() } - rcstore.Lock() - defer rcstore.Unlock() - if modified, err := rcstore.Modified(); modified || err != nil { - rcstore.Load() + if rlstore.Exists(id) { + return rlstore.Unmount(id) } - - if c, err := rcstore.Get(id); c != nil && err == nil { - id = c.LayerID - } - return rlstore.Unmount(id) + return ErrLayerUnknown } func (s *store) Changes(from, to string) ([]archive.Change, error) { @@ -1570,14 +1706,22 @@ func (s *store) Changes(from, to string) ([]archive.Change, error) { if err != nil { return nil, err } - - rlstore.Lock() - defer rlstore.Unlock() - if modified, err := rlstore.Modified(); modified || err != nil { - rlstore.Load() + stores, err := s.ROLayerStores() + if err != nil { + return nil, err } - - return rlstore.Changes(from, to) + stores = append([]ROLayerStore{rlstore}, stores...) + for _, rlstore := range stores { + rlstore.Lock() + defer rlstore.Unlock() + if modified, err := rlstore.Modified(); modified || err != nil { + rlstore.Load() + } + if rlstore.Exists(to) { + return rlstore.Changes(from, to) + } + } + return nil, ErrLayerUnknown } func (s *store) DiffSize(from, to string) (int64, error) { @@ -1585,14 +1729,22 @@ func (s *store) DiffSize(from, to string) (int64, error) { if err != nil { return -1, err } - - rlstore.Lock() - defer rlstore.Unlock() - if modified, err := rlstore.Modified(); modified || err != nil { - rlstore.Load() + stores, err := s.ROLayerStores() + if err != nil { + return -1, err } - - return rlstore.DiffSize(from, to) + stores = append([]ROLayerStore{rlstore}, stores...) + for _, rlstore := range stores { + rlstore.Lock() + defer rlstore.Unlock() + if modified, err := rlstore.Modified(); modified || err != nil { + rlstore.Load() + } + if rlstore.Exists(to) { + return rlstore.DiffSize(from, to) + } + } + return -1, ErrLayerUnknown } func (s *store) Diff(from, to string) (io.ReadCloser, error) { @@ -1600,14 +1752,22 @@ func (s *store) Diff(from, to string) (io.ReadCloser, error) { if err != nil { return nil, err } - - rlstore.Lock() - defer rlstore.Unlock() - if modified, err := rlstore.Modified(); modified || err != nil { - rlstore.Load() + stores, err := s.ROLayerStores() + if err != nil { + return nil, err } - - return rlstore.Diff(from, to) + stores = append([]ROLayerStore{rlstore}, stores...) + for _, rlstore := range stores { + rlstore.Lock() + defer rlstore.Unlock() + if modified, err := rlstore.Modified(); modified || err != nil { + rlstore.Load() + } + if rlstore.Exists(to) { + return rlstore.Diff(from, to) + } + } + return nil, ErrLayerUnknown } func (s *store) ApplyDiff(to string, diff archive.Reader) (int64, error) { @@ -1615,43 +1775,70 @@ func (s *store) ApplyDiff(to string, diff archive.Reader) (int64, error) { if err != nil { return -1, err } - rlstore.Lock() defer rlstore.Unlock() if modified, err := rlstore.Modified(); modified || err != nil { rlstore.Load() } - - return rlstore.ApplyDiff(to, diff) + if rlstore.Exists(to) { + return rlstore.ApplyDiff(to, diff) + } + return -1, ErrLayerUnknown } func (s *store) Layers() ([]Layer, error) { + var layers []Layer rlstore, err := s.LayerStore() if err != nil { return nil, err } - rlstore.Lock() - defer rlstore.Unlock() - if modified, err := rlstore.Modified(); modified || err != nil { - rlstore.Load() + stores, err := s.ROLayerStores() + if err != nil { + return nil, err } + stores = append([]ROLayerStore{rlstore}, stores...) - return rlstore.Layers() + for _, rlstore := range stores { + rlstore.Lock() + defer rlstore.Unlock() + if modified, err := rlstore.Modified(); modified || err != nil { + rlstore.Load() + } + slayers, err := rlstore.Layers() + if err != nil { + return nil, err + } + layers = append(layers, slayers...) + } + return layers, nil } func (s *store) Images() ([]Image, error) { + var images []Image ristore, err := s.ImageStore() if err != nil { return nil, err } - ristore.Lock() - defer ristore.Unlock() - if modified, err := ristore.Modified(); modified || err != nil { - ristore.Load() - } - return ristore.Images() + stores, err := s.ROImageStores() + if err != nil { + return nil, err + } + stores = append([]ROImageStore{ristore}, stores...) + for _, ristore := range stores { + ristore.Lock() + defer ristore.Unlock() + if modified, err := ristore.Modified(); modified || err != nil { + ristore.Load() + } + simages, err := ristore.Images() + if err != nil { + return nil, err + } + images = append(images, simages...) + } + return images, nil } func (s *store) Containers() ([]Container, error) { @@ -1675,13 +1862,24 @@ func (s *store) Layer(id string) (*Layer, error) { return nil, err } - rlstore.Lock() - defer rlstore.Unlock() - if modified, err := rlstore.Modified(); modified || err != nil { - rlstore.Load() + stores, err := s.ROLayerStores() + if err != nil { + return nil, err } + stores = append([]ROLayerStore{rlstore}, stores...) - return rlstore.Get(id) + for _, rlstore := range stores { + rlstore.Lock() + defer rlstore.Unlock() + if modified, err := rlstore.Modified(); modified || err != nil { + rlstore.Load() + } + layer, err := rlstore.Get(id) + if err == nil { + return layer, nil + } + } + return nil, ErrLayerUnknown } func (s *store) Image(id string) (*Image, error) { @@ -1689,51 +1887,58 @@ func (s *store) Image(id string) (*Image, error) { if err != nil { return nil, err } - ristore.Lock() - defer ristore.Unlock() - if modified, err := ristore.Modified(); modified || err != nil { - ristore.Load() + stores, err := s.ROImageStores() + if err != nil { + return nil, err } - - return ristore.Get(id) + stores = append([]ROImageStore{ristore}, stores...) + for _, ristore := range stores { + ristore.Lock() + defer ristore.Unlock() + if modified, err := ristore.Modified(); modified || err != nil { + ristore.Load() + } + image, err := ristore.Get(id) + if err == nil { + return image, nil + } + } + return nil, ErrImageUnknown } func (s *store) ImagesByTopLayer(id string) ([]*Image, error) { + images := []*Image{} + layer, err := s.Layer(id) + if err != nil { + return nil, err + } + ristore, err := s.ImageStore() if err != nil { return nil, err } - rlstore, err := s.LayerStore() - if err != nil { - return nil, err - } - rlstore.Lock() - defer rlstore.Unlock() - if modified, err := rlstore.Modified(); modified || err != nil { - rlstore.Load() - } - ristore.Lock() - defer ristore.Unlock() - if modified, err := ristore.Modified(); modified || err != nil { - ristore.Load() - } - - layer, err := rlstore.Get(id) + stores, err := s.ROImageStores() if err != nil { return nil, err } - images := []*Image{} - imageList, err := ristore.Images() - if err != nil { - return nil, err - } - for _, image := range imageList { - if image.TopLayer == layer.ID { - images = append(images, &image) + stores = append([]ROImageStore{ristore}, stores...) + for _, ristore := range stores { + ristore.Lock() + defer ristore.Unlock() + if modified, err := ristore.Modified(); modified || err != nil { + ristore.Load() + } + imageList, err := ristore.Images() + if err != nil { + return nil, err + } + for _, image := range imageList { + if image.TopLayer == layer.ID { + images = append(images, &image) + } } } - return images, nil } @@ -1751,8 +1956,25 @@ func (s *store) Container(id string) (*Container, error) { return rcstore.Get(id) } +func (s *store) ContainerLayerID(id string) (string, error) { + rcstore, err := s.ContainerStore() + if err != nil { + return "", err + } + rcstore.Lock() + defer rcstore.Unlock() + if modified, err := rcstore.Modified(); modified || err != nil { + rcstore.Load() + } + container, err := rcstore.Get(id) + if err != nil { + return "", err + } + return container.LayerID, nil +} + func (s *store) ContainerByLayer(id string) (*Container, error) { - rlstore, err := s.LayerStore() + layer, err := s.Layer(id) if err != nil { return nil, err } @@ -1760,22 +1982,11 @@ func (s *store) ContainerByLayer(id string) (*Container, error) { if err != nil { return nil, err } - - rlstore.Lock() - defer rlstore.Unlock() - if modified, err := rlstore.Modified(); modified || err != nil { - rlstore.Load() - } rcstore.Lock() defer rcstore.Unlock() if modified, err := rcstore.Modified(); modified || err != nil { rcstore.Load() } - - layer, err := rlstore.Get(id) - if err != nil { - return nil, err - } containerList, err := rcstore.Containers() if err != nil { return nil, err @@ -1918,7 +2129,7 @@ func (s *store) Shutdown(force bool) ([]string, error) { } } if len(mounted) > 0 && err == nil { - err = ErrLayerUsedByContainer + err = errors.Wrap(ErrLayerUsedByContainer, "A layer is mounted") } if err == nil { err = s.graphDriver.Cleanup() diff --git a/vendor/github.com/containers/storage/vendor.conf b/vendor/github.com/containers/storage/vendor.conf new file mode 100644 index 00000000..99895dfd --- /dev/null +++ b/vendor/github.com/containers/storage/vendor.conf @@ -0,0 +1,19 @@ +github.com/BurntSushi/toml master +github.com/Microsoft/go-winio 307e919c663683a9000576fdc855acaf9534c165 +github.com/Microsoft/hcsshim 0f615c198a84e0344b4ed49c464d8833d4648dfc +github.com/Sirupsen/logrus 61e43dc76f7ee59a82bdf3d71033dc12bea4c77d +github.com/docker/engine-api 4290f40c056686fcaa5c9caf02eac1dde9315adf +github.com/docker/go-connections eb315e36415380e7c2fdee175262560ff42359da +github.com/docker/go-units 0dadbb0345b35ec7ef35e228dabb8de89a65bf52 +github.com/go-check/check 20d25e2804050c1cd24a7eea1e7a6447dd0e74ec +github.com/mattn/go-shellwords 753a2322a99f87c0eff284980e77f53041555bc6 +github.com/mistifyio/go-zfs c0224de804d438efd11ea6e52ada8014537d6062 +github.com/opencontainers/runc 6c22e77604689db8725fa866f0f2ec0b3e8c3a07 +github.com/opencontainers/selinux ba1aefe8057f1d0cfb8e88d0ec1dc85925ef987d +github.com/pborman/uuid 1b00554d822231195d1babd97ff4a781231955c9 +github.com/pkg/errors master +github.com/tchap/go-patricia v2.2.6 +github.com/vbatts/tar-split bd4c5d64c3e9297f410025a3b1bd0c58f659e721 +github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 +golang.org/x/net f2499483f923065a842d38eb4c7f1927e6fc6e6d +golang.org/x/sys d75a52659825e75fff6158388dddc6a5b04f9ba5