github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/daemon/graphdriver/driver.go (about) 1 package graphdriver // import "github.com/demonoid81/moby/daemon/graphdriver" 2 3 import ( 4 "fmt" 5 "io" 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/demonoid81/moby/pkg/archive" 14 "github.com/demonoid81/moby/pkg/containerfs" 15 "github.com/demonoid81/moby/pkg/idtools" 16 "github.com/demonoid81/moby/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 32 // CreateOpts contains optional arguments for Create() and CreateReadWrite() 33 // methods. 34 type CreateOpts struct { 35 MountLabel string 36 StorageOpt map[string]string 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. Additional options can 53 // be passed in opts. parent may be "" and opts may be nil. 54 CreateReadWrite(id, parent string, opts *CreateOpts) error 55 // Create creates a new, empty, filesystem layer with the 56 // specified id and parent and options passed in opts. Parent 57 // may be "" and opts may be nil. 58 Create(id, parent string, opts *CreateOpts) error 59 // Remove attempts to remove the filesystem layer with this id. 60 Remove(id string) error 61 // Get returns the mountpoint for the layered filesystem referred 62 // to by this id. You can optionally specify a mountLabel or "". 63 // Returns the absolute path to the mounted layered filesystem. 64 Get(id, mountLabel string) (fs containerfs.ContainerFS, err error) 65 // Put releases the system resources for the specified id, 66 // e.g, unmounting layered filesystem. 67 Put(id string) error 68 // Exists returns whether a filesystem layer with the specified 69 // ID exists on this driver. 70 Exists(id string) bool 71 // Status returns a set of key-value pairs which give low 72 // level diagnostic status about this driver. 73 Status() [][2]string 74 // Returns a set of key-value pairs which give low level information 75 // about the image/container driver is managing. 76 GetMetadata(id string) (map[string]string, error) 77 // Cleanup performs necessary tasks to release resources 78 // held by the driver, e.g., unmounting all layered filesystems 79 // known to this driver. 80 Cleanup() error 81 } 82 83 // DiffDriver is the interface to use to implement graph diffs 84 type DiffDriver interface { 85 // Diff produces an archive of the changes between the specified 86 // layer and its parent layer which may be "". 87 Diff(id, parent string) (io.ReadCloser, error) 88 // Changes produces a list of changes between the specified layer 89 // and its parent layer. If parent is "", then all changes will be ADD changes. 90 Changes(id, parent string) ([]archive.Change, error) 91 // ApplyDiff extracts the changeset from the given diff into the 92 // layer with the specified id and parent, returning the size of the 93 // new layer in bytes. 94 // The archive.Reader must be an uncompressed stream. 95 ApplyDiff(id, parent string, diff io.Reader) (size int64, err error) 96 // DiffSize calculates the changes between the specified id 97 // and its parent and returns the size in bytes of the changes 98 // relative to its base filesystem directory. 99 DiffSize(id, parent string) (size int64, err error) 100 } 101 102 // Driver is the interface for layered/snapshot file system drivers. 103 type Driver interface { 104 ProtoDriver 105 DiffDriver 106 } 107 108 // Capabilities defines a list of capabilities a driver may implement. 109 // These capabilities are not required; however, they do determine how a 110 // graphdriver can be used. 111 type Capabilities struct { 112 // Flags that this driver is capable of reproducing exactly equivalent 113 // diffs for read-only layers. If set, clients can rely on the driver 114 // for consistent tar streams, and avoid extra processing to account 115 // for potential differences (eg: the layer store's use of tar-split). 116 ReproducesExactDiffs bool 117 } 118 119 // CapabilityDriver is the interface for layered file system drivers that 120 // can report on their Capabilities. 121 type CapabilityDriver interface { 122 Capabilities() Capabilities 123 } 124 125 // DiffGetterDriver is the interface for layered file system drivers that 126 // provide a specialized function for getting file contents for tar-split. 127 type DiffGetterDriver interface { 128 Driver 129 // DiffGetter returns an interface to efficiently retrieve the contents 130 // of files in a layer. 131 DiffGetter(id string) (FileGetCloser, error) 132 } 133 134 // FileGetCloser extends the storage.FileGetter interface with a Close method 135 // for cleaning up. 136 type FileGetCloser interface { 137 storage.FileGetter 138 // Close cleans up any resources associated with the FileGetCloser. 139 Close() error 140 } 141 142 // Checker makes checks on specified filesystems. 143 type Checker interface { 144 // IsMounted returns true if the provided path is mounted for the specific checker 145 IsMounted(path string) bool 146 } 147 148 func init() { 149 drivers = make(map[string]InitFunc) 150 } 151 152 // Register registers an InitFunc for the driver. 153 func Register(name string, initFunc InitFunc) error { 154 if _, exists := drivers[name]; exists { 155 return fmt.Errorf("Name already registered %s", name) 156 } 157 drivers[name] = initFunc 158 159 return nil 160 } 161 162 // GetDriver initializes and returns the registered driver 163 func GetDriver(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) { 164 if initFunc, exists := drivers[name]; exists { 165 return initFunc(filepath.Join(config.Root, name), config.DriverOptions, config.UIDMaps, config.GIDMaps) 166 } 167 168 pluginDriver, err := lookupPlugin(name, pg, config) 169 if err == nil { 170 return pluginDriver, nil 171 } 172 logrus.WithError(err).WithField("driver", name).WithField("home-dir", config.Root).Error("Failed to GetDriver graph") 173 return nil, ErrNotSupported 174 } 175 176 // getBuiltinDriver initializes and returns the registered driver, but does not try to load from plugins 177 func getBuiltinDriver(name, home string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) { 178 if initFunc, exists := drivers[name]; exists { 179 return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps) 180 } 181 logrus.Errorf("Failed to built-in GetDriver graph %s %s", name, home) 182 return nil, ErrNotSupported 183 } 184 185 // Options is used to initialize a graphdriver 186 type Options struct { 187 Root string 188 DriverOptions []string 189 UIDMaps []idtools.IDMap 190 GIDMaps []idtools.IDMap 191 ExperimentalEnabled bool 192 } 193 194 // New creates the driver and initializes it at the specified root. 195 func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) { 196 if name != "" { 197 logrus.Debugf("[graphdriver] trying provided driver: %s", name) // so the logs show specified driver 198 logDeprecatedWarning(name) 199 return GetDriver(name, pg, config) 200 } 201 202 // Guess for prior driver 203 driversMap := scanPriorDrivers(config.Root) 204 list := strings.Split(priority, ",") 205 logrus.Debugf("[graphdriver] priority list: %v", list) 206 for _, name := range list { 207 if name == "vfs" { 208 // don't use vfs even if there is state present. 209 continue 210 } 211 if _, prior := driversMap[name]; prior { 212 // of the state found from prior drivers, check in order of our priority 213 // which we would prefer 214 driver, err := getBuiltinDriver(name, config.Root, config.DriverOptions, config.UIDMaps, config.GIDMaps) 215 if err != nil { 216 // unlike below, we will return error here, because there is prior 217 // state, and now it is no longer supported/prereq/compatible, so 218 // something changed and needs attention. Otherwise the daemon's 219 // images would just "disappear". 220 logrus.Errorf("[graphdriver] prior storage driver %s failed: %s", name, err) 221 return nil, err 222 } 223 224 // abort starting when there are other prior configured drivers 225 // to ensure the user explicitly selects the driver to load 226 if len(driversMap)-1 > 0 { 227 var driversSlice []string 228 for name := range driversMap { 229 driversSlice = append(driversSlice, name) 230 } 231 232 return nil, fmt.Errorf("%s contains several valid graphdrivers: %s; Please cleanup or explicitly choose storage driver (-s <DRIVER>)", config.Root, strings.Join(driversSlice, ", ")) 233 } 234 235 logrus.Infof("[graphdriver] using prior storage driver: %s", name) 236 logDeprecatedWarning(name) 237 return driver, nil 238 } 239 } 240 241 // Check for priority drivers first 242 for _, name := range list { 243 driver, err := getBuiltinDriver(name, config.Root, config.DriverOptions, config.UIDMaps, config.GIDMaps) 244 if err != nil { 245 if IsDriverNotSupported(err) { 246 continue 247 } 248 return nil, err 249 } 250 logDeprecatedWarning(name) 251 return driver, nil 252 } 253 254 // Check all registered drivers if no priority driver is found 255 for name, initFunc := range drivers { 256 if isDeprecated(name) { 257 // Deprecated storage-drivers are skipped in automatic selection, but 258 // can be selected through configuration. 259 continue 260 } 261 driver, err := initFunc(filepath.Join(config.Root, name), config.DriverOptions, config.UIDMaps, config.GIDMaps) 262 if err != nil { 263 if IsDriverNotSupported(err) { 264 continue 265 } 266 return nil, err 267 } 268 logDeprecatedWarning(name) 269 return driver, nil 270 } 271 return nil, fmt.Errorf("No supported storage backend found") 272 } 273 274 // scanPriorDrivers returns an un-ordered scan of directories of prior storage drivers 275 func scanPriorDrivers(root string) map[string]bool { 276 driversMap := make(map[string]bool) 277 278 for driver := range drivers { 279 p := filepath.Join(root, driver) 280 if _, err := os.Stat(p); err == nil && driver != "vfs" { 281 if !isEmptyDir(p) { 282 driversMap[driver] = true 283 } 284 } 285 } 286 return driversMap 287 } 288 289 // IsInitialized checks if the driver's home-directory exists and is non-empty. 290 func IsInitialized(driverHome string) bool { 291 _, err := os.Stat(driverHome) 292 if os.IsNotExist(err) { 293 return false 294 } 295 if err != nil { 296 logrus.Warnf("graphdriver.IsInitialized: stat failed: %v", err) 297 } 298 return !isEmptyDir(driverHome) 299 } 300 301 // isEmptyDir checks if a directory is empty. It is used to check if prior 302 // storage-driver directories exist. If an error occurs, it also assumes the 303 // directory is not empty (which preserves the behavior _before_ this check 304 // was added) 305 func isEmptyDir(name string) bool { 306 f, err := os.Open(name) 307 if err != nil { 308 return false 309 } 310 defer f.Close() 311 312 if _, err = f.Readdirnames(1); err == io.EOF { 313 return true 314 } 315 return false 316 } 317 318 // isDeprecated checks if a storage-driver is marked "deprecated" 319 func isDeprecated(name string) bool { 320 switch name { 321 // NOTE: when deprecating a driver, update daemon.fillDriverInfo() accordingly 322 case "aufs", "devicemapper", "overlay": 323 return true 324 } 325 return false 326 } 327 328 // logDeprecatedWarning logs a warning if the given storage-driver is marked "deprecated" 329 func logDeprecatedWarning(name string) { 330 if isDeprecated(name) { 331 logrus.Warnf("[graphdriver] WARNING: the %s storage-driver is deprecated, and will be removed in a future release", name) 332 } 333 }