github.com/afein/docker@v1.8.2/daemon/graphdriver/driver.go (about) 1 package graphdriver 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strings" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/pkg/archive" 12 ) 13 14 type FsMagic uint32 15 16 const ( 17 FsMagicUnsupported = FsMagic(0x00000000) 18 ) 19 20 var ( 21 DefaultDriver string 22 // All registred drivers 23 drivers map[string]InitFunc 24 25 ErrNotSupported = errors.New("driver not supported") 26 ErrPrerequisites = errors.New("prerequisites for driver not satisfied (wrong filesystem?)") 27 ErrIncompatibleFS = fmt.Errorf("backing file system is unsupported for this graph driver") 28 ) 29 30 type InitFunc func(root string, options []string) (Driver, error) 31 32 // ProtoDriver defines the basic capabilities of a driver. 33 // This interface exists solely to be a minimum set of methods 34 // for client code which choose not to implement the entire Driver 35 // interface and use the NaiveDiffDriver wrapper constructor. 36 // 37 // Use of ProtoDriver directly by client code is not recommended. 38 type ProtoDriver interface { 39 // String returns a string representation of this driver. 40 String() string 41 // Create creates a new, empty, filesystem layer with the 42 // specified id and parent. Parent may be "". 43 Create(id, parent string) error 44 // Remove attempts to remove the filesystem layer with this id. 45 Remove(id string) error 46 // Get returns the mountpoint for the layered filesystem referred 47 // to by this id. You can optionally specify a mountLabel or "". 48 // Returns the absolute path to the mounted layered filesystem. 49 Get(id, mountLabel string) (dir string, err error) 50 // Put releases the system resources for the specified id, 51 // e.g, unmounting layered filesystem. 52 Put(id string) error 53 // Exists returns whether a filesystem layer with the specified 54 // ID exists on this driver. 55 Exists(id string) bool 56 // Status returns a set of key-value pairs which give low 57 // level diagnostic status about this driver. 58 Status() [][2]string 59 // Returns a set of key-value pairs which give low level information 60 // about the image/container driver is managing. 61 GetMetadata(id string) (map[string]string, error) 62 // Cleanup performs necessary tasks to release resources 63 // held by the driver, e.g., unmounting all layered filesystems 64 // known to this driver. 65 Cleanup() error 66 } 67 68 // Driver is the interface for layered/snapshot file system drivers. 69 type Driver interface { 70 ProtoDriver 71 // Diff produces an archive of the changes between the specified 72 // layer and its parent layer which may be "". 73 Diff(id, parent string) (archive.Archive, error) 74 // Changes produces a list of changes between the specified layer 75 // and its parent layer. If parent is "", then all changes will be ADD changes. 76 Changes(id, parent string) ([]archive.Change, error) 77 // ApplyDiff extracts the changeset from the given diff into the 78 // layer with the specified id and parent, returning the size of the 79 // new layer in bytes. 80 // The archive.ArchiveReader must be an uncompressed stream. 81 ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) 82 // DiffSize calculates the changes between the specified id 83 // and its parent and returns the size in bytes of the changes 84 // relative to its base filesystem directory. 85 DiffSize(id, parent string) (size int64, err error) 86 } 87 88 func init() { 89 drivers = make(map[string]InitFunc) 90 } 91 92 func Register(name string, initFunc InitFunc) error { 93 if _, exists := drivers[name]; exists { 94 return fmt.Errorf("Name already registered %s", name) 95 } 96 drivers[name] = initFunc 97 98 return nil 99 } 100 101 func GetDriver(name, home string, options []string) (Driver, error) { 102 if initFunc, exists := drivers[name]; exists { 103 return initFunc(filepath.Join(home, name), options) 104 } 105 logrus.Errorf("Failed to GetDriver graph %s %s", name, home) 106 return nil, ErrNotSupported 107 } 108 109 func New(root string, options []string) (driver Driver, err error) { 110 for _, name := range []string{os.Getenv("DOCKER_DRIVER"), DefaultDriver} { 111 if name != "" { 112 logrus.Debugf("[graphdriver] trying provided driver %q", name) // so the logs show specified driver 113 return GetDriver(name, root, options) 114 } 115 } 116 117 // Guess for prior driver 118 priorDrivers := scanPriorDrivers(root) 119 for _, name := range priority { 120 if name == "vfs" { 121 // don't use vfs even if there is state present. 122 continue 123 } 124 for _, prior := range priorDrivers { 125 // of the state found from prior drivers, check in order of our priority 126 // which we would prefer 127 if prior == name { 128 driver, err = GetDriver(name, root, options) 129 if err != nil { 130 // unlike below, we will return error here, because there is prior 131 // state, and now it is no longer supported/prereq/compatible, so 132 // something changed and needs attention. Otherwise the daemon's 133 // images would just "disappear". 134 logrus.Errorf("[graphdriver] prior storage driver %q failed: %s", name, err) 135 return nil, err 136 } 137 if err := checkPriorDriver(name, root); err != nil { 138 return nil, err 139 } 140 logrus.Infof("[graphdriver] using prior storage driver %q", name) 141 return driver, nil 142 } 143 } 144 } 145 146 // Check for priority drivers first 147 for _, name := range priority { 148 driver, err = GetDriver(name, root, options) 149 if err != nil { 150 if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { 151 continue 152 } 153 return nil, err 154 } 155 return driver, nil 156 } 157 158 // Check all registered drivers if no priority driver is found 159 for _, initFunc := range drivers { 160 if driver, err = initFunc(root, options); err != nil { 161 if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { 162 continue 163 } 164 return nil, err 165 } 166 return driver, nil 167 } 168 return nil, fmt.Errorf("No supported storage backend found") 169 } 170 171 // scanPriorDrivers returns an un-ordered scan of directories of prior storage drivers 172 func scanPriorDrivers(root string) []string { 173 priorDrivers := []string{} 174 for driver := range drivers { 175 p := filepath.Join(root, driver) 176 if _, err := os.Stat(p); err == nil && driver != "vfs" { 177 priorDrivers = append(priorDrivers, driver) 178 } 179 } 180 return priorDrivers 181 } 182 183 func checkPriorDriver(name, root string) error { 184 priorDrivers := []string{} 185 for _, prior := range scanPriorDrivers(root) { 186 if prior != name && prior != "vfs" { 187 if _, err := os.Stat(filepath.Join(root, prior)); err == nil { 188 priorDrivers = append(priorDrivers, prior) 189 } 190 } 191 } 192 193 if len(priorDrivers) > 0 { 194 195 return errors.New(fmt.Sprintf("%q contains other graphdrivers: %s; Please cleanup or explicitly choose storage driver (-s <DRIVER>)", root, strings.Join(priorDrivers, ","))) 196 } 197 return nil 198 }