github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/daemon/graphdriver/driver.go (about) 1 package graphdriver 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strings" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/pkg/archive" 12 ) 13 14 // FsMagic unsigned id of the filesystem in use. 15 type FsMagic uint32 16 17 const ( 18 // FsMagicUnsupported is a predifined contant value other than a valid filesystem id. 19 FsMagicUnsupported = FsMagic(0x00000000) 20 ) 21 22 var ( 23 // DefaultDriver if a storage driver is not specified. 24 DefaultDriver string 25 // All registred drivers 26 drivers map[string]InitFunc 27 28 // ErrNotSupported returned when driver is not supported. 29 ErrNotSupported = errors.New("driver not supported") 30 // ErrPrerequisites retuned when driver does not meet prerequisites. 31 ErrPrerequisites = errors.New("prerequisites for driver not satisfied (wrong filesystem?)") 32 // ErrIncompatibleFS returned when file system is not supported. 33 ErrIncompatibleFS = fmt.Errorf("backing file system is unsupported for this graph driver") 34 ) 35 36 // InitFunc initializes the storage driver. 37 type InitFunc func(root string, options []string) (Driver, error) 38 39 // ProtoDriver defines the basic capabilities of a driver. 40 // This interface exists solely to be a minimum set of methods 41 // for client code which choose not to implement the entire Driver 42 // interface and use the NaiveDiffDriver wrapper constructor. 43 // 44 // Use of ProtoDriver directly by client code is not recommended. 45 type ProtoDriver interface { 46 // String returns a string representation of this driver. 47 String() string 48 // Create creates a new, empty, filesystem layer with the 49 // specified id and parent. Parent may be "". 50 Create(id, parent string) error 51 // Remove attempts to remove the filesystem layer with this id. 52 Remove(id string) error 53 // Get returns the mountpoint for the layered filesystem referred 54 // to by this id. You can optionally specify a mountLabel or "". 55 // Returns the absolute path to the mounted layered filesystem. 56 Get(id, mountLabel string) (dir string, err error) 57 // Put releases the system resources for the specified id, 58 // e.g, unmounting layered filesystem. 59 Put(id string) error 60 // Exists returns whether a filesystem layer with the specified 61 // ID exists on this driver. 62 Exists(id string) bool 63 // Status returns a set of key-value pairs which give low 64 // level diagnostic status about this driver. 65 Status() [][2]string 66 // Returns a set of key-value pairs which give low level information 67 // about the image/container driver is managing. 68 GetMetadata(id string) (map[string]string, error) 69 // Cleanup performs necessary tasks to release resources 70 // held by the driver, e.g., unmounting all layered filesystems 71 // known to this driver. 72 Cleanup() error 73 } 74 75 // Driver is the interface for layered/snapshot file system drivers. 76 type Driver interface { 77 ProtoDriver 78 // Diff produces an archive of the changes between the specified 79 // layer and its parent layer which may be "". 80 Diff(id, parent string) (archive.Archive, error) 81 // Changes produces a list of changes between the specified layer 82 // and its parent layer. If parent is "", then all changes will be ADD changes. 83 Changes(id, parent string) ([]archive.Change, error) 84 // ApplyDiff extracts the changeset from the given diff into the 85 // layer with the specified id and parent, returning the size of the 86 // new layer in bytes. 87 // The archive.Reader must be an uncompressed stream. 88 ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) 89 // DiffSize calculates the changes between the specified id 90 // and its parent and returns the size in bytes of the changes 91 // relative to its base filesystem directory. 92 DiffSize(id, parent string) (size int64, err error) 93 } 94 95 func init() { 96 drivers = make(map[string]InitFunc) 97 } 98 99 // Register registers a InitFunc for the driver. 100 func Register(name string, initFunc InitFunc) error { 101 if _, exists := drivers[name]; exists { 102 return fmt.Errorf("Name already registered %s", name) 103 } 104 drivers[name] = initFunc 105 106 return nil 107 } 108 109 // GetDriver initializes and returns the registered driver 110 func GetDriver(name, home string, options []string) (Driver, error) { 111 if initFunc, exists := drivers[name]; exists { 112 return initFunc(filepath.Join(home, name), options) 113 } 114 logrus.Errorf("Failed to GetDriver graph %s %s", name, home) 115 return nil, ErrNotSupported 116 } 117 118 // New creates the driver and initializes it at the specified root. 119 func New(root string, options []string) (driver Driver, err error) { 120 for _, name := range []string{os.Getenv("DOCKER_DRIVER"), DefaultDriver} { 121 if name != "" { 122 logrus.Debugf("[graphdriver] trying provided driver %q", name) // so the logs show specified driver 123 return GetDriver(name, root, options) 124 } 125 } 126 127 // Guess for prior driver 128 priorDrivers := scanPriorDrivers(root) 129 for _, name := range priority { 130 if name == "vfs" { 131 // don't use vfs even if there is state present. 132 continue 133 } 134 for _, prior := range priorDrivers { 135 // of the state found from prior drivers, check in order of our priority 136 // which we would prefer 137 if prior == name { 138 driver, err = GetDriver(name, root, options) 139 if err != nil { 140 // unlike below, we will return error here, because there is prior 141 // state, and now it is no longer supported/prereq/compatible, so 142 // something changed and needs attention. Otherwise the daemon's 143 // images would just "disappear". 144 logrus.Errorf("[graphdriver] prior storage driver %q failed: %s", name, err) 145 return nil, err 146 } 147 if err := checkPriorDriver(name, root); err != nil { 148 return nil, err 149 } 150 logrus.Infof("[graphdriver] using prior storage driver %q", name) 151 return driver, nil 152 } 153 } 154 } 155 156 // Check for priority drivers first 157 for _, name := range priority { 158 driver, err = GetDriver(name, root, options) 159 if err != nil { 160 if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { 161 continue 162 } 163 return nil, err 164 } 165 return driver, nil 166 } 167 168 // Check all registered drivers if no priority driver is found 169 for _, initFunc := range drivers { 170 if driver, err = initFunc(root, options); err != nil { 171 if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { 172 continue 173 } 174 return nil, err 175 } 176 return driver, nil 177 } 178 return nil, fmt.Errorf("No supported storage backend found") 179 } 180 181 // scanPriorDrivers returns an un-ordered scan of directories of prior storage drivers 182 func scanPriorDrivers(root string) []string { 183 priorDrivers := []string{} 184 for driver := range drivers { 185 p := filepath.Join(root, driver) 186 if _, err := os.Stat(p); err == nil && driver != "vfs" { 187 priorDrivers = append(priorDrivers, driver) 188 } 189 } 190 return priorDrivers 191 } 192 193 func checkPriorDriver(name, root string) error { 194 priorDrivers := []string{} 195 for _, prior := range scanPriorDrivers(root) { 196 if prior != name && prior != "vfs" { 197 if _, err := os.Stat(filepath.Join(root, prior)); err == nil { 198 priorDrivers = append(priorDrivers, prior) 199 } 200 } 201 } 202 203 if len(priorDrivers) > 0 { 204 205 return fmt.Errorf("%q contains other graphdrivers: %s; Please cleanup or explicitly choose storage driver (-s <DRIVER>)", root, strings.Join(priorDrivers, ",")) 206 } 207 return nil 208 }