mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #1093 from mrjana/drvreg
Create driver registry package
This commit is contained in:
commit
bda53a31f4
7 changed files with 568 additions and 324 deletions
|
@ -58,6 +58,7 @@ import (
|
|||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/discoverapi"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/drvregistry"
|
||||
"github.com/docker/libnetwork/hostdiscovery"
|
||||
"github.com/docker/libnetwork/ipamapi"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
|
@ -119,26 +120,11 @@ type NetworkWalker func(nw Network) bool
|
|||
// When the function returns true, the walk will stop.
|
||||
type SandboxWalker func(sb Sandbox) bool
|
||||
|
||||
type driverData struct {
|
||||
driver driverapi.Driver
|
||||
capability driverapi.Capability
|
||||
}
|
||||
|
||||
type ipamData struct {
|
||||
driver ipamapi.Ipam
|
||||
capability *ipamapi.Capability
|
||||
// default address spaces are provided by ipam driver at registration time
|
||||
defaultLocalAddressSpace, defaultGlobalAddressSpace string
|
||||
}
|
||||
|
||||
type driverTable map[string]*driverData
|
||||
type ipamTable map[string]*ipamData
|
||||
type sandboxTable map[string]*sandbox
|
||||
|
||||
type controller struct {
|
||||
id string
|
||||
drivers driverTable
|
||||
ipamDrivers ipamTable
|
||||
drvRegistry *drvregistry.DrvRegistry
|
||||
sandboxes sandboxTable
|
||||
cfg *config.Config
|
||||
stores []datastore.DataStore
|
||||
|
@ -153,14 +139,17 @@ type controller struct {
|
|||
sync.Mutex
|
||||
}
|
||||
|
||||
type initializer struct {
|
||||
fn drvregistry.InitFunc
|
||||
ntype string
|
||||
}
|
||||
|
||||
// New creates a new instance of network controller.
|
||||
func New(cfgOptions ...config.Option) (NetworkController, error) {
|
||||
c := &controller{
|
||||
id: stringid.GenerateRandomID(),
|
||||
cfg: config.ParseConfigOptions(cfgOptions...),
|
||||
sandboxes: sandboxTable{},
|
||||
drivers: driverTable{},
|
||||
ipamDrivers: ipamTable{},
|
||||
svcDb: make(map[string]svcInfo),
|
||||
}
|
||||
|
||||
|
@ -168,6 +157,26 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
drvRegistry, err := drvregistry.New(c.getStore(datastore.LocalScope), c.getStore(datastore.GlobalScope), c.RegisterDriver, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, i := range getInitializers() {
|
||||
var dcfg map[string]interface{}
|
||||
|
||||
// External plugins don't need config passed through daemon. They can
|
||||
// bootstrap themselves
|
||||
if i.ntype != "remote" {
|
||||
dcfg = c.makeDriverConfig(i.ntype)
|
||||
}
|
||||
|
||||
if err := drvRegistry.AddDriver(i.ntype, i.fn, dcfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
c.drvRegistry = drvRegistry
|
||||
|
||||
if c.cfg != nil && c.cfg.Cluster.Watcher != nil {
|
||||
if err := c.initDiscovery(c.cfg.Cluster.Watcher); err != nil {
|
||||
// Failing to initialize discovery is a bad situation to be in.
|
||||
|
@ -176,15 +185,6 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if err := initDrivers(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := initIpams(c, c.getStore(datastore.LocalScope),
|
||||
c.getStore(datastore.GlobalScope)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.sandboxCleanup()
|
||||
c.cleanupLocalEndpoints()
|
||||
c.networkCleanup()
|
||||
|
@ -196,6 +196,43 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
|
|||
return c, nil
|
||||
}
|
||||
|
||||
func (c *controller) makeDriverConfig(ntype string) map[string]interface{} {
|
||||
if c.cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
config := make(map[string]interface{})
|
||||
|
||||
for _, label := range c.cfg.Daemon.Labels {
|
||||
if !strings.HasPrefix(netlabel.Key(label), netlabel.DriverPrefix+"."+ntype) {
|
||||
continue
|
||||
}
|
||||
|
||||
config[netlabel.Key(label)] = netlabel.Value(label)
|
||||
}
|
||||
|
||||
drvCfg, ok := c.cfg.Daemon.DriverCfg[ntype]
|
||||
if ok {
|
||||
for k, v := range drvCfg.(map[string]interface{}) {
|
||||
config[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range c.cfg.Scopes {
|
||||
if !v.IsValid() {
|
||||
continue
|
||||
}
|
||||
config[netlabel.MakeKVClient(k)] = discoverapi.DatastoreConfigData{
|
||||
Scope: k,
|
||||
Provider: v.Client.Provider,
|
||||
Address: v.Client.Address,
|
||||
Config: v.Client.Config,
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
var procReloadConfig = make(chan (bool), 1)
|
||||
|
||||
func (c *controller) ReloadConfiguration(cfgOptions ...config.Option) error {
|
||||
|
@ -255,19 +292,21 @@ func (c *controller) ReloadConfiguration(cfgOptions ...config.Option) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
for nm, id := range c.getIpamDrivers() {
|
||||
err := id.driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig)
|
||||
c.drvRegistry.WalkIPAMs(func(name string, driver ipamapi.Ipam, cap *ipamapi.Capability) bool {
|
||||
err := driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to set datastore in driver %s: %v", nm, err)
|
||||
}
|
||||
log.Errorf("Failed to set datastore in driver %s: %v", name, err)
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
for nm, id := range c.getNetDrivers() {
|
||||
err := id.driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig)
|
||||
c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool {
|
||||
err := driver.DiscoverNew(discoverapi.DatastoreConfig, *dsConfig)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to set datastore in driver %s: %v", nm, err)
|
||||
}
|
||||
log.Errorf("Failed to set datastore in driver %s: %v", name, err)
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -333,34 +372,30 @@ func (c *controller) hostLeaveCallback(nodes []net.IP) {
|
|||
}
|
||||
|
||||
func (c *controller) processNodeDiscovery(nodes []net.IP, add bool) {
|
||||
c.Lock()
|
||||
drivers := []*driverData{}
|
||||
for _, d := range c.drivers {
|
||||
drivers = append(drivers, d)
|
||||
}
|
||||
c.Unlock()
|
||||
|
||||
for _, d := range drivers {
|
||||
c.pushNodeDiscovery(d, nodes, add)
|
||||
}
|
||||
c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool {
|
||||
c.pushNodeDiscovery(driver, capability, nodes, add)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
func (c *controller) pushNodeDiscovery(d *driverData, nodes []net.IP, add bool) {
|
||||
func (c *controller) pushNodeDiscovery(d driverapi.Driver, cap driverapi.Capability, nodes []net.IP, add bool) {
|
||||
var self net.IP
|
||||
if c.cfg != nil {
|
||||
addr := strings.Split(c.cfg.Cluster.Address, ":")
|
||||
self = net.ParseIP(addr[0])
|
||||
}
|
||||
if d == nil || d.capability.DataScope != datastore.GlobalScope || nodes == nil {
|
||||
|
||||
if d == nil || cap.DataScope != datastore.GlobalScope || nodes == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, node := range nodes {
|
||||
nodeData := discoverapi.NodeDiscoveryData{Address: node.String(), Self: node.Equal(self)}
|
||||
var err error
|
||||
if add {
|
||||
err = d.driver.DiscoverNew(discoverapi.NodeDiscovery, nodeData)
|
||||
err = d.DiscoverNew(discoverapi.NodeDiscovery, nodeData)
|
||||
} else {
|
||||
err = d.driver.DiscoverDelete(discoverapi.NodeDiscovery, nodeData)
|
||||
err = d.DiscoverDelete(discoverapi.NodeDiscovery, nodeData)
|
||||
}
|
||||
if err != nil {
|
||||
log.Debugf("discovery notification error : %v", err)
|
||||
|
@ -378,59 +413,17 @@ func (c *controller) Config() config.Config {
|
|||
}
|
||||
|
||||
func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error {
|
||||
if !config.IsValidName(networkType) {
|
||||
return ErrInvalidName(networkType)
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
if _, ok := c.drivers[networkType]; ok {
|
||||
c.Unlock()
|
||||
return driverapi.ErrActiveRegistration(networkType)
|
||||
}
|
||||
dData := &driverData{driver, capability}
|
||||
c.drivers[networkType] = dData
|
||||
hd := c.discovery
|
||||
c.Unlock()
|
||||
|
||||
if hd != nil {
|
||||
c.pushNodeDiscovery(dData, hd.Fetch(), true)
|
||||
c.pushNodeDiscovery(driver, capability, hd.Fetch(), true)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) registerIpamDriver(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error {
|
||||
if !config.IsValidName(name) {
|
||||
return ErrInvalidName(name)
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
_, ok := c.ipamDrivers[name]
|
||||
c.Unlock()
|
||||
if ok {
|
||||
return types.ForbiddenErrorf("ipam driver %q already registered", name)
|
||||
}
|
||||
locAS, glbAS, err := driver.GetDefaultAddressSpaces()
|
||||
if err != nil {
|
||||
return types.InternalErrorf("ipam driver %q failed to return default address spaces: %v", name, err)
|
||||
}
|
||||
c.Lock()
|
||||
c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS, capability: caps}
|
||||
c.Unlock()
|
||||
|
||||
log.Debugf("Registering ipam driver: %q", name)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error {
|
||||
return c.registerIpamDriver(name, driver, &ipamapi.Capability{})
|
||||
}
|
||||
|
||||
func (c *controller) RegisterIpamDriverWithCapabilities(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error {
|
||||
return c.registerIpamDriver(name, driver, caps)
|
||||
}
|
||||
|
||||
// NewNetwork creates a new network of the specified network type. The options
|
||||
// are network specific and modeled in a generic way.
|
||||
func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
|
||||
|
@ -745,78 +738,47 @@ func SandboxKeyWalker(out *Sandbox, key string) SandboxWalker {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *controller) loadDriver(networkType string) (*driverData, error) {
|
||||
func (c *controller) loadDriver(networkType string) error {
|
||||
// Plugins pkg performs lazy loading of plugins that acts as remote drivers.
|
||||
// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
|
||||
_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
|
||||
if err != nil {
|
||||
if err == plugins.ErrNotFound {
|
||||
return nil, types.NotFoundErrorf(err.Error())
|
||||
return types.NotFoundErrorf(err.Error())
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
dd, ok := c.drivers[networkType]
|
||||
if !ok {
|
||||
return nil, ErrInvalidNetworkDriver(networkType)
|
||||
}
|
||||
return dd, nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *controller) loadIpamDriver(name string) (*ipamData, error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) loadIPAMDriver(name string) error {
|
||||
if _, err := plugins.Get(name, ipamapi.PluginEndpointType); err != nil {
|
||||
if err == plugins.ErrNotFound {
|
||||
return nil, types.NotFoundErrorf(err.Error())
|
||||
return types.NotFoundErrorf(err.Error())
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
c.Lock()
|
||||
id, ok := c.ipamDrivers[name]
|
||||
c.Unlock()
|
||||
if !ok {
|
||||
return nil, types.BadRequestErrorf("invalid ipam driver: %q", name)
|
||||
}
|
||||
return id, nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *controller) getIPAM(name string) (id *ipamData, err error) {
|
||||
var ok bool
|
||||
c.Lock()
|
||||
id, ok = c.ipamDrivers[name]
|
||||
c.Unlock()
|
||||
if !ok {
|
||||
id, err = c.loadIpamDriver(name)
|
||||
}
|
||||
return id, err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) getIpamDriver(name string) (ipamapi.Ipam, error) {
|
||||
id, err := c.getIPAM(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return id.driver, nil
|
||||
func (c *controller) getIPAMDriver(name string) (ipamapi.Ipam, *ipamapi.Capability, error) {
|
||||
id, cap := c.drvRegistry.IPAM(name)
|
||||
if id == nil {
|
||||
// Might be a plugin name. Try loading it
|
||||
if err := c.loadIPAMDriver(name); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
func (c *controller) getIpamDrivers() ipamTable {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
table := ipamTable{}
|
||||
for i, d := range c.ipamDrivers {
|
||||
table[i] = d
|
||||
// Now that we resolved the plugin, try again looking up the registry
|
||||
id, cap = c.drvRegistry.IPAM(name)
|
||||
if id == nil {
|
||||
return nil, nil, types.BadRequestErrorf("invalid ipam driver: %q", name)
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
func (c *controller) getNetDrivers() driverTable {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
table := driverTable{}
|
||||
for i, d := range c.drivers {
|
||||
table[i] = d
|
||||
}
|
||||
return table
|
||||
return id, cap, nil
|
||||
}
|
||||
|
||||
func (c *controller) Stop() {
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
package libnetwork
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/libnetwork/discoverapi"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/ipamapi"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
|
||||
builtinIpam "github.com/docker/libnetwork/ipams/builtin"
|
||||
nullIpam "github.com/docker/libnetwork/ipams/null"
|
||||
remoteIpam "github.com/docker/libnetwork/ipams/remote"
|
||||
)
|
||||
|
||||
type initializer struct {
|
||||
fn func(driverapi.DriverCallback, map[string]interface{}) error
|
||||
ntype string
|
||||
}
|
||||
|
||||
func initDrivers(c *controller) error {
|
||||
for _, i := range getInitializers() {
|
||||
if err := i.fn(c, makeDriverConfig(c, i.ntype)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeDriverConfig(c *controller, ntype string) map[string]interface{} {
|
||||
if c.cfg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
config := make(map[string]interface{})
|
||||
|
||||
for _, label := range c.cfg.Daemon.Labels {
|
||||
if !strings.HasPrefix(netlabel.Key(label), netlabel.DriverPrefix+"."+ntype) {
|
||||
continue
|
||||
}
|
||||
|
||||
config[netlabel.Key(label)] = netlabel.Value(label)
|
||||
}
|
||||
|
||||
drvCfg, ok := c.cfg.Daemon.DriverCfg[ntype]
|
||||
if ok {
|
||||
for k, v := range drvCfg.(map[string]interface{}) {
|
||||
config[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// We don't send datastore configs to external plugins
|
||||
if ntype == "remote" {
|
||||
return config
|
||||
}
|
||||
|
||||
for k, v := range c.cfg.Scopes {
|
||||
if !v.IsValid() {
|
||||
continue
|
||||
}
|
||||
config[netlabel.MakeKVClient(k)] = discoverapi.DatastoreConfigData{
|
||||
Scope: k,
|
||||
Provider: v.Client.Provider,
|
||||
Address: v.Client.Address,
|
||||
Config: v.Client.Config,
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
func initIpams(ic ipamapi.Callback, lDs, gDs interface{}) error {
|
||||
for _, fn := range [](func(ipamapi.Callback, interface{}, interface{}) error){
|
||||
builtinIpam.Init,
|
||||
remoteIpam.Init,
|
||||
nullIpam.Init,
|
||||
} {
|
||||
if err := fn(ic, lDs, gDs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
241
libnetwork/drvregistry/drvregistry.go
Normal file
241
libnetwork/drvregistry/drvregistry.go
Normal file
|
@ -0,0 +1,241 @@
|
|||
package drvregistry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/ipamapi"
|
||||
"github.com/docker/libnetwork/types"
|
||||
|
||||
builtinIpam "github.com/docker/libnetwork/ipams/builtin"
|
||||
nullIpam "github.com/docker/libnetwork/ipams/null"
|
||||
remoteIpam "github.com/docker/libnetwork/ipams/remote"
|
||||
)
|
||||
|
||||
type driverData struct {
|
||||
driver driverapi.Driver
|
||||
capability driverapi.Capability
|
||||
}
|
||||
|
||||
type ipamData struct {
|
||||
driver ipamapi.Ipam
|
||||
capability *ipamapi.Capability
|
||||
// default address spaces are provided by ipam driver at registration time
|
||||
defaultLocalAddressSpace, defaultGlobalAddressSpace string
|
||||
}
|
||||
|
||||
type driverTable map[string]*driverData
|
||||
type ipamTable map[string]*ipamData
|
||||
|
||||
// DrvRegistry holds the registry of all network drivers and IPAM drivers that it knows about.
|
||||
type DrvRegistry struct {
|
||||
sync.Mutex
|
||||
drivers driverTable
|
||||
ipamDrivers ipamTable
|
||||
dfn DriverNotifyFunc
|
||||
ifn IPAMNotifyFunc
|
||||
}
|
||||
|
||||
// Functors definition
|
||||
|
||||
// InitFunc defines the driver initialization function signature.
|
||||
type InitFunc func(driverapi.DriverCallback, map[string]interface{}) error
|
||||
|
||||
// IPAMWalkFunc defines the IPAM driver table walker function signature.
|
||||
type IPAMWalkFunc func(name string, driver ipamapi.Ipam, cap *ipamapi.Capability) bool
|
||||
|
||||
// DriverWalkFunc defines the network driver table walker function signature.
|
||||
type DriverWalkFunc func(name string, driver driverapi.Driver, capability driverapi.Capability) bool
|
||||
|
||||
// IPAMNotifyFunc defines the notify function signature when a new IPAM driver gets registered.
|
||||
type IPAMNotifyFunc func(name string, driver ipamapi.Ipam, cap *ipamapi.Capability) error
|
||||
|
||||
// DriverNotifyFunc defines the notify function signature when a new network driver gets registered.
|
||||
type DriverNotifyFunc func(name string, driver driverapi.Driver, capability driverapi.Capability) error
|
||||
|
||||
// New retruns a new driver registry handle.
|
||||
func New(lDs, gDs interface{}, dfn DriverNotifyFunc, ifn IPAMNotifyFunc) (*DrvRegistry, error) {
|
||||
r := &DrvRegistry{
|
||||
drivers: make(driverTable),
|
||||
ipamDrivers: make(ipamTable),
|
||||
dfn: dfn,
|
||||
ifn: ifn,
|
||||
}
|
||||
|
||||
if err := r.initIPAMs(lDs, gDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// AddDriver adds a network driver to the registry.
|
||||
func (r *DrvRegistry) AddDriver(ntype string, fn InitFunc, config map[string]interface{}) error {
|
||||
return fn(r, config)
|
||||
}
|
||||
|
||||
// WalkIPAMs walks the IPAM drivers registered in the registry and invokes the passed walk function and each one of them.
|
||||
func (r *DrvRegistry) WalkIPAMs(ifn IPAMWalkFunc) {
|
||||
type ipamVal struct {
|
||||
name string
|
||||
data *ipamData
|
||||
}
|
||||
|
||||
r.Lock()
|
||||
ivl := make([]ipamVal, 0, len(r.ipamDrivers))
|
||||
for k, v := range r.ipamDrivers {
|
||||
ivl = append(ivl, ipamVal{name: k, data: v})
|
||||
}
|
||||
r.Unlock()
|
||||
|
||||
for _, iv := range ivl {
|
||||
if ifn(iv.name, iv.data.driver, iv.data.capability) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WalkDrivers walks the network drivers registered in the registry and invokes the passed walk function and each one of them.
|
||||
func (r *DrvRegistry) WalkDrivers(dfn DriverWalkFunc) {
|
||||
type driverVal struct {
|
||||
name string
|
||||
data *driverData
|
||||
}
|
||||
|
||||
r.Lock()
|
||||
dvl := make([]driverVal, 0, len(r.drivers))
|
||||
for k, v := range r.drivers {
|
||||
dvl = append(dvl, driverVal{name: k, data: v})
|
||||
}
|
||||
r.Unlock()
|
||||
|
||||
for _, dv := range dvl {
|
||||
if dfn(dv.name, dv.data.driver, dv.data.capability) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Driver returns the actual network driver instance and its capability which registered with the passed name.
|
||||
func (r *DrvRegistry) Driver(name string) (driverapi.Driver, *driverapi.Capability) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
d, ok := r.drivers[name]
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return d.driver, &d.capability
|
||||
}
|
||||
|
||||
// IPAM returns the actual IPAM driver instance and its capability which registered with the passed name.
|
||||
func (r *DrvRegistry) IPAM(name string) (ipamapi.Ipam, *ipamapi.Capability) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
i, ok := r.ipamDrivers[name]
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return i.driver, i.capability
|
||||
}
|
||||
|
||||
// IPAMDefaultAddressSpaces returns the default address space strings for the passed IPAM driver name.
|
||||
func (r *DrvRegistry) IPAMDefaultAddressSpaces(name string) (string, string, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
i, ok := r.ipamDrivers[name]
|
||||
if !ok {
|
||||
return "", "", fmt.Errorf("ipam %s not found", name)
|
||||
}
|
||||
|
||||
return i.defaultLocalAddressSpace, i.defaultGlobalAddressSpace, nil
|
||||
}
|
||||
|
||||
func (r *DrvRegistry) initIPAMs(lDs, gDs interface{}) error {
|
||||
for _, fn := range [](func(ipamapi.Callback, interface{}, interface{}) error){
|
||||
builtinIpam.Init,
|
||||
remoteIpam.Init,
|
||||
nullIpam.Init,
|
||||
} {
|
||||
if err := fn(r, lDs, gDs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterDriver registers the network driver when it gets discovered.
|
||||
func (r *DrvRegistry) RegisterDriver(ntype string, driver driverapi.Driver, capability driverapi.Capability) error {
|
||||
if strings.TrimSpace(ntype) == "" {
|
||||
return fmt.Errorf("network type string cannot be empty")
|
||||
}
|
||||
|
||||
r.Lock()
|
||||
_, ok := r.drivers[ntype]
|
||||
r.Unlock()
|
||||
|
||||
if ok {
|
||||
return driverapi.ErrActiveRegistration(ntype)
|
||||
}
|
||||
|
||||
if r.dfn != nil {
|
||||
if err := r.dfn(ntype, driver, capability); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
dData := &driverData{driver, capability}
|
||||
|
||||
r.Lock()
|
||||
r.drivers[ntype] = dData
|
||||
r.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *DrvRegistry) registerIpamDriver(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error {
|
||||
if strings.TrimSpace(name) == "" {
|
||||
return fmt.Errorf("ipam driver name string cannot be empty")
|
||||
}
|
||||
|
||||
r.Lock()
|
||||
_, ok := r.ipamDrivers[name]
|
||||
r.Unlock()
|
||||
if ok {
|
||||
return types.ForbiddenErrorf("ipam driver %q already registered", name)
|
||||
}
|
||||
|
||||
locAS, glbAS, err := driver.GetDefaultAddressSpaces()
|
||||
if err != nil {
|
||||
return types.InternalErrorf("ipam driver %q failed to return default address spaces: %v", name, err)
|
||||
}
|
||||
|
||||
if r.ifn != nil {
|
||||
if err := r.ifn(name, driver, caps); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
r.Lock()
|
||||
r.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS, capability: caps}
|
||||
r.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterIpamDriver registers the IPAM driver discovered with default capabilities.
|
||||
func (r *DrvRegistry) RegisterIpamDriver(name string, driver ipamapi.Ipam) error {
|
||||
return r.registerIpamDriver(name, driver, &ipamapi.Capability{})
|
||||
}
|
||||
|
||||
// RegisterIpamDriverWithCapabilities registers the IPAM driver discovered with specified capabilities.
|
||||
func (r *DrvRegistry) RegisterIpamDriverWithCapabilities(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error {
|
||||
return r.registerIpamDriver(name, driver, caps)
|
||||
}
|
161
libnetwork/drvregistry/drvregistry_test.go
Normal file
161
libnetwork/drvregistry/drvregistry_test.go
Normal file
|
@ -0,0 +1,161 @@
|
|||
package drvregistry
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/discoverapi"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/ipamapi"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var runningInContainer = flag.Bool("incontainer", false,
|
||||
"Indicates if the test is running in a container")
|
||||
|
||||
const mockDriverName = "mock-driver"
|
||||
|
||||
type mockDriver struct{}
|
||||
|
||||
var md = mockDriver{}
|
||||
|
||||
func mockDriverInit(reg driverapi.DriverCallback, opt map[string]interface{}) error {
|
||||
return reg.RegisterDriver(mockDriverName, &md, driverapi.Capability{DataScope: datastore.LocalScope})
|
||||
}
|
||||
|
||||
func (m *mockDriver) CreateNetwork(nid string, options map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockDriver) DeleteNetwork(nid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockDriver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, options map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockDriver) DeleteEndpoint(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockDriver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *mockDriver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockDriver) Leave(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockDriver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockDriver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockDriver) Type() string {
|
||||
return mockDriverName
|
||||
}
|
||||
|
||||
func (m *mockDriver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockDriver) RevokeExternalConnectivity(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getNew(t *testing.T) *DrvRegistry {
|
||||
reg, err := New(nil, nil, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return reg
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
getNew(t)
|
||||
}
|
||||
|
||||
func TestAddDriver(t *testing.T) {
|
||||
reg := getNew(t)
|
||||
|
||||
err := reg.AddDriver(mockDriverName, mockDriverInit, nil)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestAddDuplicateDriver(t *testing.T) {
|
||||
reg := getNew(t)
|
||||
|
||||
err := reg.AddDriver(mockDriverName, mockDriverInit, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Try adding the same driver
|
||||
err = reg.AddDriver(mockDriverName, mockDriverInit, nil)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestIPAMDefaultAddressSpaces(t *testing.T) {
|
||||
reg := getNew(t)
|
||||
|
||||
as1, as2, err := reg.IPAMDefaultAddressSpaces("default")
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, as1, "")
|
||||
assert.NotEqual(t, as2, "")
|
||||
}
|
||||
|
||||
func TestDriver(t *testing.T) {
|
||||
reg := getNew(t)
|
||||
|
||||
err := reg.AddDriver(mockDriverName, mockDriverInit, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
d, cap := reg.Driver(mockDriverName)
|
||||
assert.NotEqual(t, d, nil)
|
||||
assert.NotEqual(t, cap, nil)
|
||||
}
|
||||
|
||||
func TestIPAM(t *testing.T) {
|
||||
reg := getNew(t)
|
||||
|
||||
i, cap := reg.IPAM("default")
|
||||
assert.NotEqual(t, i, nil)
|
||||
assert.NotEqual(t, cap, nil)
|
||||
}
|
||||
|
||||
func TestWalkIPAMs(t *testing.T) {
|
||||
reg := getNew(t)
|
||||
|
||||
ipams := make([]string, 0, 2)
|
||||
reg.WalkIPAMs(func(name string, driver ipamapi.Ipam, cap *ipamapi.Capability) bool {
|
||||
ipams = append(ipams, name)
|
||||
return false
|
||||
})
|
||||
|
||||
sort.Strings(ipams)
|
||||
assert.Equal(t, ipams, []string{"default", "null"})
|
||||
}
|
||||
|
||||
func TestWalkDrivers(t *testing.T) {
|
||||
reg := getNew(t)
|
||||
|
||||
err := reg.AddDriver(mockDriverName, mockDriverInit, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
var driverName string
|
||||
reg.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool {
|
||||
driverName = name
|
||||
return false
|
||||
})
|
||||
|
||||
assert.Equal(t, driverName, mockDriverName)
|
||||
}
|
|
@ -981,7 +981,7 @@ func (ep *endpoint) releaseAddress() {
|
|||
|
||||
log.Debugf("Releasing addresses for endpoint %s's interface on network %s", ep.Name(), n.Name())
|
||||
|
||||
ipam, err := n.getController().getIpamDriver(n.ipamType)
|
||||
ipam, _, err := n.getController().getIPAMDriver(n.ipamType)
|
||||
if err != nil {
|
||||
log.Warnf("Failed to retrieve ipam driver to release interface address on delete of endpoint %s (%s): %v", ep.Name(), ep.ID(), err)
|
||||
return
|
||||
|
|
|
@ -15,50 +15,6 @@ import (
|
|||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
func TestDriverRegistration(t *testing.T) {
|
||||
bridgeNetType := "bridge"
|
||||
c, err := New()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Stop()
|
||||
err = c.(*controller).RegisterDriver(bridgeNetType, nil, driverapi.Capability{})
|
||||
if err == nil {
|
||||
t.Fatalf("Expecting the RegisterDriver to fail for %s", bridgeNetType)
|
||||
}
|
||||
if _, ok := err.(driverapi.ErrActiveRegistration); !ok {
|
||||
t.Fatalf("Failed for unexpected reason: %v", err)
|
||||
}
|
||||
err = c.(*controller).RegisterDriver("test-dummy", nil, driverapi.Capability{})
|
||||
if err != nil {
|
||||
t.Fatalf("Test failed with an error %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIpamDriverRegistration(t *testing.T) {
|
||||
c, err := New()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Stop()
|
||||
|
||||
err = c.(*controller).RegisterIpamDriver("", nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected failure, but succeeded")
|
||||
}
|
||||
if _, ok := err.(types.BadRequestError); !ok {
|
||||
t.Fatalf("Failed for unexpected reason: %v", err)
|
||||
}
|
||||
|
||||
err = c.(*controller).RegisterIpamDriver(ipamapi.DefaultIPAM, nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected failure, but succeeded")
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("Failed for unexpected reason: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkMarshalling(t *testing.T) {
|
||||
n := &network{
|
||||
name: "Miao",
|
||||
|
@ -375,8 +331,10 @@ func TestIpamReleaseOnNetDriverFailures(t *testing.T) {
|
|||
defer c.Stop()
|
||||
|
||||
cc := c.(*controller)
|
||||
bd := badDriver{failNetworkCreation: true}
|
||||
cc.drivers[badDriverName] = &driverData{driver: &bd, capability: driverapi.Capability{DataScope: datastore.LocalScope}}
|
||||
|
||||
if err := cc.drvRegistry.AddDriver(badDriverName, badDriverInit, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test whether ipam state release is invoked on network create failure from net driver
|
||||
// by checking whether subsequent network creation requesting same gateway IP succeeds
|
||||
|
@ -429,6 +387,12 @@ type badDriver struct {
|
|||
failNetworkCreation bool
|
||||
}
|
||||
|
||||
var bd = badDriver{failNetworkCreation: true}
|
||||
|
||||
func badDriverInit(reg driverapi.DriverCallback, opt map[string]interface{}) error {
|
||||
return reg.RegisterDriver(badDriverName, &bd, driverapi.Capability{DataScope: datastore.LocalScope})
|
||||
}
|
||||
|
||||
func (b *badDriver) CreateNetwork(nid string, options map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
||||
if b.failNetworkCreation {
|
||||
return fmt.Errorf("I will not create any network")
|
||||
|
|
|
@ -620,49 +620,52 @@ func (n *network) processOptions(options ...NetworkOption) {
|
|||
}
|
||||
}
|
||||
|
||||
func (n *network) driverScope() string {
|
||||
func (n *network) resolveDriver(name string, load bool) (driverapi.Driver, *driverapi.Capability, error) {
|
||||
c := n.getController()
|
||||
|
||||
c.Lock()
|
||||
// Check if a driver for the specified network type is available
|
||||
dd, ok := c.drivers[n.networkType]
|
||||
c.Unlock()
|
||||
|
||||
if !ok {
|
||||
d, cap := c.drvRegistry.Driver(name)
|
||||
if d == nil {
|
||||
if load {
|
||||
var err error
|
||||
dd, err = c.loadDriver(n.networkType)
|
||||
err = c.loadDriver(name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
d, cap = c.drvRegistry.Driver(name)
|
||||
if d == nil {
|
||||
return nil, nil, fmt.Errorf("could not resolve driver %s in registry", name)
|
||||
}
|
||||
} else {
|
||||
// don't fail if driver loading is not required
|
||||
return nil, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
return d, cap, nil
|
||||
}
|
||||
|
||||
func (n *network) driverScope() string {
|
||||
_, cap, err := n.resolveDriver(n.networkType, true)
|
||||
if err != nil {
|
||||
// If driver could not be resolved simply return an empty string
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
return dd.capability.DataScope
|
||||
return cap.DataScope
|
||||
}
|
||||
|
||||
func (n *network) driver(load bool) (driverapi.Driver, error) {
|
||||
c := n.getController()
|
||||
|
||||
c.Lock()
|
||||
// Check if a driver for the specified network type is available
|
||||
dd, ok := c.drivers[n.networkType]
|
||||
c.Unlock()
|
||||
|
||||
if !ok && load {
|
||||
var err error
|
||||
dd, err = c.loadDriver(n.networkType)
|
||||
d, cap, err := n.resolveDriver(n.networkType, load)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !ok {
|
||||
// don't fail if driver loading is not required
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
n.scope = dd.capability.DataScope
|
||||
n.scope = cap.DataScope
|
||||
n.Unlock()
|
||||
return dd.driver, nil
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (n *network) Delete() error {
|
||||
|
@ -786,12 +789,12 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
|
|||
}
|
||||
}
|
||||
|
||||
ipam, err := n.getController().getIPAM(n.ipamType)
|
||||
ipam, cap, err := n.getController().getIPAMDriver(n.ipamType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ipam.capability.RequiresMACAddress {
|
||||
if cap.RequiresMACAddress {
|
||||
if ep.iface.mac == nil {
|
||||
ep.iface.mac = netutils.GenerateRandomMAC()
|
||||
}
|
||||
|
@ -801,7 +804,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
|
|||
ep.ipamOptions[netlabel.MacAddress] = ep.iface.mac.String()
|
||||
}
|
||||
|
||||
if err = ep.assignAddress(ipam.driver, true, n.enableIPv6 && !n.postIPv6); err != nil {
|
||||
if err = ep.assignAddress(ipam, true, n.enableIPv6 && !n.postIPv6); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
|
@ -821,7 +824,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
|
|||
}
|
||||
}()
|
||||
|
||||
if err = ep.assignAddress(ipam.driver, false, n.enableIPv6 && n.postIPv6); err != nil {
|
||||
if err = ep.assignAddress(ipam, false, n.enableIPv6 && n.postIPv6); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -1065,7 +1068,7 @@ func (n *network) ipamAllocate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
ipam, err := n.getController().getIpamDriver(n.ipamType)
|
||||
ipam, _, err := n.getController().getIPAMDriver(n.ipamType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1189,7 +1192,7 @@ func (n *network) ipamRelease() {
|
|||
if n.Type() == "host" || n.Type() == "null" {
|
||||
return
|
||||
}
|
||||
ipam, err := n.getController().getIpamDriver(n.ipamType)
|
||||
ipam, _, err := n.getController().getIPAMDriver(n.ipamType)
|
||||
if err != nil {
|
||||
log.Warnf("Failed to retrieve ipam driver to release address pool(s) on delete of network %s (%s): %v", n.Name(), n.ID(), err)
|
||||
return
|
||||
|
@ -1279,17 +1282,14 @@ func (n *network) getIPData(ipVer int) []driverapi.IPAMData {
|
|||
}
|
||||
|
||||
func (n *network) deriveAddressSpace() (string, error) {
|
||||
c := n.getController()
|
||||
c.Lock()
|
||||
ipd, ok := c.ipamDrivers[n.ipamType]
|
||||
c.Unlock()
|
||||
if !ok {
|
||||
return "", types.NotFoundErrorf("could not find ipam driver %s to get default address space", n.ipamType)
|
||||
local, global, err := n.getController().drvRegistry.IPAMDefaultAddressSpaces(n.ipamType)
|
||||
if err != nil {
|
||||
return "", types.NotFoundErrorf("failed to get default address space: %v", err)
|
||||
}
|
||||
if n.DataScope() == datastore.GlobalScope {
|
||||
return ipd.defaultGlobalAddressSpace, nil
|
||||
return global, nil
|
||||
}
|
||||
return ipd.defaultLocalAddressSpace, nil
|
||||
return local, nil
|
||||
}
|
||||
|
||||
func (n *network) Info() NetworkInfo {
|
||||
|
|
Loading…
Add table
Reference in a new issue