1
0
Fork 0
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:
Alessandro Boch 2016-04-12 15:26:37 -07:00
commit bda53a31f4
7 changed files with 568 additions and 324 deletions

View file

@ -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() {

View file

@ -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
}

View 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)
}

View 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)
}

View file

@ -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

View file

@ -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")

View file

@ -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 {