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