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