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