github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/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 returned 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 //CreateOpts contains optional arguments for Create() and CreateReadWrite() 40 // methods. 41 type CreateOpts struct { 42 MountLabel string 43 StorageOpt map[string]string 44 } 45 46 // InitFunc initializes the storage driver. 47 type InitFunc func(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) 48 49 // ProtoDriver defines the basic capabilities of a driver. 50 // This interface exists solely to be a minimum set of methods 51 // for client code which choose not to implement the entire Driver 52 // interface and use the NaiveDiffDriver wrapper constructor. 53 // 54 // Use of ProtoDriver directly by client code is not recommended. 55 type ProtoDriver interface { 56 // String returns a string representation of this driver. 57 String() string 58 // CreateReadWrite creates a new, empty filesystem layer that is ready 59 // to be used as the storage for a container. Additional options can 60 // be passed in opts. parent may be "" and opts may be nil. 61 CreateReadWrite(id, parent string, opts *CreateOpts) error 62 // Create creates a new, empty, filesystem layer with the 63 // specified id and parent and options passed in opts. Parent 64 // may be "" and opts may be nil. 65 Create(id, parent string, opts *CreateOpts) error 66 // Remove attempts to remove the filesystem layer with this id. 67 Remove(id string) error 68 // Get returns the mountpoint for the layered filesystem referred 69 // to by this id. You can optionally specify a mountLabel or "". 70 // Returns the absolute path to the mounted layered filesystem. 71 Get(id, mountLabel string) (dir string, err error) 72 // Put releases the system resources for the specified id, 73 // e.g, unmounting layered filesystem. 74 Put(id string) error 75 // Exists returns whether a filesystem layer with the specified 76 // ID exists on this driver. 77 Exists(id string) bool 78 // Status returns a set of key-value pairs which give low 79 // level diagnostic status about this driver. 80 Status() [][2]string 81 // Returns a set of key-value pairs which give low level information 82 // about the image/container driver is managing. 83 GetMetadata(id string) (map[string]string, error) 84 // Cleanup performs necessary tasks to release resources 85 // held by the driver, e.g., unmounting all layered filesystems 86 // known to this driver. 87 Cleanup() error 88 } 89 90 // DiffDriver is the interface to use to implement graph diffs 91 type DiffDriver interface { 92 // Diff produces an archive of the changes between the specified 93 // layer and its parent layer which may be "". 94 Diff(id, parent string) (io.ReadCloser, error) 95 // Changes produces a list of changes between the specified layer 96 // and its parent layer. If parent is "", then all changes will be ADD changes. 97 Changes(id, parent string) ([]archive.Change, error) 98 // ApplyDiff extracts the changeset from the given diff into the 99 // layer with the specified id and parent, returning the size of the 100 // new layer in bytes. 101 // The archive.Reader must be an uncompressed stream. 102 ApplyDiff(id, parent string, diff io.Reader) (size int64, err error) 103 // DiffSize calculates the changes between the specified id 104 // and its parent and returns the size in bytes of the changes 105 // relative to its base filesystem directory. 106 DiffSize(id, parent string) (size int64, err error) 107 } 108 109 // Driver is the interface for layered/snapshot file system drivers. 110 type Driver interface { 111 ProtoDriver 112 DiffDriver 113 } 114 115 // Capabilities defines a list of capabilities a driver may implement. 116 // These capabilities are not required; however, they do determine how a 117 // graphdriver can be used. 118 type Capabilities struct { 119 // Flags that this driver is capable of reproducing exactly equivalent 120 // diffs for read-only layers. If set, clients can rely on the driver 121 // for consistent tar streams, and avoid extra processing to account 122 // for potential differences (eg: the layer store's use of tar-split). 123 ReproducesExactDiffs bool 124 } 125 126 // CapabilityDriver is the interface for layered file system drivers that 127 // can report on their Capabilities. 128 type CapabilityDriver interface { 129 Capabilities() Capabilities 130 } 131 132 // DiffGetterDriver is the interface for layered file system drivers that 133 // provide a specialized function for getting file contents for tar-split. 134 type DiffGetterDriver interface { 135 Driver 136 // DiffGetter returns an interface to efficiently retrieve the contents 137 // of files in a layer. 138 DiffGetter(id string) (FileGetCloser, error) 139 } 140 141 // FileGetCloser extends the storage.FileGetter interface with a Close method 142 // for cleaning up. 143 type FileGetCloser interface { 144 storage.FileGetter 145 // Close cleans up any resources associated with the FileGetCloser. 146 Close() error 147 } 148 149 // Checker makes checks on specified filesystems. 150 type Checker interface { 151 // IsMounted returns true if the provided path is mounted for the specific checker 152 IsMounted(path string) bool 153 } 154 155 func init() { 156 drivers = make(map[string]InitFunc) 157 } 158 159 // Register registers an InitFunc for the driver. 160 func Register(name string, initFunc InitFunc) error { 161 if _, exists := drivers[name]; exists { 162 return fmt.Errorf("Name already registered %s", name) 163 } 164 drivers[name] = initFunc 165 166 return nil 167 } 168 169 // GetDriver initializes and returns the registered driver 170 func GetDriver(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) { 171 if initFunc, exists := drivers[name]; exists { 172 return initFunc(filepath.Join(config.Root, name), config.DriverOptions, config.UIDMaps, config.GIDMaps) 173 } 174 175 pluginDriver, err := lookupPlugin(name, pg, config) 176 if err == nil { 177 return pluginDriver, nil 178 } 179 logrus.WithError(err).WithField("driver", name).WithField("home-dir", config.Root).Error("Failed to GetDriver graph") 180 return nil, ErrNotSupported 181 } 182 183 // getBuiltinDriver initializes and returns the registered driver, but does not try to load from plugins 184 func getBuiltinDriver(name, home string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) { 185 if initFunc, exists := drivers[name]; exists { 186 return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps) 187 } 188 logrus.Errorf("Failed to built-in GetDriver graph %s %s", name, home) 189 return nil, ErrNotSupported 190 } 191 192 // Options is used to initialize a graphdriver 193 type Options struct { 194 Root string 195 DriverOptions []string 196 UIDMaps []idtools.IDMap 197 GIDMaps []idtools.IDMap 198 ExperimentalEnabled bool 199 } 200 201 // New creates the driver and initializes it at the specified root. 202 func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) { 203 if name != "" { 204 logrus.Debugf("[graphdriver] trying provided driver: %s", name) // so the logs show specified driver 205 return GetDriver(name, pg, config) 206 } 207 208 // Guess for prior driver 209 driversMap := scanPriorDrivers(config.Root) 210 for _, name := range priority { 211 if name == "vfs" { 212 // don't use vfs even if there is state present. 213 continue 214 } 215 if _, prior := driversMap[name]; prior { 216 // of the state found from prior drivers, check in order of our priority 217 // which we would prefer 218 driver, err := getBuiltinDriver(name, config.Root, config.DriverOptions, config.UIDMaps, config.GIDMaps) 219 if err != nil { 220 // unlike below, we will return error here, because there is prior 221 // state, and now it is no longer supported/prereq/compatible, so 222 // something changed and needs attention. Otherwise the daemon's 223 // images would just "disappear". 224 logrus.Errorf("[graphdriver] prior storage driver %s failed: %s", name, err) 225 return nil, err 226 } 227 228 // abort starting when there are other prior configured drivers 229 // to ensure the user explicitly selects the driver to load 230 if len(driversMap)-1 > 0 { 231 var driversSlice []string 232 for name := range driversMap { 233 driversSlice = append(driversSlice, name) 234 } 235 236 return nil, fmt.Errorf("%s contains several valid graphdrivers: %s; Please cleanup or explicitly choose storage driver (-s <DRIVER>)", config.Root, strings.Join(driversSlice, ", ")) 237 } 238 239 logrus.Infof("[graphdriver] using prior storage driver: %s", name) 240 return driver, nil 241 } 242 } 243 244 // Check for priority drivers first 245 for _, name := range priority { 246 driver, err := getBuiltinDriver(name, config.Root, config.DriverOptions, config.UIDMaps, config.GIDMaps) 247 if err != nil { 248 if isDriverNotSupported(err) { 249 continue 250 } 251 return nil, err 252 } 253 return driver, nil 254 } 255 256 // Check all registered drivers if no priority driver is found 257 for name, initFunc := range drivers { 258 driver, err := initFunc(filepath.Join(config.Root, name), config.DriverOptions, config.UIDMaps, config.GIDMaps) 259 if err != nil { 260 if isDriverNotSupported(err) { 261 continue 262 } 263 return nil, err 264 } 265 return driver, nil 266 } 267 return nil, fmt.Errorf("No supported storage backend found") 268 } 269 270 // isDriverNotSupported returns true if the error initializing 271 // the graph driver is a non-supported error. 272 func isDriverNotSupported(err error) bool { 273 return err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS 274 } 275 276 // scanPriorDrivers returns an un-ordered scan of directories of prior storage drivers 277 func scanPriorDrivers(root string) map[string]bool { 278 driversMap := make(map[string]bool) 279 280 for driver := range drivers { 281 p := filepath.Join(root, driver) 282 if _, err := os.Stat(p); err == nil && driver != "vfs" { 283 driversMap[driver] = true 284 } 285 } 286 return driversMap 287 }