7 "github.com/Sirupsen/logrus"
8 "github.com/docker/docker/pkg/plugins"
9 "github.com/docker/libnetwork/discoverapi"
10 "github.com/docker/libnetwork/ipamapi"
11 "github.com/docker/libnetwork/ipams/remote/api"
12 "github.com/docker/libnetwork/types"
15 type allocator struct {
16 endpoint *plugins.Client
20 // PluginResponse is the interface for the plugin request responses
21 type PluginResponse interface {
26 func newAllocator(name string, client *plugins.Client) ipamapi.Ipam {
27 a := &allocator{name: name, endpoint: client}
31 // Init registers a remote ipam when its plugin is activated
32 func Init(cb ipamapi.Callback, l, g interface{}) error {
34 newPluginHandler := func(name string, client *plugins.Client) {
35 a := newAllocator(name, client)
36 if cps, err := a.(*allocator).getCapabilities(); err == nil {
37 if err := cb.RegisterIpamDriverWithCapabilities(name, a, cps); err != nil {
38 logrus.Errorf("error registering remote ipam driver %s due to %v", name, err)
41 logrus.Infof("remote ipam driver %s does not support capabilities", name)
43 if err := cb.RegisterIpamDriver(name, a); err != nil {
44 logrus.Errorf("error registering remote ipam driver %s due to %v", name, err)
49 // Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins.
50 handleFunc := plugins.Handle
51 if pg := cb.GetPluginGetter(); pg != nil {
52 handleFunc = pg.Handle
53 activePlugins := pg.GetAllManagedPluginsByCap(ipamapi.PluginEndpointType)
54 for _, ap := range activePlugins {
55 newPluginHandler(ap.Name(), ap.Client())
58 handleFunc(ipamapi.PluginEndpointType, newPluginHandler)
62 func (a *allocator) call(methodName string, arg interface{}, retVal PluginResponse) error {
63 method := ipamapi.PluginEndpointType + "." + methodName
64 err := a.endpoint.Call(method, arg, retVal)
68 if !retVal.IsSuccess() {
69 return fmt.Errorf("remote: %s", retVal.GetError())
74 func (a *allocator) getCapabilities() (*ipamapi.Capability, error) {
75 var res api.GetCapabilityResponse
76 if err := a.call("GetCapabilities", nil, &res); err != nil {
79 return res.ToCapability(), nil
82 // GetDefaultAddressSpaces returns the local and global default address spaces
83 func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
84 res := &api.GetAddressSpacesResponse{}
85 if err := a.call("GetDefaultAddressSpaces", nil, res); err != nil {
88 return res.LocalDefaultAddressSpace, res.GlobalDefaultAddressSpace, nil
91 // RequestPool requests an address pool in the specified address space
92 func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
93 req := &api.RequestPoolRequest{AddressSpace: addressSpace, Pool: pool, SubPool: subPool, Options: options, V6: v6}
94 res := &api.RequestPoolResponse{}
95 if err := a.call("RequestPool", req, res); err != nil {
96 return "", nil, nil, err
98 retPool, err := types.ParseCIDR(res.Pool)
99 return res.PoolID, retPool, res.Data, err
102 // ReleasePool removes an address pool from the specified address space
103 func (a *allocator) ReleasePool(poolID string) error {
104 req := &api.ReleasePoolRequest{PoolID: poolID}
105 res := &api.ReleasePoolResponse{}
106 return a.call("ReleasePool", req, res)
109 // RequestAddress requests an address from the address pool
110 func (a *allocator) RequestAddress(poolID string, address net.IP, options map[string]string) (*net.IPNet, map[string]string, error) {
113 retAddress *net.IPNet
117 prefAddress = address.String()
119 req := &api.RequestAddressRequest{PoolID: poolID, Address: prefAddress, Options: options}
120 res := &api.RequestAddressResponse{}
121 if err := a.call("RequestAddress", req, res); err != nil {
124 if res.Address != "" {
125 retAddress, err = types.ParseCIDR(res.Address)
127 return nil, nil, ipamapi.ErrNoIPReturned
129 return retAddress, res.Data, err
132 // ReleaseAddress releases the address from the specified address pool
133 func (a *allocator) ReleaseAddress(poolID string, address net.IP) error {
134 var relAddress string
136 relAddress = address.String()
138 req := &api.ReleaseAddressRequest{PoolID: poolID, Address: relAddress}
139 res := &api.ReleaseAddressResponse{}
140 return a.call("ReleaseAddress", req, res)
143 // DiscoverNew is a notification for a new discovery event, such as a new global datastore
144 func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
148 // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
149 func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
153 func (a *allocator) IsBuiltIn() bool {