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