2013-11-04 01:54:51 +00:00
package graphdriver
2013-10-31 18:07:54 -07:00
2013-11-04 15:22:34 -08:00
import (
2014-03-27 17:41:06 +01:00
"errors"
2013-11-04 15:22:34 -08:00
"fmt"
2013-11-19 03:13:22 -08:00
"os"
2015-04-24 12:35:51 -07:00
"path/filepath"
2014-11-16 02:54:21 +09:00
"strings"
2014-06-05 12:50:53 -07:00
2015-03-26 23:22:04 +01:00
"github.com/Sirupsen/logrus"
2015-06-30 09:00:02 -07:00
"github.com/docker/docker/autogen/dockerversion"
2014-09-29 23:23:36 -07:00
"github.com/docker/docker/pkg/archive"
2013-11-04 15:22:34 -08:00
)
2015-01-09 02:22:38 +02:00
type FsMagic uint32
2014-06-02 19:26:41 -06:00
const (
2015-01-15 16:40:39 -05:00
FsMagicUnsupported = FsMagic ( 0x00000000 )
)
var (
DefaultDriver string
// All registred drivers
drivers map [ string ] InitFunc
2015-06-30 09:00:02 -07:00
ErrNotSupported = errors . New ( "driver not supported" )
ErrPrerequisites = errors . New ( "prerequisites for driver not satisfied (wrong filesystem?)" )
ErrIncompatibleFS = fmt . Errorf ( "backing file system is unsupported for this graph driver" )
ErrDeviceMapperWithStaticDocker = fmt . Errorf ( "devicemapper storage driver cannot reliably be used with a statically linked docker binary: please either pick a different storage driver, install a dynamically linked docker binary, or force this unreliable setup anyway by specifying --storage-driver=devicemapper" )
2014-06-02 19:26:41 -06:00
)
2014-06-05 10:34:20 +02:00
type InitFunc func ( root string , options [ ] string ) ( Driver , error )
2013-11-04 20:51:12 -08:00
2014-09-16 12:13:50 -07:00
// ProtoDriver defines the basic capabilities of a driver.
// This interface exists solely to be a minimum set of methods
// for client code which choose not to implement the entire Driver
// interface and use the NaiveDiffDriver wrapper constructor.
//
// Use of ProtoDriver directly by client code is not recommended.
type ProtoDriver interface {
2014-09-10 20:30:52 -07:00
// String returns a string representation of this driver.
2013-11-15 10:24:48 +01:00
String ( ) string
2014-09-10 20:30:52 -07:00
// Create creates a new, empty, filesystem layer with the
// specified id and parent. Parent may be "".
2014-04-17 23:47:27 +00:00
Create ( id , parent string ) error
2014-09-16 12:13:50 -07:00
// Remove attempts to remove the filesystem layer with this id.
2013-11-07 20:34:01 +00:00
Remove ( id string ) error
2014-09-10 20:30:52 -07:00
// Get returns the mountpoint for the layered filesystem referred
// to by this id. You can optionally specify a mountLabel or "".
// Returns the absolute path to the mounted layered filesystem.
2014-04-17 23:47:27 +00:00
Get ( id , mountLabel string ) ( dir string , err error )
2014-09-10 20:30:52 -07:00
// Put releases the system resources for the specified id,
// e.g, unmounting layered filesystem.
2015-01-09 17:14:52 -05:00
Put ( id string ) error
2014-09-10 20:30:52 -07:00
// Exists returns whether a filesystem layer with the specified
// ID exists on this driver.
2013-11-19 02:32:08 -08:00
Exists ( id string ) bool
2014-09-10 20:30:52 -07:00
// Status returns a set of key-value pairs which give low
// level diagnostic status about this driver.
2013-11-15 11:04:02 +01:00
Status ( ) [ ] [ 2 ] string
2015-06-15 14:05:10 -04:00
// Returns a set of key-value pairs which give low level information
// about the image/container driver is managing.
GetMetadata ( id string ) ( map [ string ] string , error )
2014-09-10 20:30:52 -07:00
// Cleanup performs necessary tasks to release resources
// held by the driver, e.g., unmounting all layered filesystems
// known to this driver.
2013-11-11 17:17:38 -08:00
Cleanup ( ) error
}
2014-09-16 12:13:50 -07:00
// Driver is the interface for layered/snapshot file system drivers.
2014-09-10 20:30:52 -07:00
type Driver interface {
2014-09-16 12:13:50 -07:00
ProtoDriver
2014-09-10 20:30:52 -07:00
// Diff produces an archive of the changes between the specified
// layer and its parent layer which may be "".
Diff ( id , parent string ) ( archive . Archive , error )
// Changes produces a list of changes between the specified layer
// and its parent layer. If parent is "", then all changes will be ADD changes.
Changes ( id , parent string ) ( [ ] archive . Change , error )
// ApplyDiff extracts the changeset from the given diff into the
// layer with the specified id and parent, returning the size of the
// new layer in bytes.
2014-12-17 18:26:03 -08:00
ApplyDiff ( id , parent string , diff archive . ArchiveReader ) ( size int64 , err error )
2014-09-10 20:30:52 -07:00
// DiffSize calculates the changes between the specified id
// and its parent and returns the size in bytes of the changes
// relative to its base filesystem directory.
2014-12-17 18:26:03 -08:00
DiffSize ( id , parent string ) ( size int64 , err error )
2013-11-11 16:47:36 +01:00
}
2013-11-07 20:31:50 +00:00
func init ( ) {
drivers = make ( map [ string ] InitFunc )
}
2013-11-04 15:22:34 -08:00
func Register ( name string , initFunc InitFunc ) error {
if _ , exists := drivers [ name ] ; exists {
return fmt . Errorf ( "Name already registered %s" , name )
}
drivers [ name ] = initFunc
return nil
}
2014-06-05 10:34:20 +02:00
func GetDriver ( name , home string , options [ ] string ) ( Driver , error ) {
2013-11-08 02:49:32 +00:00
if initFunc , exists := drivers [ name ] ; exists {
2015-04-24 12:35:51 -07:00
return initFunc ( filepath . Join ( home , name ) , options )
2013-11-08 02:49:32 +00:00
}
2014-03-27 17:41:06 +01:00
return nil , ErrNotSupported
2013-11-08 02:49:32 +00:00
}
2014-06-05 10:34:20 +02:00
func New ( root string , options [ ] string ) ( driver Driver , err error ) {
2013-11-20 11:39:15 -08:00
for _ , name := range [ ] string { os . Getenv ( "DOCKER_DRIVER" ) , DefaultDriver } {
2013-11-19 03:13:22 -08:00
if name != "" {
2015-04-17 10:56:12 -07:00
logrus . Debugf ( "[graphdriver] trying provided driver %q" , name ) // so the logs show specified driver
2014-06-05 10:34:20 +02:00
return GetDriver ( name , root , options )
2013-11-19 03:13:22 -08:00
}
2013-11-08 02:49:32 +00:00
}
2013-11-19 03:13:22 -08:00
2015-04-01 14:12:15 -04:00
// Guess for prior driver
2015-06-30 09:00:02 -07:00
priorDriver , err := scanPriorDrivers ( root )
if err != nil {
return nil , err
}
if len ( priorDriver ) != 0 {
// Do not allow devicemapper when it's not explicit and the Docker binary was built statically.
if staticWithDeviceMapper ( priorDriver ) {
return nil , ErrDeviceMapperWithStaticDocker
2015-04-01 14:12:15 -04:00
}
2015-06-30 09:00:02 -07:00
driver , err = GetDriver ( priorDriver , root , options )
if err != nil {
// unlike below, we will return error here, because there is prior
// state, and now it is no longer supported/prereq/compatible, so
// something changed and needs attention. Otherwise the daemon's
// images would just "disappear".
logrus . Errorf ( "[graphdriver] prior storage driver %q failed: %s" , priorDriver , err )
return nil , err
2015-04-01 14:12:15 -04:00
}
2015-06-30 09:00:02 -07:00
logrus . Infof ( "[graphdriver] using prior storage driver %q" , priorDriver )
return driver , nil
2015-04-01 14:12:15 -04:00
}
2013-11-04 15:22:34 -08:00
// Check for priority drivers first
for _ , name := range priority {
2015-06-30 09:00:02 -07:00
if staticWithDeviceMapper ( name ) {
continue
}
2014-06-05 10:34:20 +02:00
driver , err = GetDriver ( name , root , options )
2014-03-27 17:41:06 +01:00
if err != nil {
2014-05-29 22:55:59 +03:00
if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS {
2014-03-27 17:41:06 +01:00
continue
}
return nil , err
2013-11-04 15:22:34 -08:00
}
2013-11-08 02:49:32 +00:00
return driver , nil
2013-11-04 15:22:34 -08:00
}
// Check all registered drivers if no priority driver is found
2015-06-30 09:00:02 -07:00
for name , initFunc := range drivers {
if staticWithDeviceMapper ( name ) {
continue
}
2014-06-05 10:34:20 +02:00
if driver , err = initFunc ( root , options ) ; err != nil {
2014-05-29 22:55:59 +03:00
if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS {
2014-03-27 17:41:06 +01:00
continue
}
return nil , err
2013-11-04 15:22:34 -08:00
}
return driver , nil
}
2014-03-27 17:41:06 +01:00
return nil , fmt . Errorf ( "No supported storage backend found" )
2013-11-04 15:22:34 -08:00
}
2014-11-16 02:54:21 +09:00
2015-06-30 09:00:02 -07:00
// scanPriorDrivers returns a previosly used driver.
// it returns an error when there are several drivers scanned.
func scanPriorDrivers ( root string ) ( string , error ) {
var priorDrivers [ ] string
2015-04-01 14:12:15 -04:00
for driver := range drivers {
2015-04-24 12:35:51 -07:00
p := filepath . Join ( root , driver )
2015-06-30 09:00:02 -07:00
if _ , err := os . Stat ( p ) ; err == nil && driver != "vfs" {
2015-04-01 14:12:15 -04:00
priorDrivers = append ( priorDrivers , driver )
}
}
2015-06-30 09:00:02 -07:00
if len ( priorDrivers ) > 1 {
return "" , multipleDriversError ( root , priorDrivers )
2014-11-16 02:54:21 +09:00
}
2015-04-01 14:12:15 -04:00
2015-06-30 09:00:02 -07:00
if len ( priorDrivers ) == 0 {
return "" , nil
2014-11-16 02:54:21 +09:00
}
2015-06-30 09:00:02 -07:00
return priorDrivers [ 0 ] , nil
}
func multipleDriversError ( root string , drivers [ ] string ) error {
return fmt . Errorf ( "%q contains several graphdrivers: %s; Please cleanup or explicitly choose storage driver (--storage-driver <DRIVER>)" , root , strings . Join ( drivers , ", " ) )
}
func staticWithDeviceMapper ( name string ) bool {
return name == "devicemapper" && dockerversion . IAMSTATIC == "true"
2014-11-16 02:54:21 +09:00
}