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