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