2015-09-22 20:20:55 +00:00
|
|
|
package remote
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
|
|
|
|
log "github.com/Sirupsen/logrus"
|
|
|
|
"github.com/docker/docker/pkg/plugins"
|
2016-01-28 00:37:47 +00:00
|
|
|
"github.com/docker/libnetwork/discoverapi"
|
2015-09-22 20:20:55 +00:00
|
|
|
"github.com/docker/libnetwork/ipamapi"
|
|
|
|
"github.com/docker/libnetwork/ipams/remote/api"
|
2015-10-12 20:03:28 +00:00
|
|
|
"github.com/docker/libnetwork/types"
|
2015-09-22 20:20:55 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type allocator struct {
|
|
|
|
endpoint *plugins.Client
|
|
|
|
name string
|
|
|
|
}
|
|
|
|
|
|
|
|
// PluginResponse is the interface for the plugin request responses
|
|
|
|
type PluginResponse interface {
|
|
|
|
IsSuccess() bool
|
|
|
|
GetError() string
|
|
|
|
}
|
|
|
|
|
|
|
|
func newAllocator(name string, client *plugins.Client) ipamapi.Ipam {
|
|
|
|
a := &allocator{name: name, endpoint: client}
|
|
|
|
return a
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init registers a remote ipam when its plugin is activated
|
|
|
|
func Init(cb ipamapi.Callback, l, g interface{}) error {
|
|
|
|
plugins.Handle(ipamapi.PluginEndpointType, func(name string, client *plugins.Client) {
|
2015-12-10 02:09:58 +00:00
|
|
|
a := newAllocator(name, client)
|
|
|
|
if cps, err := a.(*allocator).getCapabilities(); err == nil {
|
|
|
|
if err := cb.RegisterIpamDriverWithCapabilities(name, a, cps); err != nil {
|
|
|
|
log.Errorf("error registering remote ipam driver %s due to %v", name, err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Infof("remote ipam driver %s does not support capabilities", name)
|
|
|
|
log.Debug(err)
|
|
|
|
if err := cb.RegisterIpamDriver(name, a); err != nil {
|
|
|
|
log.Errorf("error registering remote ipam driver %s due to %v", name, err)
|
|
|
|
}
|
2015-09-22 20:20:55 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *allocator) call(methodName string, arg interface{}, retVal PluginResponse) error {
|
|
|
|
method := ipamapi.PluginEndpointType + "." + methodName
|
|
|
|
err := a.endpoint.Call(method, arg, retVal)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !retVal.IsSuccess() {
|
|
|
|
return fmt.Errorf("remote: %s", retVal.GetError())
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-12-10 02:09:58 +00:00
|
|
|
func (a *allocator) getCapabilities() (*ipamapi.Capability, error) {
|
|
|
|
var res api.GetCapabilityResponse
|
|
|
|
if err := a.call("GetCapabilities", nil, &res); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return res.ToCapability(), nil
|
|
|
|
}
|
|
|
|
|
2015-09-22 20:20:55 +00:00
|
|
|
// GetDefaultAddressSpaces returns the local and global default address spaces
|
|
|
|
func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
|
|
|
|
res := &api.GetAddressSpacesResponse{}
|
|
|
|
if err := a.call("GetDefaultAddressSpaces", nil, res); err != nil {
|
|
|
|
return "", "", err
|
|
|
|
}
|
|
|
|
return res.LocalDefaultAddressSpace, res.GlobalDefaultAddressSpace, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// RequestPool requests an address pool in the specified address space
|
|
|
|
func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
|
|
|
|
req := &api.RequestPoolRequest{AddressSpace: addressSpace, Pool: pool, SubPool: subPool, Options: options, V6: v6}
|
|
|
|
res := &api.RequestPoolResponse{}
|
|
|
|
if err := a.call("RequestPool", req, res); err != nil {
|
|
|
|
return "", nil, nil, err
|
|
|
|
}
|
2015-10-12 20:03:28 +00:00
|
|
|
retPool, err := types.ParseCIDR(res.Pool)
|
|
|
|
return res.PoolID, retPool, res.Data, err
|
2015-09-22 20:20:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ReleasePool removes an address pool from the specified address space
|
|
|
|
func (a *allocator) ReleasePool(poolID string) error {
|
|
|
|
req := &api.ReleasePoolRequest{PoolID: poolID}
|
|
|
|
res := &api.ReleasePoolResponse{}
|
|
|
|
return a.call("ReleasePool", req, res)
|
|
|
|
}
|
|
|
|
|
|
|
|
// RequestAddress requests an address from the address pool
|
|
|
|
func (a *allocator) RequestAddress(poolID string, address net.IP, options map[string]string) (*net.IPNet, map[string]string, error) {
|
2015-10-21 06:03:51 +00:00
|
|
|
var (
|
|
|
|
prefAddress string
|
|
|
|
retAddress *net.IPNet
|
|
|
|
err error
|
|
|
|
)
|
2015-10-12 20:03:28 +00:00
|
|
|
if address != nil {
|
|
|
|
prefAddress = address.String()
|
|
|
|
}
|
|
|
|
req := &api.RequestAddressRequest{PoolID: poolID, Address: prefAddress, Options: options}
|
2015-09-22 20:20:55 +00:00
|
|
|
res := &api.RequestAddressResponse{}
|
|
|
|
if err := a.call("RequestAddress", req, res); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2015-10-21 06:03:51 +00:00
|
|
|
if res.Address != "" {
|
|
|
|
retAddress, err = types.ParseCIDR(res.Address)
|
|
|
|
}
|
2015-10-12 20:03:28 +00:00
|
|
|
return retAddress, res.Data, err
|
2015-09-22 20:20:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ReleaseAddress releases the address from the specified address pool
|
|
|
|
func (a *allocator) ReleaseAddress(poolID string, address net.IP) error {
|
2015-10-12 20:03:28 +00:00
|
|
|
var relAddress string
|
|
|
|
if address != nil {
|
|
|
|
relAddress = address.String()
|
|
|
|
}
|
|
|
|
req := &api.ReleaseAddressRequest{PoolID: poolID, Address: relAddress}
|
2015-09-22 20:20:55 +00:00
|
|
|
res := &api.ReleaseAddressResponse{}
|
|
|
|
return a.call("ReleaseAddress", req, res)
|
|
|
|
}
|
2016-01-28 00:37:47 +00:00
|
|
|
|
|
|
|
// DiscoverNew is a notification for a new discovery event, such as a new global datastore
|
|
|
|
func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
|
|
|
|
func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
|
|
|
|
return nil
|
|
|
|
}
|