github.com/noxiouz/docker@v0.7.3-0.20160629055221-3d231c78e8c5/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/vbatts/tar-split/tar/storage" 12 13 "github.com/docker/docker/pkg/archive" 14 "github.com/docker/docker/pkg/idtools" 15 ) 16 17 // FsMagic unsigned id of the filesystem in use. 18 type FsMagic uint32 19 20 const ( 21 // FsMagicUnsupported is a predefined constant value other than a valid filesystem id. 22 FsMagicUnsupported = FsMagic(0x00000000) 23 ) 24 25 var ( 26 // All registered drivers 27 drivers map[string]InitFunc 28 29 // ErrNotSupported returned when driver is not supported. 30 ErrNotSupported = errors.New("driver not supported") 31 // ErrPrerequisites retuned when driver does not meet prerequisites. 32 ErrPrerequisites = errors.New("prerequisites for driver not satisfied (wrong filesystem?)") 33 // ErrIncompatibleFS returned when file system is not supported. 34 ErrIncompatibleFS = fmt.Errorf("backing file system is unsupported for this graph driver") 35 ) 36 37 // InitFunc initializes the storage driver. 38 type InitFunc func(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) 39 40 // ProtoDriver defines the basic capabilities of a driver. 41 // This interface exists solely to be a minimum set of methods 42 // for client code which choose not to implement the entire Driver 43 // interface and use the NaiveDiffDriver wrapper constructor. 44 // 45 // Use of ProtoDriver directly by client code is not recommended. 46 type ProtoDriver interface { 47 // String returns a string representation of this driver. 48 String() string 49 // CreateReadWrite creates a new, empty filesystem layer that is ready 50 // to be used as the storage for a container. 51 CreateReadWrite(id, parent, mountLabel string, storageOpt map[string]string) error 52 // Create creates a new, empty, filesystem layer with the 53 // specified id and parent and mountLabel. Parent and mountLabel may be "". 54 Create(id, parent, mountLabel string, storageOpt map[string]string) error 55 // Remove attempts to remove the filesystem layer with this id. 56 Remove(id string) error 57 // Get returns the mountpoint for the layered filesystem referred 58 // to by this id. You can optionally specify a mountLabel or "". 59 // Returns the absolute path to the mounted layered filesystem. 60 Get(id, mountLabel string) (dir string, err error) 61 // Put releases the system resources for the specified id, 62 // e.g, unmounting layered filesystem. 63 Put(id string) error 64 // Exists returns whether a filesystem layer with the specified 65 // ID exists on this driver. 66 Exists(id string) bool 67 // Status returns a set of key-value pairs which give low 68 // level diagnostic status about this driver. 69 Status() [][2]string 70 // Returns a set of key-value pairs which give low level information 71 // about the image/container driver is managing. 72 GetMetadata(id string) (map[string]string, error) 73 // Cleanup performs necessary tasks to release resources 74 // held by the driver, e.g., unmounting all layered filesystems 75 // known to this driver. 76 Cleanup() error 77 } 78 79 // Driver is the interface for layered/snapshot file system drivers. 80 type Driver interface { 81 ProtoDriver 82 // Diff produces an archive of the changes between the specified 83 // layer and its parent layer which may be "". 84 Diff(id, parent string) (archive.Archive, error) 85 // Changes produces a list of changes between the specified layer 86 // and its parent layer. If parent is "", then all changes will be ADD changes. 87 Changes(id, parent string) ([]archive.Change, error) 88 // ApplyDiff extracts the changeset from the given diff into the 89 // layer with the specified id and parent, returning the size of the 90 // new layer in bytes. 91 // The archive.Reader must be an uncompressed stream. 92 ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) 93 // DiffSize calculates the changes between the specified id 94 // and its parent and returns the size in bytes of the changes 95 // relative to its base filesystem directory. 96 DiffSize(id, parent string) (size int64, err error) 97 } 98 99 // DiffGetterDriver is the interface for layered file system drivers that 100 // provide a specialized function for getting file contents for tar-split. 101 type DiffGetterDriver interface { 102 Driver 103 // DiffGetter returns an interface to efficiently retrieve the contents 104 // of files in a layer. 105 DiffGetter(id string) (FileGetCloser, error) 106 } 107 108 // FileGetCloser extends the storage.FileGetter interface with a Close method 109 // for cleaning up. 110 type FileGetCloser interface { 111 storage.FileGetter 112 // Close cleans up any resources associated with the FileGetCloser. 113 Close() error 114 } 115 116 // Checker makes checks on specified filesystems. 117 type Checker interface { 118 // IsMounted returns true if the provided path is mounted for the specific checker 119 IsMounted(path string) bool 120 } 121 122 func init() { 123 drivers = make(map[string]InitFunc) 124 } 125 126 // Register registers an InitFunc for the driver. 127 func Register(name string, initFunc InitFunc) error { 128 if _, exists := drivers[name]; exists { 129 return fmt.Errorf("Name already registered %s", name) 130 } 131 drivers[name] = initFunc 132 133 return nil 134 } 135 136 // GetDriver initializes and returns the registered driver 137 func GetDriver(name, home string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) { 138 if initFunc, exists := drivers[name]; exists { 139 return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps) 140 } 141 if pluginDriver, err := lookupPlugin(name, home, options); err == nil { 142 return pluginDriver, nil 143 } 144 logrus.Errorf("Failed to GetDriver graph %s %s", name, home) 145 return nil, ErrNotSupported 146 } 147 148 // getBuiltinDriver initializes and returns the registered driver, but does not try to load from plugins 149 func getBuiltinDriver(name, home string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) { 150 if initFunc, exists := drivers[name]; exists { 151 return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps) 152 } 153 logrus.Errorf("Failed to built-in GetDriver graph %s %s", name, home) 154 return nil, ErrNotSupported 155 } 156 157 // New creates the driver and initializes it at the specified root. 158 func New(root string, name string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) { 159 if name != "" { 160 logrus.Debugf("[graphdriver] trying provided driver %q", name) // so the logs show specified driver 161 return GetDriver(name, root, options, uidMaps, gidMaps) 162 } 163 164 // Guess for prior driver 165 driversMap := scanPriorDrivers(root) 166 for _, name := range priority { 167 if name == "vfs" { 168 // don't use vfs even if there is state present. 169 continue 170 } 171 if _, prior := driversMap[name]; prior { 172 // of the state found from prior drivers, check in order of our priority 173 // which we would prefer 174 driver, err := getBuiltinDriver(name, root, options, uidMaps, gidMaps) 175 if err != nil { 176 // unlike below, we will return error here, because there is prior 177 // state, and now it is no longer supported/prereq/compatible, so 178 // something changed and needs attention. Otherwise the daemon's 179 // images would just "disappear". 180 logrus.Errorf("[graphdriver] prior storage driver %q failed: %s", name, err) 181 return nil, err 182 } 183 184 // abort starting when there are other prior configured drivers 185 // to ensure the user explicitly selects the driver to load 186 if len(driversMap)-1 > 0 { 187 var driversSlice []string 188 for name := range driversMap { 189 driversSlice = append(driversSlice, name) 190 } 191 192 return nil, fmt.Errorf("%q contains several valid graphdrivers: %s; Please cleanup or explicitly choose storage driver (-s <DRIVER>)", root, strings.Join(driversSlice, ", ")) 193 } 194 195 logrus.Infof("[graphdriver] using prior storage driver %q", name) 196 return driver, nil 197 } 198 } 199 200 // Check for priority drivers first 201 for _, name := range priority { 202 driver, err := getBuiltinDriver(name, root, options, uidMaps, gidMaps) 203 if err != nil { 204 if isDriverNotSupported(err) { 205 continue 206 } 207 return nil, err 208 } 209 return driver, nil 210 } 211 212 // Check all registered drivers if no priority driver is found 213 for name, initFunc := range drivers { 214 driver, err := initFunc(filepath.Join(root, name), options, uidMaps, gidMaps) 215 if err != nil { 216 if isDriverNotSupported(err) { 217 continue 218 } 219 return nil, err 220 } 221 return driver, nil 222 } 223 return nil, fmt.Errorf("No supported storage backend found") 224 } 225 226 // isDriverNotSupported returns true if the error initializing 227 // the graph driver is a non-supported error. 228 func isDriverNotSupported(err error) bool { 229 return err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS 230 } 231 232 // scanPriorDrivers returns an un-ordered scan of directories of prior storage drivers 233 func scanPriorDrivers(root string) map[string]bool { 234 driversMap := make(map[string]bool) 235 236 for driver := range drivers { 237 p := filepath.Join(root, driver) 238 if _, err := os.Stat(p); err == nil && driver != "vfs" { 239 driversMap[driver] = true 240 } 241 } 242 return driversMap 243 }