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