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