github.com/tompao/docker@v1.9.1/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 predifined contant value other than a valid filesystem id. 21 FsMagicUnsupported = FsMagic(0x00000000) 22 ) 23 24 var ( 25 // DefaultDriver if a storage driver is not specified. 26 DefaultDriver string 27 // All registred 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 // Create creates a new, empty, filesystem layer with the 51 // specified id and parent. Parent may be "". 52 Create(id, parent string) error 53 // Remove attempts to remove the filesystem layer with this id. 54 Remove(id string) error 55 // Get returns the mountpoint for the layered filesystem referred 56 // to by this id. You can optionally specify a mountLabel or "". 57 // Returns the absolute path to the mounted layered filesystem. 58 Get(id, mountLabel string) (dir string, err error) 59 // Put releases the system resources for the specified id, 60 // e.g, unmounting layered filesystem. 61 Put(id string) error 62 // Exists returns whether a filesystem layer with the specified 63 // ID exists on this driver. 64 Exists(id string) bool 65 // Status returns a set of key-value pairs which give low 66 // level diagnostic status about this driver. 67 Status() [][2]string 68 // Returns a set of key-value pairs which give low level information 69 // about the image/container driver is managing. 70 GetMetadata(id string) (map[string]string, error) 71 // Cleanup performs necessary tasks to release resources 72 // held by the driver, e.g., unmounting all layered filesystems 73 // known to this driver. 74 Cleanup() error 75 } 76 77 // Driver is the interface for layered/snapshot file system drivers. 78 type Driver interface { 79 ProtoDriver 80 // Diff produces an archive of the changes between the specified 81 // layer and its parent layer which may be "". 82 Diff(id, parent string) (archive.Archive, error) 83 // Changes produces a list of changes between the specified layer 84 // and its parent layer. If parent is "", then all changes will be ADD changes. 85 Changes(id, parent string) ([]archive.Change, error) 86 // ApplyDiff extracts the changeset from the given diff into the 87 // layer with the specified id and parent, returning the size of the 88 // new layer in bytes. 89 // The archive.Reader must be an uncompressed stream. 90 ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) 91 // DiffSize calculates the changes between the specified id 92 // and its parent and returns the size in bytes of the changes 93 // relative to its base filesystem directory. 94 DiffSize(id, parent string) (size int64, err error) 95 } 96 97 func init() { 98 drivers = make(map[string]InitFunc) 99 } 100 101 // Register registers a InitFunc for the driver. 102 func Register(name string, initFunc InitFunc) error { 103 if _, exists := drivers[name]; exists { 104 return fmt.Errorf("Name already registered %s", name) 105 } 106 drivers[name] = initFunc 107 108 return nil 109 } 110 111 // GetDriver initializes and returns the registered driver 112 func GetDriver(name, home string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) { 113 if initFunc, exists := drivers[name]; exists { 114 return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps) 115 } 116 if pluginDriver, err := lookupPlugin(name, home, options); err == nil { 117 return pluginDriver, nil 118 } 119 logrus.Errorf("Failed to GetDriver graph %s %s", name, home) 120 return nil, ErrNotSupported 121 } 122 123 // getBuiltinDriver initalizes and returns the registered driver, but does not try to load from plugins 124 func getBuiltinDriver(name, home string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) { 125 if initFunc, exists := drivers[name]; exists { 126 return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps) 127 } 128 logrus.Errorf("Failed to built-in GetDriver graph %s %s", name, home) 129 return nil, ErrNotSupported 130 } 131 132 // New creates the driver and initializes it at the specified root. 133 func New(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (driver Driver, err error) { 134 for _, name := range []string{os.Getenv("DOCKER_DRIVER"), DefaultDriver} { 135 if name != "" { 136 logrus.Debugf("[graphdriver] trying provided driver %q", name) // so the logs show specified driver 137 return GetDriver(name, root, options, uidMaps, gidMaps) 138 } 139 } 140 141 // Guess for prior driver 142 priorDrivers := scanPriorDrivers(root) 143 for _, name := range priority { 144 if name == "vfs" { 145 // don't use vfs even if there is state present. 146 continue 147 } 148 for _, prior := range priorDrivers { 149 // of the state found from prior drivers, check in order of our priority 150 // which we would prefer 151 if prior == name { 152 driver, err = getBuiltinDriver(name, root, options, uidMaps, gidMaps) 153 if err != nil { 154 // unlike below, we will return error here, because there is prior 155 // state, and now it is no longer supported/prereq/compatible, so 156 // something changed and needs attention. Otherwise the daemon's 157 // images would just "disappear". 158 logrus.Errorf("[graphdriver] prior storage driver %q failed: %s", name, err) 159 return nil, err 160 } 161 if err := checkPriorDriver(name, root); err != nil { 162 return nil, err 163 } 164 logrus.Infof("[graphdriver] using prior storage driver %q", name) 165 return driver, nil 166 } 167 } 168 } 169 170 // Check for priority drivers first 171 for _, name := range priority { 172 driver, err = getBuiltinDriver(name, root, options, uidMaps, gidMaps) 173 if err != nil { 174 if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { 175 continue 176 } 177 return nil, err 178 } 179 return driver, nil 180 } 181 182 // Check all registered drivers if no priority driver is found 183 for _, initFunc := range drivers { 184 if driver, err = initFunc(root, options, uidMaps, gidMaps); err != nil { 185 if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { 186 continue 187 } 188 return nil, err 189 } 190 return driver, nil 191 } 192 return nil, fmt.Errorf("No supported storage backend found") 193 } 194 195 // scanPriorDrivers returns an un-ordered scan of directories of prior storage drivers 196 func scanPriorDrivers(root string) []string { 197 priorDrivers := []string{} 198 for driver := range drivers { 199 p := filepath.Join(root, driver) 200 if _, err := os.Stat(p); err == nil && driver != "vfs" { 201 priorDrivers = append(priorDrivers, driver) 202 } 203 } 204 return priorDrivers 205 } 206 207 func checkPriorDriver(name, root string) error { 208 priorDrivers := []string{} 209 for _, prior := range scanPriorDrivers(root) { 210 if prior != name && prior != "vfs" { 211 if _, err := os.Stat(filepath.Join(root, prior)); err == nil { 212 priorDrivers = append(priorDrivers, prior) 213 } 214 } 215 } 216 217 if len(priorDrivers) > 0 { 218 219 return fmt.Errorf("%q contains other graphdrivers: %s; Please cleanup or explicitly choose storage driver (-s <DRIVER>)", root, strings.Join(priorDrivers, ",")) 220 } 221 return nil 222 }