diff --git a/libnetwork/drivers.go b/libnetwork/drivers.go index 1a4b348303..566d330ff4 100644 --- a/libnetwork/drivers.go +++ b/libnetwork/drivers.go @@ -9,6 +9,7 @@ import ( "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" ) @@ -73,6 +74,7 @@ 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 diff --git a/libnetwork/ipamapi/contract.go b/libnetwork/ipamapi/contract.go index eda461120e..513e482349 100644 --- a/libnetwork/ipamapi/contract.go +++ b/libnetwork/ipamapi/contract.go @@ -15,6 +15,8 @@ import ( const ( // DefaultIPAM is the name of the built-in default ipam driver DefaultIPAM = "default" + // NullIPAM is the name of the built-in null ipam driver + NullIPAM = "null" // PluginEndpointType represents the Endpoint Type used by Plugin system PluginEndpointType = "IpamDriver" // RequestAddressType represents the Address Type used when requesting an address diff --git a/libnetwork/ipams/null/null.go b/libnetwork/ipams/null/null.go new file mode 100644 index 0000000000..60119a36ab --- /dev/null +++ b/libnetwork/ipams/null/null.go @@ -0,0 +1,71 @@ +// Package null implements the null ipam driver. Null ipam driver satisfies ipamapi contract, +// but does not effectively reserve/allocate any address pool or address +package null + +import ( + "fmt" + "net" + + "github.com/docker/libnetwork/discoverapi" + "github.com/docker/libnetwork/ipamapi" + "github.com/docker/libnetwork/types" +) + +var ( + defaultAS = "null" + defaultPool, _ = types.ParseCIDR("0.0.0.0/0") + defaultPoolID = fmt.Sprintf("%s/%s", defaultAS, defaultPool.String()) +) + +type allocator struct{} + +func (a *allocator) GetDefaultAddressSpaces() (string, string, error) { + return defaultAS, defaultAS, nil +} + +func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) { + if addressSpace != defaultAS { + return "", nil, nil, types.BadRequestErrorf("unknown address space: %s", addressSpace) + } + if pool != "" { + return "", nil, nil, types.BadRequestErrorf("null ipam driver does not handle specific address pool requests") + } + if subPool != "" { + return "", nil, nil, types.BadRequestErrorf("null ipam driver does not handle specific address subpool requests") + } + if v6 { + return "", nil, nil, types.BadRequestErrorf("null ipam driver does not handle IPv6 address pool pool requests") + } + return defaultPoolID, defaultPool, nil, nil +} + +func (a *allocator) ReleasePool(poolID string) error { + return nil +} + +func (a *allocator) RequestAddress(poolID string, ip net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) { + if poolID != defaultPoolID { + return nil, nil, types.BadRequestErrorf("unknown pool id: %s", poolID) + } + return nil, nil, nil +} + +func (a *allocator) ReleaseAddress(poolID string, ip net.IP) error { + if poolID != defaultPoolID { + return types.BadRequestErrorf("unknown pool id: %s", poolID) + } + return nil +} + +func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { + return nil +} + +func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { + return nil +} + +// Init registers a remote ipam when its plugin is activated +func Init(ic ipamapi.Callback, l, g interface{}) error { + return ic.RegisterIpamDriver(ipamapi.NullIPAM, &allocator{}) +} diff --git a/libnetwork/ipams/null/null_test.go b/libnetwork/ipams/null/null_test.go new file mode 100644 index 0000000000..d56135e9a5 --- /dev/null +++ b/libnetwork/ipams/null/null_test.go @@ -0,0 +1,61 @@ +package null + +import ( + "testing" + + _ "github.com/docker/libnetwork/testutils" + "github.com/docker/libnetwork/types" +) + +func TestPoolRequest(t *testing.T) { + a := allocator{} + + pid, pool, _, err := a.RequestPool(defaultAS, "", "", nil, false) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(defaultPool, pool) { + t.Fatalf("Unexpected pool returned. Expected %v. Got: %v", defaultPool, pool) + } + if pid != defaultPoolID { + t.Fatalf("Unexpected pool id returned. Expected: %s. Got: %s", defaultPoolID, pid) + } + + _, _, _, err = a.RequestPool("default", "", "", nil, false) + if err == nil { + t.Fatalf("Unexpected success") + } + + _, _, _, err = a.RequestPool(defaultAS, "192.168.0.0/16", "", nil, false) + if err == nil { + t.Fatalf("Unexpected success") + } + + _, _, _, err = a.RequestPool(defaultAS, "", "192.168.0.0/24", nil, false) + if err == nil { + t.Fatalf("Unexpected success") + } + + _, _, _, err = a.RequestPool(defaultAS, "", "", nil, true) + if err == nil { + t.Fatalf("Unexpected success") + } +} + +func TestOtherRequests(t *testing.T) { + a := allocator{} + + ip, _, err := a.RequestAddress(defaultPoolID, nil, nil) + if err != nil { + t.Fatal(err) + } + if ip != nil { + t.Fatalf("Unexpected address returned: %v", ip) + } + + _, _, err = a.RequestAddress("anypid", nil, nil) + if err == nil { + t.Fatalf("Unexpected success") + } + +}