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 }