ecd0006e80
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
2198 lines
56 KiB
Go
2198 lines
56 KiB
Go
package storage
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"errors"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
// register all of the built-in drivers
|
|
_ "github.com/containers/storage/drivers/register"
|
|
|
|
drivers "github.com/containers/storage/drivers"
|
|
"github.com/containers/storage/pkg/archive"
|
|
"github.com/containers/storage/pkg/idtools"
|
|
"github.com/containers/storage/pkg/ioutils"
|
|
"github.com/containers/storage/pkg/stringid"
|
|
"github.com/containers/storage/storageversion"
|
|
)
|
|
|
|
var (
|
|
// ErrLoadError indicates that there was an initialization error.
|
|
ErrLoadError = errors.New("error loading storage metadata")
|
|
// ErrDuplicateID indicates that an ID which is to be assigned to a new item is already being used.
|
|
ErrDuplicateID = errors.New("that ID is already in use")
|
|
// ErrDuplicateName indicates that a name which is to be assigned to a new item is already being used.
|
|
ErrDuplicateName = errors.New("that name is already in use")
|
|
// ErrParentIsContainer is returned when a caller attempts to create a layer as a child of a container's layer.
|
|
ErrParentIsContainer = errors.New("would-be parent layer is a container")
|
|
// ErrNotAContainer is returned when the caller attempts to delete a container that isn't a container.
|
|
ErrNotAContainer = errors.New("identifier is not a container")
|
|
// ErrNotAnImage is returned when the caller attempts to delete an image that isn't an image.
|
|
ErrNotAnImage = errors.New("identifier is not an image")
|
|
// ErrNotALayer is returned when the caller attempts to delete a layer that isn't a layer.
|
|
ErrNotALayer = errors.New("identifier is not a layer")
|
|
// ErrNotAnID is returned when the caller attempts to read or write metadata from an item that doesn't exist.
|
|
ErrNotAnID = errors.New("identifier is not a layer, image, or container")
|
|
// ErrLayerHasChildren is returned when the caller attempts to delete a layer that has children.
|
|
ErrLayerHasChildren = errors.New("layer has children")
|
|
// ErrLayerUsedByImage is returned when the caller attempts to delete a layer that is an image's top layer.
|
|
ErrLayerUsedByImage = errors.New("layer is in use by an image")
|
|
// ErrLayerUsedByContainer is returned when the caller attempts to delete a layer that is a container's layer.
|
|
ErrLayerUsedByContainer = errors.New("layer is in use by a container")
|
|
// ErrImageUsedByContainer is returned when the caller attempts to delete an image that is a container's image.
|
|
ErrImageUsedByContainer = errors.New("image is in use by a container")
|
|
// ErrIncompleteOptions is returned when the caller attempts to initialize a Store without providing required information.
|
|
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")
|
|
// 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 {
|
|
Locker
|
|
|
|
// Load reloads the contents of the store from disk. It should be called
|
|
// with the lock held.
|
|
Load() error
|
|
|
|
// 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 {
|
|
// Metadata reads metadata associated with an item with the specified ID.
|
|
Metadata(id string) (string, error)
|
|
|
|
// 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
|
|
|
|
// BigData retrieves a (potentially large) piece of data associated with
|
|
// this ID, if it has previously been set.
|
|
BigData(id, key string) ([]byte, error)
|
|
|
|
// BigDataSize retrieves the size of a (potentially large) piece of
|
|
// data associated with this ID, if it has previously been set.
|
|
BigDataSize(id, key string) (int64, error)
|
|
|
|
// BigDataNames() returns a list of the names of previously-stored pieces of
|
|
// data.
|
|
BigDataNames(id string) ([]string, error)
|
|
}
|
|
|
|
// 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.
|
|
ClearFlag(id string, flag string) error
|
|
|
|
// SetFlag sets a named flag and its value on an item in the store.
|
|
SetFlag(id string, flag string, value interface{}) error
|
|
}
|
|
|
|
// StoreOptions is used for passing initialization options to GetStore(), for
|
|
// initializing a Store object and the underlying storage that it controls.
|
|
type StoreOptions struct {
|
|
// RunRoot is the filesystem path under which we can store run-time
|
|
// information, such as the locations of active mount points, that we
|
|
// want to lose if the host is rebooted.
|
|
RunRoot string `json:"runroot,omitempty"`
|
|
// GraphRoot is the filesystem path under which we will store the
|
|
// contents of layers, images, and containers.
|
|
GraphRoot string `json:"root,omitempty"`
|
|
// GraphDriverName is the underlying storage driver that we'll be
|
|
// using. It only needs to be specified the first time a Store is
|
|
// initialized for a given RunRoot and GraphRoot.
|
|
GraphDriverName string `json:"driver,omitempty"`
|
|
// GraphDriverOptions are driver-specific options.
|
|
GraphDriverOptions []string `json:"driver-options,omitempty"`
|
|
// UIDMap and GIDMap are used mainly for deciding on the ownership of
|
|
// files in layers as they're stored on disk, which is often necessary
|
|
// when user namespaces are being used.
|
|
UIDMap []idtools.IDMap `json:"uidmap,omitempty"`
|
|
GIDMap []idtools.IDMap `json:"gidmap,omitempty"`
|
|
}
|
|
|
|
// Store wraps up the various types of file-based stores that we use into a
|
|
// singleton object that initializes and manages them all together.
|
|
type Store interface {
|
|
// RunRoot, GraphRoot, GraphDriverName, and GraphOptions retrieve
|
|
// settings that were passed to GetStore() when the object was created.
|
|
RunRoot() string
|
|
GraphRoot() string
|
|
GraphDriverName() string
|
|
GraphOptions() []string
|
|
|
|
// GraphDriver obtains and returns a handle to the graph Driver object used
|
|
// by the Store.
|
|
GraphDriver() (drivers.Driver, error)
|
|
|
|
// LayerStore obtains and returns a handle to the layer store object used by
|
|
// the Store.
|
|
LayerStore() (LayerStore, error)
|
|
|
|
// ImageStore obtains and returns a handle to the image store object used by
|
|
// the Store.
|
|
ImageStore() (ImageStore, error)
|
|
|
|
// ContainerStore obtains and returns a handle to the container store object
|
|
// used by the Store.
|
|
ContainerStore() (ContainerStore, error)
|
|
|
|
// CreateLayer creates a new layer in the underlying storage driver, optionally
|
|
// having the specified ID (one will be assigned if none is specified), with
|
|
// the specified layer (or no layer) as its parent, and with optional names.
|
|
// (The writeable flag is ignored.)
|
|
CreateLayer(id, parent string, names []string, mountLabel string, writeable bool) (*Layer, error)
|
|
|
|
// PutLayer combines the functions of CreateLayer and ApplyDiff, marking the
|
|
// layer for automatic removal if applying the diff fails for any reason.
|
|
PutLayer(id, parent string, names []string, mountLabel string, writeable bool, diff archive.Reader) (*Layer, int64, error)
|
|
|
|
// CreateImage creates a new image, optionally with the specified ID
|
|
// (one will be assigned if none is specified), with optional names,
|
|
// referring to a specified image, and with optional metadata. An
|
|
// image is a record which associates the ID of a layer with a
|
|
// additional bookkeeping information which the library stores for the
|
|
// convenience of its caller.
|
|
CreateImage(id string, names []string, layer, metadata string, options *ImageOptions) (*Image, error)
|
|
|
|
// CreateContainer creates a new container, optionally with the specified ID
|
|
// (one will be assigned if none is specified), with optional names,
|
|
// using the specified image's top layer as the basis for the
|
|
// container's layer, and assigning the specified ID to that layer (one
|
|
// will be created if none is specified). A container is a layer which
|
|
// is associated with additional bookkeeping information which the
|
|
// library stores for the convenience of its caller.
|
|
CreateContainer(id string, names []string, image, layer, metadata string, options *ContainerOptions) (*Container, error)
|
|
|
|
// Metadata retrieves the metadata which is associated with a layer, image,
|
|
// or container (whichever the passed-in ID refers to).
|
|
Metadata(id string) (string, error)
|
|
|
|
// SetMetadata updates the metadata which is associated with a layer, image, or
|
|
// container (whichever the passed-in ID refers to) to match the specified
|
|
// value. The metadata value can be retrieved at any time using Metadata,
|
|
// or using Layer, Image, or Container and reading the object directly.
|
|
SetMetadata(id, metadata string) error
|
|
|
|
// Exists checks if there is a layer, image, or container which has the
|
|
// passed-in ID or name.
|
|
Exists(id string) bool
|
|
|
|
// Status asks for a status report, in the form of key-value pairs, from the
|
|
// underlying storage driver. The contents vary from driver to driver.
|
|
Status() ([][2]string, error)
|
|
|
|
// Delete removes the layer, image, or container which has the passed-in ID or
|
|
// name. Note that no safety checks are performed, so this can leave images
|
|
// with references to layers which do not exist, and layers with references to
|
|
// parents which no longer exist.
|
|
Delete(id string) error
|
|
|
|
// DeleteLayer attempts to remove the specified layer. If the layer is the
|
|
// parent of any other layer, or is referred to by any images, it will return
|
|
// an error.
|
|
DeleteLayer(id string) error
|
|
|
|
// DeleteImage removes the specified image if it is not referred to by
|
|
// any containers. If its top layer is then no longer referred to by
|
|
// any other images and is not the parent of any other layers, its top
|
|
// layer will be removed. If that layer's parent is no longer referred
|
|
// to by any other images and is not the parent of any other layers,
|
|
// then it, too, will be removed. This procedure will be repeated
|
|
// until a layer which should not be removed, or the base layer, is
|
|
// reached, at which point the list of removed layers is returned. If
|
|
// the commit argument is false, the image and layers are not removed,
|
|
// but the list of layers which would be removed is still returned.
|
|
DeleteImage(id string, commit bool) (layers []string, err error)
|
|
|
|
// DeleteContainer removes the specified container and its layer. If there is
|
|
// no matching container, or if the container exists but its layer does not, an
|
|
// error will be returned.
|
|
DeleteContainer(id string) error
|
|
|
|
// Wipe removes all known layers, images, and containers.
|
|
Wipe() error
|
|
|
|
// Mount attempts to mount a layer, image, or container for access, and returns
|
|
// the pathname if it succeeds.
|
|
Mount(id, mountLabel string) (string, error)
|
|
|
|
// Unmount attempts to unmount a layer, image, or container, given an ID, a
|
|
// name, or a mount path.
|
|
Unmount(id string) error
|
|
|
|
// Changes returns a summary of the changes which would need to be made to one
|
|
// layer to make its contents the same as a second layer. If the first layer
|
|
// is not specified, the second layer's parent is assumed. Each Change
|
|
// structure contains a Path relative to the layer's root directory, and a Kind
|
|
// which is either ChangeAdd, ChangeModify, or ChangeDelete.
|
|
Changes(from, to string) ([]archive.Change, error)
|
|
|
|
// DiffSize returns a count of the size of the tarstream which would specify
|
|
// the changes returned by Changes.
|
|
DiffSize(from, to string) (int64, error)
|
|
|
|
// Diff returns the tarstream which would specify the changes returned by
|
|
// Changes.
|
|
Diff(from, to string) (io.ReadCloser, error)
|
|
|
|
// ApplyDiff applies a tarstream to a layer. Information about the tarstream
|
|
// is cached with the layer. Typically, a layer which is populated using a
|
|
// tarstream will be expected to not be modified in any other way, either
|
|
// before or after the diff is applied.
|
|
ApplyDiff(to string, diff archive.Reader) (int64, error)
|
|
|
|
// Layers returns a list of the currently known layers.
|
|
Layers() ([]Layer, error)
|
|
|
|
// Images returns a list of the currently known images.
|
|
Images() ([]Image, error)
|
|
|
|
// Containers returns a list of the currently known containers.
|
|
Containers() ([]Container, error)
|
|
|
|
// Names returns the list of names for a layer, image, or container.
|
|
Names(id string) ([]string, error)
|
|
|
|
// SetNames changes the list of names for a layer, image, or container.
|
|
SetNames(id string, names []string) error
|
|
|
|
// ListImageBigData retrieves a list of the (possibly large) chunks of named
|
|
// data associated with an image.
|
|
ListImageBigData(id string) ([]string, error)
|
|
|
|
// ImageBigData retrieves a (possibly large) chunk of named data associated
|
|
// with an image.
|
|
ImageBigData(id, key string) ([]byte, error)
|
|
|
|
// ImageBigDataSize retrieves the size of a (possibly large) chunk
|
|
// of named data associated with an image.
|
|
ImageBigDataSize(id, key string) (int64, error)
|
|
|
|
// SetImageBigData stores a (possibly large) chunk of named data associated
|
|
// with an image.
|
|
SetImageBigData(id, key string, data []byte) error
|
|
|
|
// ListContainerBigData retrieves a list of the (possibly large) chunks of
|
|
// named data associated with a container.
|
|
ListContainerBigData(id string) ([]string, error)
|
|
|
|
// ContainerBigData retrieves a (possibly large) chunk of named data
|
|
// associated with a container.
|
|
ContainerBigData(id, key string) ([]byte, error)
|
|
|
|
// ContainerBigDataSize retrieves the size of a (possibly large)
|
|
// chunk of named data associated with a container.
|
|
ContainerBigDataSize(id, key string) (int64, error)
|
|
|
|
// SetContainerBigData stores a (possibly large) chunk of named data
|
|
// associated with a container.
|
|
SetContainerBigData(id, key string, data []byte) error
|
|
|
|
// Layer returns a specific layer.
|
|
Layer(id string) (*Layer, error)
|
|
|
|
// Image returns a specific image.
|
|
Image(id string) (*Image, error)
|
|
|
|
// ImagesByTopLayer returns a list of images which reference the specified
|
|
// layer as their top layer. They will have different IDs and names
|
|
// and may have different metadata, big data items, and flags.
|
|
ImagesByTopLayer(id string) ([]*Image, error)
|
|
|
|
// Container returns a specific container.
|
|
Container(id string) (*Container, error)
|
|
|
|
// ContainerByLayer returns a specific container based on its layer ID or
|
|
// name.
|
|
ContainerByLayer(id string) (*Container, error)
|
|
|
|
// ContainerDirectory returns a path of a directory which the caller
|
|
// can use to store data, specific to the container, which the library
|
|
// does not directly manage. The directory will be deleted when the
|
|
// container is deleted.
|
|
ContainerDirectory(id string) (string, error)
|
|
|
|
// SetContainerDirectoryFile is a convenience function which stores
|
|
// a piece of data in the specified file relative to the container's
|
|
// directory.
|
|
SetContainerDirectoryFile(id, file string, data []byte) error
|
|
|
|
// FromContainerDirectory is a convenience function which reads
|
|
// the contents of the specified file relative to the container's
|
|
// directory.
|
|
FromContainerDirectory(id, file string) ([]byte, error)
|
|
|
|
// ContainerRunDirectory returns a path of a directory which the
|
|
// caller can use to store data, specific to the container, which the
|
|
// library does not directly manage. The directory will be deleted
|
|
// when the host system is restarted.
|
|
ContainerRunDirectory(id string) (string, error)
|
|
|
|
// SetContainerRunDirectoryFile is a convenience function which stores
|
|
// a piece of data in the specified file relative to the container's
|
|
// run directory.
|
|
SetContainerRunDirectoryFile(id, file string, data []byte) error
|
|
|
|
// FromContainerRunDirectory is a convenience function which reads
|
|
// the contents of the specified file relative to the container's run
|
|
// directory.
|
|
FromContainerRunDirectory(id, file string) ([]byte, error)
|
|
|
|
// Lookup returns the ID of a layer, image, or container with the specified
|
|
// name or ID.
|
|
Lookup(name string) (string, error)
|
|
|
|
// Shutdown attempts to free any kernel resources which are being used
|
|
// by the underlying driver. If "force" is true, any mounted (i.e., in
|
|
// use) layers are unmounted beforehand. If "force" is not true, then
|
|
// layers being in use is considered to be an error condition. A list
|
|
// of still-mounted layers is returned along with possible errors.
|
|
Shutdown(force bool) (layers []string, err error)
|
|
|
|
// Version returns version information, in the form of key-value pairs, from
|
|
// the storage package.
|
|
Version() ([][2]string, error)
|
|
}
|
|
|
|
// ImageOptions is used for passing options to a Store's CreateImage() method.
|
|
type ImageOptions struct {
|
|
}
|
|
|
|
// ContainerOptions is used for passing options to a Store's CreateContainer() method.
|
|
type ContainerOptions struct {
|
|
}
|
|
|
|
type store struct {
|
|
lastLoaded time.Time
|
|
runRoot string
|
|
graphLock Locker
|
|
graphRoot string
|
|
graphDriverName string
|
|
graphOptions []string
|
|
uidMap []idtools.IDMap
|
|
gidMap []idtools.IDMap
|
|
graphDriver drivers.Driver
|
|
layerStore LayerStore
|
|
imageStore ImageStore
|
|
containerStore ContainerStore
|
|
}
|
|
|
|
// GetStore attempts to find an already-created Store object matching the
|
|
// specified location and graph driver, and if it can't, it creates and
|
|
// initializes a new Store object, and the underlying storage that it controls.
|
|
func GetStore(options StoreOptions) (Store, error) {
|
|
if options.RunRoot == "" && options.GraphRoot == "" && options.GraphDriverName == "" && len(options.GraphDriverOptions) == 0 {
|
|
options = DefaultStoreOptions
|
|
}
|
|
|
|
if options.GraphRoot != "" {
|
|
options.GraphRoot = filepath.Clean(options.GraphRoot)
|
|
}
|
|
if options.RunRoot != "" {
|
|
options.RunRoot = filepath.Clean(options.RunRoot)
|
|
}
|
|
|
|
storesLock.Lock()
|
|
defer storesLock.Unlock()
|
|
|
|
for _, s := range stores {
|
|
if s.graphRoot == options.GraphRoot && (options.GraphDriverName == "" || s.graphDriverName == options.GraphDriverName) {
|
|
return s, nil
|
|
}
|
|
}
|
|
|
|
if options.GraphRoot == "" {
|
|
return nil, ErrIncompleteOptions
|
|
}
|
|
if options.RunRoot == "" {
|
|
return nil, ErrIncompleteOptions
|
|
}
|
|
|
|
if err := os.MkdirAll(options.RunRoot, 0700); err != nil && !os.IsExist(err) {
|
|
return nil, err
|
|
}
|
|
for _, subdir := range []string{} {
|
|
if err := os.MkdirAll(filepath.Join(options.RunRoot, subdir), 0700); err != nil && !os.IsExist(err) {
|
|
return nil, err
|
|
}
|
|
}
|
|
if err := os.MkdirAll(options.GraphRoot, 0700); err != nil && !os.IsExist(err) {
|
|
return nil, err
|
|
}
|
|
for _, subdir := range []string{"mounts", "tmp", options.GraphDriverName} {
|
|
if err := os.MkdirAll(filepath.Join(options.GraphRoot, subdir), 0700); err != nil && !os.IsExist(err) {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
graphLock, err := GetLockfile(filepath.Join(options.GraphRoot, "storage.lock"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s := &store{
|
|
runRoot: options.RunRoot,
|
|
graphLock: graphLock,
|
|
graphRoot: options.GraphRoot,
|
|
graphDriverName: options.GraphDriverName,
|
|
graphOptions: options.GraphDriverOptions,
|
|
uidMap: copyIDMap(options.UIDMap),
|
|
gidMap: copyIDMap(options.GIDMap),
|
|
}
|
|
if err := s.load(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
stores = append(stores, s)
|
|
|
|
return s, nil
|
|
}
|
|
|
|
func copyIDMap(idmap []idtools.IDMap) []idtools.IDMap {
|
|
m := []idtools.IDMap{}
|
|
if idmap != nil {
|
|
m = make([]idtools.IDMap, len(idmap))
|
|
copy(m, idmap)
|
|
}
|
|
if len(m) > 0 {
|
|
return m[:]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *store) RunRoot() string {
|
|
return s.runRoot
|
|
}
|
|
|
|
func (s *store) GraphDriverName() string {
|
|
return s.graphDriverName
|
|
}
|
|
|
|
func (s *store) GraphRoot() string {
|
|
return s.graphRoot
|
|
}
|
|
|
|
func (s *store) GraphOptions() []string {
|
|
return s.graphOptions
|
|
}
|
|
|
|
func (s *store) load() error {
|
|
driver, err := s.GraphDriver()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.graphDriver = driver
|
|
s.graphDriverName = driver.String()
|
|
driverPrefix := s.graphDriverName + "-"
|
|
|
|
rls, err := s.LayerStore()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.layerStore = rls
|
|
|
|
gipath := filepath.Join(s.graphRoot, driverPrefix+"images")
|
|
if err := os.MkdirAll(gipath, 0700); err != nil {
|
|
return err
|
|
}
|
|
ris, err := newImageStore(gipath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.imageStore = ris
|
|
gcpath := filepath.Join(s.graphRoot, driverPrefix+"containers")
|
|
if err := os.MkdirAll(gcpath, 0700); err != nil {
|
|
return err
|
|
}
|
|
rcs, err := newContainerStore(gcpath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rcpath := filepath.Join(s.runRoot, driverPrefix+"containers")
|
|
if err := os.MkdirAll(rcpath, 0700); err != nil {
|
|
return err
|
|
}
|
|
s.containerStore = rcs
|
|
return nil
|
|
}
|
|
|
|
func (s *store) getGraphDriver() (drivers.Driver, error) {
|
|
if s.graphDriver != nil {
|
|
return s.graphDriver, nil
|
|
}
|
|
driver, err := drivers.New(s.graphRoot, s.graphDriverName, s.graphOptions, s.uidMap, s.gidMap)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s.graphDriver = driver
|
|
s.graphDriverName = driver.String()
|
|
return driver, nil
|
|
}
|
|
|
|
func (s *store) GraphDriver() (drivers.Driver, error) {
|
|
s.graphLock.Lock()
|
|
defer s.graphLock.Unlock()
|
|
if s.graphLock.TouchedSince(s.lastLoaded) {
|
|
s.graphDriver = nil
|
|
s.layerStore = nil
|
|
s.lastLoaded = time.Now()
|
|
}
|
|
return s.getGraphDriver()
|
|
}
|
|
|
|
func (s *store) LayerStore() (LayerStore, error) {
|
|
s.graphLock.Lock()
|
|
defer s.graphLock.Unlock()
|
|
if s.graphLock.TouchedSince(s.lastLoaded) {
|
|
s.graphDriver = nil
|
|
s.layerStore = nil
|
|
s.lastLoaded = time.Now()
|
|
}
|
|
if s.layerStore != nil {
|
|
return s.layerStore, 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
|
|
}
|
|
glpath := filepath.Join(s.graphRoot, driverPrefix+"layers")
|
|
if err := os.MkdirAll(glpath, 0700); err != nil {
|
|
return nil, err
|
|
}
|
|
rls, err := newLayerStore(rlpath, glpath, driver)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s.layerStore = rls
|
|
return s.layerStore, nil
|
|
}
|
|
|
|
func (s *store) ImageStore() (ImageStore, error) {
|
|
if s.imageStore != nil {
|
|
return s.imageStore, nil
|
|
}
|
|
return nil, ErrLoadError
|
|
}
|
|
|
|
func (s *store) ContainerStore() (ContainerStore, error) {
|
|
if s.containerStore != nil {
|
|
return s.containerStore, nil
|
|
}
|
|
return nil, ErrLoadError
|
|
}
|
|
|
|
func (s *store) PutLayer(id, parent string, names []string, mountLabel string, writeable bool, diff archive.Reader) (*Layer, int64, error) {
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return nil, -1, err
|
|
}
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return nil, -1, err
|
|
}
|
|
rcstore, err := s.ContainerStore()
|
|
if err != nil {
|
|
return nil, -1, err
|
|
}
|
|
|
|
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()
|
|
}
|
|
if id == "" {
|
|
id = stringid.GenerateRandomID()
|
|
}
|
|
if parent != "" {
|
|
if l, err := rlstore.Get(parent); err == nil && l != nil {
|
|
parent = l.ID
|
|
} else {
|
|
return nil, -1, ErrLayerUnknown
|
|
}
|
|
containers, err := rcstore.Containers()
|
|
if err != nil {
|
|
return nil, -1, err
|
|
}
|
|
for _, container := range containers {
|
|
if container.LayerID == parent {
|
|
return nil, -1, ErrParentIsContainer
|
|
}
|
|
}
|
|
}
|
|
return rlstore.Put(id, parent, names, mountLabel, nil, writeable, nil, diff)
|
|
}
|
|
|
|
func (s *store) CreateLayer(id, parent string, names []string, mountLabel string, writeable bool) (*Layer, error) {
|
|
layer, _, err := s.PutLayer(id, parent, names, mountLabel, writeable, nil)
|
|
return layer, err
|
|
}
|
|
|
|
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
|
|
}
|
|
rcstore, err := s.ContainerStore()
|
|
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()
|
|
}
|
|
rcstore.Lock()
|
|
defer rcstore.Unlock()
|
|
defer rcstore.Touch()
|
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
|
rcstore.Load()
|
|
}
|
|
if id == "" {
|
|
id = stringid.GenerateRandomID()
|
|
}
|
|
|
|
ilayer, err := rlstore.Get(layer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if ilayer == nil {
|
|
return nil, ErrLayerUnknown
|
|
}
|
|
layer = ilayer.ID
|
|
return ristore.Create(id, names, layer, metadata)
|
|
}
|
|
|
|
func (s *store) CreateContainer(id string, names []string, image, layer, metadata string, options *ContainerOptions) (*Container, error) {
|
|
rlstore, err := s.LayerStore()
|
|
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()
|
|
}
|
|
|
|
imageTopLayer := ""
|
|
imageID := ""
|
|
if image != "" {
|
|
cimage, err := ristore.Get(image)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if cimage == nil {
|
|
return nil, ErrImageUnknown
|
|
}
|
|
imageTopLayer = cimage.TopLayer
|
|
imageID = cimage.ID
|
|
}
|
|
clayer, err := rlstore.Create(layer, imageTopLayer, nil, "", nil, true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
layer = clayer.ID
|
|
container, err := rcstore.Create(id, names, imageID, layer, metadata)
|
|
if err != nil || container == nil {
|
|
rlstore.Delete(layer)
|
|
}
|
|
return container, err
|
|
}
|
|
|
|
func (s *store) SetMetadata(id, metadata string) error {
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
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) {
|
|
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
|
|
}
|
|
|
|
func (s *store) Metadata(id string) (string, error) {
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
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)
|
|
}
|
|
return "", ErrNotAnID
|
|
}
|
|
|
|
func (s *store) ListImageBigData(id string) ([]string, 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()
|
|
if modified, err := ristore.Modified(); modified || err != nil {
|
|
ristore.Load()
|
|
}
|
|
|
|
return ristore.BigDataNames(id)
|
|
}
|
|
|
|
func (s *store) ImageBigDataSize(id, key string) (int64, error) {
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return -1, 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()
|
|
}
|
|
|
|
return ristore.BigDataSize(id, key)
|
|
}
|
|
|
|
func (s *store) ImageBigData(id, key string) ([]byte, 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()
|
|
if modified, err := ristore.Modified(); modified || err != nil {
|
|
ristore.Load()
|
|
}
|
|
|
|
return ristore.BigData(id, key)
|
|
}
|
|
|
|
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 {
|
|
ristore.Load()
|
|
}
|
|
|
|
return ristore.SetBigData(id, key, data)
|
|
}
|
|
|
|
func (s *store) ListContainerBigData(id string) ([]string, error) {
|
|
rlstore, err := s.LayerStore()
|
|
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()
|
|
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()
|
|
}
|
|
|
|
return rcstore.BigDataNames(id)
|
|
}
|
|
|
|
func (s *store) ContainerBigDataSize(id, key string) (int64, error) {
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
rcstore, err := s.ContainerStore()
|
|
if err != nil {
|
|
return -1, 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()
|
|
}
|
|
|
|
return rcstore.BigDataSize(id, key)
|
|
}
|
|
|
|
func (s *store) ContainerBigData(id, key string) ([]byte, error) {
|
|
rlstore, err := s.LayerStore()
|
|
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()
|
|
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()
|
|
}
|
|
|
|
return rcstore.BigData(id, key)
|
|
}
|
|
|
|
func (s *store) SetContainerBigData(id, key string, data []byte) error {
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
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()
|
|
}
|
|
|
|
return rcstore.SetBigData(id, key, data)
|
|
}
|
|
|
|
func (s *store) Exists(id string) bool {
|
|
rcstore, err := s.ContainerStore()
|
|
if err != nil {
|
|
return false
|
|
}
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return false
|
|
}
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
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 rcstore.Exists(id) {
|
|
return true
|
|
}
|
|
if ristore.Exists(id) {
|
|
return true
|
|
}
|
|
return rlstore.Exists(id)
|
|
}
|
|
|
|
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 {
|
|
if _, wasSeen := seen[name]; !wasSeen {
|
|
seen[name] = true
|
|
deduped = append(deduped, name)
|
|
}
|
|
}
|
|
|
|
if rlstore.Exists(id) {
|
|
return rlstore.SetNames(id, deduped)
|
|
}
|
|
if ristore.Exists(id) {
|
|
return ristore.SetNames(id, deduped)
|
|
}
|
|
if rcstore.Exists(id) {
|
|
return rcstore.SetNames(id, deduped)
|
|
}
|
|
return ErrLayerUnknown
|
|
}
|
|
|
|
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()
|
|
}
|
|
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 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
|
|
}
|
|
return nil, ErrLayerUnknown
|
|
}
|
|
|
|
func (s *store) Lookup(name string) (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()
|
|
}
|
|
|
|
if l, err := rlstore.Get(name); l != nil && err == nil {
|
|
return l.ID, nil
|
|
}
|
|
if i, err := ristore.Get(name); i != nil && err == nil {
|
|
return i.ID, nil
|
|
}
|
|
if c, err := rcstore.Get(name); c != nil && err == nil {
|
|
return c.ID, nil
|
|
}
|
|
return "", ErrLayerUnknown
|
|
}
|
|
|
|
func (s *store) DeleteLayer(id string) error {
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
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) {
|
|
defer rlstore.Touch()
|
|
defer rcstore.Touch()
|
|
if l, err := rlstore.Get(id); err != nil {
|
|
id = l.ID
|
|
}
|
|
layers, err := rlstore.Layers()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, layer := range layers {
|
|
if layer.Parent == id {
|
|
return ErrLayerHasChildren
|
|
}
|
|
}
|
|
images, err := ristore.Images()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, image := range images {
|
|
if image.TopLayer == id {
|
|
return ErrLayerUsedByImage
|
|
}
|
|
}
|
|
containers, err := rcstore.Containers()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, container := range containers {
|
|
if container.LayerID == id {
|
|
return ErrLayerUsedByContainer
|
|
}
|
|
}
|
|
return rlstore.Delete(id)
|
|
}
|
|
return ErrNotALayer
|
|
}
|
|
|
|
func (s *store) DeleteImage(id string, commit bool) (layers []string, err error) {
|
|
rlstore, err := s.LayerStore()
|
|
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()
|
|
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()
|
|
}
|
|
layersToRemove := []string{}
|
|
if ristore.Exists(id) {
|
|
image, err := ristore.Get(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
id = image.ID
|
|
defer rlstore.Touch()
|
|
defer ristore.Touch()
|
|
containers, err := rcstore.Containers()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
aContainerByImage := make(map[string]string)
|
|
for _, container := range containers {
|
|
aContainerByImage[container.ImageID] = container.ID
|
|
}
|
|
if _, ok := aContainerByImage[id]; ok {
|
|
return nil, ErrImageUsedByContainer
|
|
}
|
|
images, err := ristore.Images()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
layers, err := rlstore.Layers()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
childrenByParent := make(map[string]*[]string)
|
|
for _, layer := range layers {
|
|
parent := layer.Parent
|
|
if list, ok := childrenByParent[parent]; ok {
|
|
newList := append(*list, layer.ID)
|
|
childrenByParent[parent] = &newList
|
|
} else {
|
|
childrenByParent[parent] = &([]string{layer.ID})
|
|
}
|
|
}
|
|
anyImageByTopLayer := make(map[string]string)
|
|
for _, img := range images {
|
|
if img.ID != id {
|
|
anyImageByTopLayer[img.TopLayer] = img.ID
|
|
}
|
|
}
|
|
if commit {
|
|
if err = ristore.Delete(id); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
layer := image.TopLayer
|
|
lastRemoved := ""
|
|
for layer != "" {
|
|
if rcstore.Exists(layer) {
|
|
break
|
|
}
|
|
if _, ok := anyImageByTopLayer[layer]; ok {
|
|
break
|
|
}
|
|
parent := ""
|
|
if l, err := rlstore.Get(layer); err == nil {
|
|
parent = l.Parent
|
|
}
|
|
otherRefs := 0
|
|
if childList, ok := childrenByParent[layer]; ok && childList != nil {
|
|
children := *childList
|
|
for _, child := range children {
|
|
if child != lastRemoved {
|
|
otherRefs++
|
|
}
|
|
}
|
|
}
|
|
if otherRefs != 0 {
|
|
break
|
|
}
|
|
lastRemoved = layer
|
|
layersToRemove = append(layersToRemove, lastRemoved)
|
|
layer = parent
|
|
}
|
|
} else {
|
|
return nil, ErrNotAnImage
|
|
}
|
|
if commit {
|
|
for _, layer := range layersToRemove {
|
|
if err = rlstore.Delete(layer); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
return layersToRemove, nil
|
|
}
|
|
|
|
func (s *store) DeleteContainer(id string) error {
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
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 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 {
|
|
return err
|
|
}
|
|
if err = rcstore.Delete(id); err != nil {
|
|
return err
|
|
}
|
|
middleDir := s.graphDriverName + "-containers"
|
|
gcpath := filepath.Join(s.GraphRoot(), middleDir, container.ID)
|
|
if err = os.RemoveAll(gcpath); err != nil {
|
|
return err
|
|
}
|
|
rcpath := filepath.Join(s.RunRoot(), middleDir, container.ID)
|
|
if err = os.RemoveAll(rcpath); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
return ErrNotALayer
|
|
}
|
|
}
|
|
return ErrNotAContainer
|
|
}
|
|
|
|
func (s *store) Delete(id string) error {
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
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 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 {
|
|
return err
|
|
}
|
|
if err = rcstore.Delete(id); err != nil {
|
|
return err
|
|
}
|
|
middleDir := s.graphDriverName + "-containers"
|
|
gcpath := filepath.Join(s.GraphRoot(), middleDir, container.ID, "userdata")
|
|
if err = os.RemoveAll(gcpath); err != nil {
|
|
return err
|
|
}
|
|
rcpath := filepath.Join(s.RunRoot(), middleDir, container.ID, "userdata")
|
|
if err = os.RemoveAll(rcpath); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
return ErrNotALayer
|
|
}
|
|
}
|
|
if ristore.Exists(id) {
|
|
defer ristore.Touch()
|
|
return ristore.Delete(id)
|
|
}
|
|
if rlstore.Exists(id) {
|
|
defer rlstore.Touch()
|
|
return rlstore.Delete(id)
|
|
}
|
|
return ErrLayerUnknown
|
|
}
|
|
|
|
func (s *store) Wipe() 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()
|
|
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()
|
|
}
|
|
|
|
if err = rcstore.Wipe(); err != nil {
|
|
return err
|
|
}
|
|
if err = ristore.Wipe(); err != nil {
|
|
return err
|
|
}
|
|
return rlstore.Wipe()
|
|
}
|
|
|
|
func (s *store) Status() ([][2]string, error) {
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return rlstore.Status()
|
|
}
|
|
|
|
func (s *store) Version() ([][2]string, error) {
|
|
return [][2]string{
|
|
{"GitCommit", storageversion.GitCommit},
|
|
{"Version", storageversion.Version},
|
|
{"BuildTime", storageversion.BuildTime},
|
|
}, nil
|
|
}
|
|
|
|
func (s *store) Mount(id, mountLabel string) (string, error) {
|
|
rcstore, err := s.ContainerStore()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
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 c, err := rcstore.Get(id); c != nil && err == nil {
|
|
id = c.LayerID
|
|
}
|
|
return rlstore.Mount(id, mountLabel)
|
|
}
|
|
|
|
func (s *store) Unmount(id string) error {
|
|
rcstore, err := s.ContainerStore()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
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 c, err := rcstore.Get(id); c != nil && err == nil {
|
|
id = c.LayerID
|
|
}
|
|
return rlstore.Unmount(id)
|
|
}
|
|
|
|
func (s *store) Changes(from, to string) ([]archive.Change, error) {
|
|
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()
|
|
}
|
|
|
|
return rlstore.Changes(from, to)
|
|
}
|
|
|
|
func (s *store) DiffSize(from, to string) (int64, error) {
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
|
|
rlstore.Lock()
|
|
defer rlstore.Unlock()
|
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
|
rlstore.Load()
|
|
}
|
|
|
|
return rlstore.DiffSize(from, to)
|
|
}
|
|
|
|
func (s *store) Diff(from, to string) (io.ReadCloser, error) {
|
|
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()
|
|
}
|
|
|
|
return rlstore.Diff(from, to)
|
|
}
|
|
|
|
func (s *store) ApplyDiff(to string, diff archive.Reader) (int64, error) {
|
|
rlstore, err := s.LayerStore()
|
|
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)
|
|
}
|
|
|
|
func (s *store) Layers() ([]Layer, error) {
|
|
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()
|
|
}
|
|
|
|
return rlstore.Layers()
|
|
}
|
|
|
|
func (s *store) Images() ([]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()
|
|
if modified, err := ristore.Modified(); modified || err != nil {
|
|
ristore.Load()
|
|
}
|
|
|
|
return ristore.Images()
|
|
}
|
|
|
|
func (s *store) Containers() ([]Container, error) {
|
|
rlstore, err := s.LayerStore()
|
|
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()
|
|
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()
|
|
}
|
|
|
|
return rcstore.Containers()
|
|
}
|
|
|
|
func (s *store) Layer(id string) (*Layer, error) {
|
|
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()
|
|
}
|
|
|
|
return rlstore.Get(id)
|
|
}
|
|
|
|
func (s *store) Image(id string) (*Image, error) {
|
|
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()
|
|
}
|
|
|
|
return ristore.Get(id)
|
|
}
|
|
|
|
func (s *store) ImagesByTopLayer(id string) ([]*Image, error) {
|
|
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)
|
|
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)
|
|
}
|
|
}
|
|
|
|
return images, nil
|
|
}
|
|
|
|
func (s *store) Container(id string) (*Container, error) {
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rcstore, err := s.ContainerStore()
|
|
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()
|
|
}
|
|
rcstore.Lock()
|
|
defer rcstore.Unlock()
|
|
if modified, err := rcstore.Modified(); modified || err != nil {
|
|
rcstore.Load()
|
|
}
|
|
|
|
return rcstore.Get(id)
|
|
}
|
|
|
|
func (s *store) ContainerByLayer(id string) (*Container, error) {
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rcstore, err := s.ContainerStore()
|
|
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()
|
|
}
|
|
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
|
|
}
|
|
for _, container := range containerList {
|
|
if container.LayerID == layer.ID {
|
|
return &container, nil
|
|
}
|
|
}
|
|
|
|
return nil, ErrContainerUnknown
|
|
}
|
|
|
|
func (s *store) ContainerDirectory(id string) (string, error) {
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
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()
|
|
}
|
|
|
|
id, err = rcstore.Lookup(id)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
middleDir := s.graphDriverName + "-containers"
|
|
gcpath := filepath.Join(s.GraphRoot(), middleDir, id, "userdata")
|
|
if err := os.MkdirAll(gcpath, 0700); err != nil {
|
|
return "", err
|
|
}
|
|
return gcpath, nil
|
|
}
|
|
|
|
func (s *store) ContainerRunDirectory(id string) (string, error) {
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
ristore, err := s.ImageStore()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
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()
|
|
}
|
|
|
|
id, err = rcstore.Lookup(id)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
middleDir := s.graphDriverName + "-containers"
|
|
rcpath := filepath.Join(s.RunRoot(), middleDir, id, "userdata")
|
|
if err := os.MkdirAll(rcpath, 0700); err != nil {
|
|
return "", err
|
|
}
|
|
return rcpath, nil
|
|
}
|
|
|
|
func (s *store) SetContainerDirectoryFile(id, file string, data []byte) error {
|
|
dir, err := s.ContainerDirectory(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = os.MkdirAll(filepath.Dir(filepath.Join(dir, file)), 0700)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return ioutils.AtomicWriteFile(filepath.Join(dir, file), data, 0600)
|
|
}
|
|
|
|
func (s *store) FromContainerDirectory(id, file string) ([]byte, error) {
|
|
dir, err := s.ContainerDirectory(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return ioutil.ReadFile(filepath.Join(dir, file))
|
|
}
|
|
|
|
func (s *store) SetContainerRunDirectoryFile(id, file string, data []byte) error {
|
|
dir, err := s.ContainerRunDirectory(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = os.MkdirAll(filepath.Dir(filepath.Join(dir, file)), 0700)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return ioutils.AtomicWriteFile(filepath.Join(dir, file), data, 0600)
|
|
}
|
|
|
|
func (s *store) FromContainerRunDirectory(id, file string) ([]byte, error) {
|
|
dir, err := s.ContainerRunDirectory(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return ioutil.ReadFile(filepath.Join(dir, file))
|
|
}
|
|
|
|
func (s *store) Shutdown(force bool) ([]string, error) {
|
|
mounted := []string{}
|
|
modified := false
|
|
|
|
rlstore, err := s.LayerStore()
|
|
if err != nil {
|
|
return mounted, err
|
|
}
|
|
|
|
rlstore.Lock()
|
|
defer rlstore.Unlock()
|
|
if modified, err := rlstore.Modified(); modified || err != nil {
|
|
rlstore.Load()
|
|
}
|
|
|
|
s.graphLock.Lock()
|
|
defer s.graphLock.Unlock()
|
|
layers, err := rlstore.Layers()
|
|
if err != nil {
|
|
return mounted, err
|
|
}
|
|
for _, layer := range layers {
|
|
if layer.MountCount == 0 {
|
|
continue
|
|
}
|
|
mounted = append(mounted, layer.ID)
|
|
if force {
|
|
for layer.MountCount > 0 {
|
|
err2 := rlstore.Unmount(layer.ID)
|
|
if err2 != nil {
|
|
if err == nil {
|
|
err = err2
|
|
}
|
|
break
|
|
}
|
|
modified = true
|
|
}
|
|
}
|
|
}
|
|
if len(mounted) > 0 && err == nil {
|
|
err = ErrLayerUsedByContainer
|
|
}
|
|
if err == nil {
|
|
err = s.graphDriver.Cleanup()
|
|
s.graphLock.Touch()
|
|
modified = true
|
|
}
|
|
if modified {
|
|
rlstore.Touch()
|
|
}
|
|
return mounted, err
|
|
}
|
|
|
|
// Convert a BigData key name into an acceptable file name.
|
|
func makeBigDataBaseName(key string) string {
|
|
reader := strings.NewReader(key)
|
|
for reader.Len() > 0 {
|
|
ch, size, err := reader.ReadRune()
|
|
if err != nil || size != 1 {
|
|
break
|
|
}
|
|
if ch != '.' && !(ch >= '0' && ch <= '9') && !(ch >= 'a' && ch <= 'z') {
|
|
break
|
|
}
|
|
}
|
|
if reader.Len() > 0 {
|
|
return "=" + base64.StdEncoding.EncodeToString([]byte(key))
|
|
}
|
|
return key
|
|
}
|
|
|
|
func stringSliceWithoutValue(slice []string, value string) []string {
|
|
modified := []string{}
|
|
for _, v := range slice {
|
|
if v == value {
|
|
continue
|
|
}
|
|
modified = append(modified, v)
|
|
}
|
|
return modified
|
|
}
|
|
|
|
func init() {
|
|
DefaultStoreOptions.RunRoot = "/var/run/containers/storage"
|
|
DefaultStoreOptions.GraphRoot = "/var/lib/containers/storage"
|
|
DefaultStoreOptions.GraphDriverName = os.Getenv("STORAGE_DRIVER")
|
|
DefaultStoreOptions.GraphDriverOptions = strings.Split(os.Getenv("STORAGE_OPTS"), ",")
|
|
if len(DefaultStoreOptions.GraphDriverOptions) == 1 && DefaultStoreOptions.GraphDriverOptions[0] == "" {
|
|
DefaultStoreOptions.GraphDriverOptions = nil
|
|
}
|
|
}
|