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