github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/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 12 "github.com/docker/docker/pkg/archive" 13 "github.com/docker/docker/pkg/idtools" 14 ) 15 16 // FsMagic unsigned id of the filesystem in use. 17 type FsMagic uint32 18 19 const ( 20 // FsMagicUnsupported is a predefined constant value other than a valid filesystem id. 21 FsMagicUnsupported = FsMagic(0x00000000) 22 ) 23 24 var ( 25 // All registered 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, uidMaps, gidMaps []idtools.IDMap) (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 and mountLabel. Parent and mountLabel may be "". 50 Create(id, parent, mountLabel 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, uidMaps, gidMaps []idtools.IDMap) (Driver, error) { 111 if initFunc, exists := drivers[name]; exists { 112 return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps) 113 } 114 if pluginDriver, err := lookupPlugin(name, home, options); err == nil { 115 return pluginDriver, nil 116 } 117 logrus.Errorf("Failed to GetDriver graph %s %s", name, home) 118 return nil, ErrNotSupported 119 } 120 121 // getBuiltinDriver initializes and returns the registered driver, but does not try to load from plugins 122 func getBuiltinDriver(name, home string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) { 123 if initFunc, exists := drivers[name]; exists { 124 return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps) 125 } 126 logrus.Errorf("Failed to built-in GetDriver graph %s %s", name, home) 127 return nil, ErrNotSupported 128 } 129 130 // New creates the driver and initializes it at the specified root. 131 func New(root string, name string, options []string, uidMaps, gidMaps []idtools.IDMap) (driver Driver, err error) { 132 if name != "" { 133 logrus.Debugf("[graphdriver] trying provided driver %q", name) // so the logs show specified driver 134 return GetDriver(name, root, options, uidMaps, gidMaps) 135 } 136 137 // Guess for prior driver 138 priorDrivers := scanPriorDrivers(root) 139 for _, name := range priority { 140 if name == "vfs" { 141 // don't use vfs even if there is state present. 142 continue 143 } 144 for _, prior := range priorDrivers { 145 // of the state found from prior drivers, check in order of our priority 146 // which we would prefer 147 if prior == name { 148 driver, err = getBuiltinDriver(name, root, options, uidMaps, gidMaps) 149 if err != nil { 150 // unlike below, we will return error here, because there is prior 151 // state, and now it is no longer supported/prereq/compatible, so 152 // something changed and needs attention. Otherwise the daemon's 153 // images would just "disappear". 154 logrus.Errorf("[graphdriver] prior storage driver %q failed: %s", name, err) 155 return nil, err 156 } 157 if err := checkPriorDriver(name, root); err != nil { 158 return nil, err 159 } 160 logrus.Infof("[graphdriver] using prior storage driver %q", name) 161 return driver, nil 162 } 163 } 164 } 165 166 // Check for priority drivers first 167 for _, name := range priority { 168 driver, err = getBuiltinDriver(name, root, options, uidMaps, gidMaps) 169 if err != nil { 170 if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { 171 continue 172 } 173 return nil, err 174 } 175 return driver, nil 176 } 177 178 // Check all registered drivers if no priority driver is found 179 for _, initFunc := range drivers { 180 if driver, err = initFunc(root, options, uidMaps, gidMaps); err != nil { 181 if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { 182 continue 183 } 184 return nil, err 185 } 186 return driver, nil 187 } 188 return nil, fmt.Errorf("No supported storage backend found") 189 } 190 191 // scanPriorDrivers returns an un-ordered scan of directories of prior storage drivers 192 func scanPriorDrivers(root string) []string { 193 priorDrivers := []string{} 194 for driver := range drivers { 195 p := filepath.Join(root, driver) 196 if _, err := os.Stat(p); err == nil && driver != "vfs" { 197 priorDrivers = append(priorDrivers, driver) 198 } 199 } 200 return priorDrivers 201 } 202 203 func checkPriorDriver(name, root string) error { 204 priorDrivers := []string{} 205 for _, prior := range scanPriorDrivers(root) { 206 if prior != name && prior != "vfs" { 207 if _, err := os.Stat(filepath.Join(root, prior)); err == nil { 208 priorDrivers = append(priorDrivers, prior) 209 } 210 } 211 } 212 213 if len(priorDrivers) > 0 { 214 215 return fmt.Errorf("%q contains other graphdrivers: %s; Please cleanup or explicitly choose storage driver (-s <DRIVER>)", root, strings.Join(priorDrivers, ",")) 216 } 217 return nil 218 }