github.com/docker/Engine@v17.12.1-ce-rc2+incompatible/volume/drivers/extpoint.go (about) 1 //go:generate pluginrpc-gen -i $GOFILE -o proxy.go -type volumeDriver -name VolumeDriver 2 3 package volumedrivers 4 5 import ( 6 "fmt" 7 "sort" 8 "sync" 9 10 "github.com/docker/docker/pkg/locker" 11 getter "github.com/docker/docker/pkg/plugingetter" 12 "github.com/docker/docker/volume" 13 "github.com/pkg/errors" 14 "github.com/sirupsen/logrus" 15 ) 16 17 // currently created by hand. generation tool would generate this like: 18 // $ extpoint-gen Driver > volume/extpoint.go 19 20 var drivers = &driverExtpoint{ 21 extensions: make(map[string]volume.Driver), 22 driverLock: &locker.Locker{}, 23 } 24 25 const extName = "VolumeDriver" 26 27 // NewVolumeDriver returns a driver has the given name mapped on the given client. 28 func NewVolumeDriver(name string, baseHostPath string, c client) volume.Driver { 29 proxy := &volumeDriverProxy{c} 30 return &volumeDriverAdapter{name: name, baseHostPath: baseHostPath, proxy: proxy} 31 } 32 33 // volumeDriver defines the available functions that volume plugins must implement. 34 // This interface is only defined to generate the proxy objects. 35 // It's not intended to be public or reused. 36 // nolint: deadcode 37 type volumeDriver interface { 38 // Create a volume with the given name 39 Create(name string, opts map[string]string) (err error) 40 // Remove the volume with the given name 41 Remove(name string) (err error) 42 // Get the mountpoint of the given volume 43 Path(name string) (mountpoint string, err error) 44 // Mount the given volume and return the mountpoint 45 Mount(name, id string) (mountpoint string, err error) 46 // Unmount the given volume 47 Unmount(name, id string) (err error) 48 // List lists all the volumes known to the driver 49 List() (volumes []*proxyVolume, err error) 50 // Get retrieves the volume with the requested name 51 Get(name string) (volume *proxyVolume, err error) 52 // Capabilities gets the list of capabilities of the driver 53 Capabilities() (capabilities volume.Capability, err error) 54 } 55 56 type driverExtpoint struct { 57 extensions map[string]volume.Driver 58 sync.Mutex 59 driverLock *locker.Locker 60 plugingetter getter.PluginGetter 61 } 62 63 // RegisterPluginGetter sets the plugingetter 64 func RegisterPluginGetter(plugingetter getter.PluginGetter) { 65 drivers.plugingetter = plugingetter 66 } 67 68 // Register associates the given driver to the given name, checking if 69 // the name is already associated 70 func Register(extension volume.Driver, name string) bool { 71 if name == "" { 72 return false 73 } 74 75 drivers.Lock() 76 defer drivers.Unlock() 77 78 _, exists := drivers.extensions[name] 79 if exists { 80 return false 81 } 82 83 if err := validateDriver(extension); err != nil { 84 return false 85 } 86 87 drivers.extensions[name] = extension 88 89 return true 90 } 91 92 // Unregister dissociates the name from its driver, if the association exists. 93 func Unregister(name string) bool { 94 drivers.Lock() 95 defer drivers.Unlock() 96 97 _, exists := drivers.extensions[name] 98 if !exists { 99 return false 100 } 101 delete(drivers.extensions, name) 102 return true 103 } 104 105 type driverNotFoundError string 106 107 func (e driverNotFoundError) Error() string { 108 return "volume driver not found: " + string(e) 109 } 110 111 func (driverNotFoundError) NotFound() {} 112 113 // lookup returns the driver associated with the given name. If a 114 // driver with the given name has not been registered it checks if 115 // there is a VolumeDriver plugin available with the given name. 116 func lookup(name string, mode int) (volume.Driver, error) { 117 drivers.driverLock.Lock(name) 118 defer drivers.driverLock.Unlock(name) 119 120 drivers.Lock() 121 ext, ok := drivers.extensions[name] 122 drivers.Unlock() 123 if ok { 124 return ext, nil 125 } 126 if drivers.plugingetter != nil { 127 p, err := drivers.plugingetter.Get(name, extName, mode) 128 if err != nil { 129 return nil, errors.Wrap(err, "error looking up volume plugin "+name) 130 } 131 132 d := NewVolumeDriver(p.Name(), p.BasePath(), p.Client()) 133 if err := validateDriver(d); err != nil { 134 if mode > 0 { 135 // Undo any reference count changes from the initial `Get` 136 if _, err := drivers.plugingetter.Get(name, extName, mode*-1); err != nil { 137 logrus.WithError(err).WithField("action", "validate-driver").WithField("plugin", name).Error("error releasing reference to plugin") 138 } 139 } 140 return nil, err 141 } 142 143 if p.IsV1() { 144 drivers.Lock() 145 drivers.extensions[name] = d 146 drivers.Unlock() 147 } 148 return d, nil 149 } 150 return nil, driverNotFoundError(name) 151 } 152 153 func validateDriver(vd volume.Driver) error { 154 scope := vd.Scope() 155 if scope != volume.LocalScope && scope != volume.GlobalScope { 156 return fmt.Errorf("Driver %q provided an invalid capability scope: %s", vd.Name(), scope) 157 } 158 return nil 159 } 160 161 // GetDriver returns a volume driver by its name. 162 // If the driver is empty, it looks for the local driver. 163 func GetDriver(name string) (volume.Driver, error) { 164 if name == "" { 165 name = volume.DefaultDriverName 166 } 167 return lookup(name, getter.Lookup) 168 } 169 170 // CreateDriver returns a volume driver by its name and increments RefCount. 171 // If the driver is empty, it looks for the local driver. 172 func CreateDriver(name string) (volume.Driver, error) { 173 if name == "" { 174 name = volume.DefaultDriverName 175 } 176 return lookup(name, getter.Acquire) 177 } 178 179 // ReleaseDriver returns a volume driver by its name and decrements RefCount.. 180 // If the driver is empty, it looks for the local driver. 181 func ReleaseDriver(name string) (volume.Driver, error) { 182 if name == "" { 183 name = volume.DefaultDriverName 184 } 185 return lookup(name, getter.Release) 186 } 187 188 // GetDriverList returns list of volume drivers registered. 189 // If no driver is registered, empty string list will be returned. 190 func GetDriverList() []string { 191 var driverList []string 192 drivers.Lock() 193 for driverName := range drivers.extensions { 194 driverList = append(driverList, driverName) 195 } 196 drivers.Unlock() 197 sort.Strings(driverList) 198 return driverList 199 } 200 201 // GetAllDrivers lists all the registered drivers 202 func GetAllDrivers() ([]volume.Driver, error) { 203 var plugins []getter.CompatPlugin 204 if drivers.plugingetter != nil { 205 var err error 206 plugins, err = drivers.plugingetter.GetAllByCap(extName) 207 if err != nil { 208 return nil, fmt.Errorf("error listing plugins: %v", err) 209 } 210 } 211 var ds []volume.Driver 212 213 drivers.Lock() 214 defer drivers.Unlock() 215 216 for _, d := range drivers.extensions { 217 ds = append(ds, d) 218 } 219 220 for _, p := range plugins { 221 name := p.Name() 222 223 if _, ok := drivers.extensions[name]; ok { 224 continue 225 } 226 227 ext := NewVolumeDriver(name, p.BasePath(), p.Client()) 228 if p.IsV1() { 229 drivers.extensions[name] = ext 230 } 231 ds = append(ds, ext) 232 } 233 return ds, nil 234 }