github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/ipams/remote/remote.go (about)

     1  package remote
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  
     7  	"github.com/docker/docker/libnetwork/discoverapi"
     8  	"github.com/docker/docker/libnetwork/ipamapi"
     9  	"github.com/docker/docker/libnetwork/ipams/remote/api"
    10  	"github.com/docker/docker/libnetwork/types"
    11  	"github.com/docker/docker/pkg/plugingetter"
    12  	"github.com/docker/docker/pkg/plugins"
    13  	"github.com/pkg/errors"
    14  	"github.com/sirupsen/logrus"
    15  )
    16  
    17  type allocator struct {
    18  	endpoint *plugins.Client
    19  	name     string
    20  }
    21  
    22  // PluginResponse is the interface for the plugin request responses
    23  type PluginResponse interface {
    24  	IsSuccess() bool
    25  	GetError() string
    26  }
    27  
    28  func newAllocator(name string, client *plugins.Client) ipamapi.Ipam {
    29  	a := &allocator{name: name, endpoint: client}
    30  	return a
    31  }
    32  
    33  // Init registers a remote ipam when its plugin is activated
    34  func Init(cb ipamapi.Callback, l, g interface{}) error {
    35  
    36  	newPluginHandler := func(name string, client *plugins.Client) {
    37  		a := newAllocator(name, client)
    38  		if cps, err := a.(*allocator).getCapabilities(); err == nil {
    39  			if err := cb.RegisterIpamDriverWithCapabilities(name, a, cps); err != nil {
    40  				logrus.Errorf("error registering remote ipam driver %s due to %v", name, err)
    41  			}
    42  		} else {
    43  			logrus.Infof("remote ipam driver %s does not support capabilities", name)
    44  			logrus.Debug(err)
    45  			if err := cb.RegisterIpamDriver(name, a); err != nil {
    46  				logrus.Errorf("error registering remote ipam driver %s due to %v", name, err)
    47  			}
    48  		}
    49  	}
    50  
    51  	// Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins.
    52  	handleFunc := plugins.Handle
    53  	if pg := cb.GetPluginGetter(); pg != nil {
    54  		handleFunc = pg.Handle
    55  		activePlugins := pg.GetAllManagedPluginsByCap(ipamapi.PluginEndpointType)
    56  		for _, ap := range activePlugins {
    57  			client, err := getPluginClient(ap)
    58  			if err != nil {
    59  				return err
    60  			}
    61  			newPluginHandler(ap.Name(), client)
    62  		}
    63  	}
    64  	handleFunc(ipamapi.PluginEndpointType, newPluginHandler)
    65  	return nil
    66  }
    67  
    68  func getPluginClient(p plugingetter.CompatPlugin) (*plugins.Client, error) {
    69  	if v1, ok := p.(plugingetter.PluginWithV1Client); ok {
    70  		return v1.Client(), nil
    71  	}
    72  
    73  	pa, ok := p.(plugingetter.PluginAddr)
    74  	if !ok {
    75  		return nil, errors.Errorf("unknown plugin type %T", p)
    76  	}
    77  
    78  	if pa.Protocol() != plugins.ProtocolSchemeHTTPV1 {
    79  		return nil, errors.Errorf("unsupported plugin protocol %s", pa.Protocol())
    80  	}
    81  
    82  	addr := pa.Addr()
    83  	client, err := plugins.NewClientWithTimeout(addr.Network()+"://"+addr.String(), nil, pa.Timeout())
    84  	if err != nil {
    85  		return nil, errors.Wrap(err, "error creating plugin client")
    86  	}
    87  	return client, nil
    88  }
    89  
    90  func (a *allocator) call(methodName string, arg interface{}, retVal PluginResponse) error {
    91  	method := ipamapi.PluginEndpointType + "." + methodName
    92  	err := a.endpoint.Call(method, arg, retVal)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	if !retVal.IsSuccess() {
    97  		return fmt.Errorf("remote: %s", retVal.GetError())
    98  	}
    99  	return nil
   100  }
   101  
   102  func (a *allocator) getCapabilities() (*ipamapi.Capability, error) {
   103  	var res api.GetCapabilityResponse
   104  	if err := a.call("GetCapabilities", nil, &res); err != nil {
   105  		return nil, err
   106  	}
   107  	return res.ToCapability(), nil
   108  }
   109  
   110  // GetDefaultAddressSpaces returns the local and global default address spaces
   111  func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
   112  	res := &api.GetAddressSpacesResponse{}
   113  	if err := a.call("GetDefaultAddressSpaces", nil, res); err != nil {
   114  		return "", "", err
   115  	}
   116  	return res.LocalDefaultAddressSpace, res.GlobalDefaultAddressSpace, nil
   117  }
   118  
   119  // RequestPool requests an address pool in the specified address space
   120  func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
   121  	req := &api.RequestPoolRequest{AddressSpace: addressSpace, Pool: pool, SubPool: subPool, Options: options, V6: v6}
   122  	res := &api.RequestPoolResponse{}
   123  	if err := a.call("RequestPool", req, res); err != nil {
   124  		return "", nil, nil, err
   125  	}
   126  	retPool, err := types.ParseCIDR(res.Pool)
   127  	return res.PoolID, retPool, res.Data, err
   128  }
   129  
   130  // ReleasePool removes an address pool from the specified address space
   131  func (a *allocator) ReleasePool(poolID string) error {
   132  	req := &api.ReleasePoolRequest{PoolID: poolID}
   133  	res := &api.ReleasePoolResponse{}
   134  	return a.call("ReleasePool", req, res)
   135  }
   136  
   137  // RequestAddress requests an address from the address pool
   138  func (a *allocator) RequestAddress(poolID string, address net.IP, options map[string]string) (*net.IPNet, map[string]string, error) {
   139  	var (
   140  		prefAddress string
   141  		retAddress  *net.IPNet
   142  		err         error
   143  	)
   144  	if address != nil {
   145  		prefAddress = address.String()
   146  	}
   147  	req := &api.RequestAddressRequest{PoolID: poolID, Address: prefAddress, Options: options}
   148  	res := &api.RequestAddressResponse{}
   149  	if err := a.call("RequestAddress", req, res); err != nil {
   150  		return nil, nil, err
   151  	}
   152  	if res.Address != "" {
   153  		retAddress, err = types.ParseCIDR(res.Address)
   154  	} else {
   155  		return nil, nil, ipamapi.ErrNoIPReturned
   156  	}
   157  	return retAddress, res.Data, err
   158  }
   159  
   160  // ReleaseAddress releases the address from the specified address pool
   161  func (a *allocator) ReleaseAddress(poolID string, address net.IP) error {
   162  	var relAddress string
   163  	if address != nil {
   164  		relAddress = address.String()
   165  	}
   166  	req := &api.ReleaseAddressRequest{PoolID: poolID, Address: relAddress}
   167  	res := &api.ReleaseAddressResponse{}
   168  	return a.call("ReleaseAddress", req, res)
   169  }
   170  
   171  // DiscoverNew is a notification for a new discovery event, such as a new global datastore
   172  func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
   173  	return nil
   174  }
   175  
   176  // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
   177  func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
   178  	return nil
   179  }
   180  
   181  func (a *allocator) IsBuiltIn() bool {
   182  	return false
   183  }