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