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