github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/drivers/remote/driver.go (about) 1 package remote 2 3 import ( 4 "fmt" 5 "net" 6 7 "github.com/docker/docker/libnetwork/datastore" 8 "github.com/docker/docker/libnetwork/discoverapi" 9 "github.com/docker/docker/libnetwork/driverapi" 10 "github.com/docker/docker/libnetwork/drivers/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 "github.com/sirupsen/logrus" 16 ) 17 18 type driver struct { 19 endpoint *plugins.Client 20 networkType string 21 } 22 23 type maybeError interface { 24 GetError() string 25 } 26 27 func newDriver(name string, client *plugins.Client) driverapi.Driver { 28 return &driver{networkType: name, endpoint: client} 29 } 30 31 // Init makes sure a remote driver is registered when a network driver 32 // plugin is activated. 33 func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { 34 newPluginHandler := func(name string, client *plugins.Client) { 35 // negotiate driver capability with client 36 d := newDriver(name, client) 37 c, err := d.(*driver).getCapabilities() 38 if err != nil { 39 logrus.Errorf("error getting capability for %s due to %v", name, err) 40 return 41 } 42 if err = dc.RegisterDriver(name, d, *c); err != nil { 43 logrus.Errorf("error registering driver for %s due to %v", name, err) 44 } 45 } 46 47 // Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins. 48 handleFunc := plugins.Handle 49 if pg := dc.GetPluginGetter(); pg != nil { 50 handleFunc = pg.Handle 51 activePlugins := pg.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType) 52 for _, ap := range activePlugins { 53 client, err := getPluginClient(ap) 54 if err != nil { 55 return err 56 } 57 newPluginHandler(ap.Name(), client) 58 } 59 } 60 handleFunc(driverapi.NetworkPluginEndpointType, newPluginHandler) 61 62 return nil 63 } 64 65 func getPluginClient(p plugingetter.CompatPlugin) (*plugins.Client, error) { 66 if v1, ok := p.(plugingetter.PluginWithV1Client); ok { 67 return v1.Client(), nil 68 } 69 70 pa, ok := p.(plugingetter.PluginAddr) 71 if !ok { 72 return nil, errors.Errorf("unknown plugin type %T", p) 73 } 74 75 if pa.Protocol() != plugins.ProtocolSchemeHTTPV1 { 76 return nil, errors.Errorf("unsupported plugin protocol %s", pa.Protocol()) 77 } 78 79 addr := pa.Addr() 80 client, err := plugins.NewClientWithTimeout(addr.Network()+"://"+addr.String(), nil, pa.Timeout()) 81 if err != nil { 82 return nil, errors.Wrap(err, "error creating plugin client") 83 } 84 return client, nil 85 } 86 87 // Get capability from client 88 func (d *driver) getCapabilities() (*driverapi.Capability, error) { 89 var capResp api.GetCapabilityResponse 90 if err := d.call("GetCapabilities", nil, &capResp); err != nil { 91 return nil, err 92 } 93 94 c := &driverapi.Capability{} 95 switch capResp.Scope { 96 case "global": 97 c.DataScope = datastore.GlobalScope 98 case "local": 99 c.DataScope = datastore.LocalScope 100 default: 101 return nil, fmt.Errorf("invalid capability: expecting 'local' or 'global', got %s", capResp.Scope) 102 } 103 104 switch capResp.ConnectivityScope { 105 case "global": 106 c.ConnectivityScope = datastore.GlobalScope 107 case "local": 108 c.ConnectivityScope = datastore.LocalScope 109 case "": 110 c.ConnectivityScope = c.DataScope 111 default: 112 return nil, fmt.Errorf("invalid capability: expecting 'local' or 'global', got %s", capResp.Scope) 113 } 114 115 return c, nil 116 } 117 118 // Config is not implemented for remote drivers, since it is assumed 119 // to be supplied to the remote process out-of-band (e.g., as command 120 // line arguments). 121 func (d *driver) Config(option map[string]interface{}) error { 122 return &driverapi.ErrNotImplemented{} 123 } 124 125 func (d *driver) call(methodName string, arg interface{}, retVal maybeError) error { 126 method := driverapi.NetworkPluginEndpointType + "." + methodName 127 err := d.endpoint.Call(method, arg, retVal) 128 if err != nil { 129 return err 130 } 131 if e := retVal.GetError(); e != "" { 132 return fmt.Errorf("remote: %s", e) 133 } 134 return nil 135 } 136 137 func (d *driver) NetworkAllocate(id string, options map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) { 138 create := &api.AllocateNetworkRequest{ 139 NetworkID: id, 140 Options: options, 141 IPv4Data: ipV4Data, 142 IPv6Data: ipV6Data, 143 } 144 retVal := api.AllocateNetworkResponse{} 145 err := d.call("AllocateNetwork", create, &retVal) 146 return retVal.Options, err 147 } 148 149 func (d *driver) NetworkFree(id string) error { 150 fr := &api.FreeNetworkRequest{NetworkID: id} 151 return d.call("FreeNetwork", fr, &api.FreeNetworkResponse{}) 152 } 153 154 func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) { 155 } 156 157 func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) { 158 return "", nil 159 } 160 161 func (d *driver) CreateNetwork(id string, options map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error { 162 create := &api.CreateNetworkRequest{ 163 NetworkID: id, 164 Options: options, 165 IPv4Data: ipV4Data, 166 IPv6Data: ipV6Data, 167 } 168 return d.call("CreateNetwork", create, &api.CreateNetworkResponse{}) 169 } 170 171 func (d *driver) DeleteNetwork(nid string) error { 172 delete := &api.DeleteNetworkRequest{NetworkID: nid} 173 return d.call("DeleteNetwork", delete, &api.DeleteNetworkResponse{}) 174 } 175 176 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error { 177 if ifInfo == nil { 178 return errors.New("must not be called with nil InterfaceInfo") 179 } 180 181 reqIface := &api.EndpointInterface{} 182 if ifInfo.Address() != nil { 183 reqIface.Address = ifInfo.Address().String() 184 } 185 if ifInfo.AddressIPv6() != nil { 186 reqIface.AddressIPv6 = ifInfo.AddressIPv6().String() 187 } 188 if ifInfo.MacAddress() != nil { 189 reqIface.MacAddress = ifInfo.MacAddress().String() 190 } 191 192 create := &api.CreateEndpointRequest{ 193 NetworkID: nid, 194 EndpointID: eid, 195 Interface: reqIface, 196 Options: epOptions, 197 } 198 var res api.CreateEndpointResponse 199 if err := d.call("CreateEndpoint", create, &res); err != nil { 200 return err 201 } 202 203 inIface, err := parseInterface(res) 204 if err != nil { 205 return err 206 } 207 if inIface == nil { 208 // Remote driver did not set any field 209 return nil 210 } 211 212 if inIface.MacAddress != nil { 213 if err := ifInfo.SetMacAddress(inIface.MacAddress); err != nil { 214 return errorWithRollback(fmt.Sprintf("driver modified interface MAC address: %v", err), d.DeleteEndpoint(nid, eid)) 215 } 216 } 217 if inIface.Address != nil { 218 if err := ifInfo.SetIPAddress(inIface.Address); err != nil { 219 return errorWithRollback(fmt.Sprintf("driver modified interface address: %v", err), d.DeleteEndpoint(nid, eid)) 220 } 221 } 222 if inIface.AddressIPv6 != nil { 223 if err := ifInfo.SetIPAddress(inIface.AddressIPv6); err != nil { 224 return errorWithRollback(fmt.Sprintf("driver modified interface address: %v", err), d.DeleteEndpoint(nid, eid)) 225 } 226 } 227 228 return nil 229 } 230 231 func errorWithRollback(msg string, err error) error { 232 rollback := "rolled back" 233 if err != nil { 234 rollback = "failed to roll back: " + err.Error() 235 } 236 return fmt.Errorf("%s; %s", msg, rollback) 237 } 238 239 func (d *driver) DeleteEndpoint(nid, eid string) error { 240 delete := &api.DeleteEndpointRequest{ 241 NetworkID: nid, 242 EndpointID: eid, 243 } 244 return d.call("DeleteEndpoint", delete, &api.DeleteEndpointResponse{}) 245 } 246 247 func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { 248 info := &api.EndpointInfoRequest{ 249 NetworkID: nid, 250 EndpointID: eid, 251 } 252 var res api.EndpointInfoResponse 253 if err := d.call("EndpointOperInfo", info, &res); err != nil { 254 return nil, err 255 } 256 return res.Value, nil 257 } 258 259 // Join method is invoked when a Sandbox is attached to an endpoint. 260 func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { 261 join := &api.JoinRequest{ 262 NetworkID: nid, 263 EndpointID: eid, 264 SandboxKey: sboxKey, 265 Options: options, 266 } 267 var ( 268 res api.JoinResponse 269 err error 270 ) 271 if err = d.call("Join", join, &res); err != nil { 272 return err 273 } 274 275 ifaceName := res.InterfaceName 276 if iface := jinfo.InterfaceName(); iface != nil && ifaceName != nil { 277 if err := iface.SetNames(ifaceName.SrcName, ifaceName.DstPrefix); err != nil { 278 return errorWithRollback(fmt.Sprintf("failed to set interface name: %s", err), d.Leave(nid, eid)) 279 } 280 } 281 282 var addr net.IP 283 if res.Gateway != "" { 284 if addr = net.ParseIP(res.Gateway); addr == nil { 285 return fmt.Errorf(`unable to parse Gateway "%s"`, res.Gateway) 286 } 287 if jinfo.SetGateway(addr) != nil { 288 return errorWithRollback(fmt.Sprintf("failed to set gateway: %v", addr), d.Leave(nid, eid)) 289 } 290 } 291 if res.GatewayIPv6 != "" { 292 if addr = net.ParseIP(res.GatewayIPv6); addr == nil { 293 return fmt.Errorf(`unable to parse GatewayIPv6 "%s"`, res.GatewayIPv6) 294 } 295 if jinfo.SetGatewayIPv6(addr) != nil { 296 return errorWithRollback(fmt.Sprintf("failed to set gateway IPv6: %v", addr), d.Leave(nid, eid)) 297 } 298 } 299 if len(res.StaticRoutes) > 0 { 300 routes, err := parseStaticRoutes(res) 301 if err != nil { 302 return err 303 } 304 for _, route := range routes { 305 if jinfo.AddStaticRoute(route.Destination, route.RouteType, route.NextHop) != nil { 306 return errorWithRollback(fmt.Sprintf("failed to set static route: %v", route), d.Leave(nid, eid)) 307 } 308 } 309 } 310 if res.DisableGatewayService { 311 jinfo.DisableGatewayService() 312 } 313 return nil 314 } 315 316 // Leave method is invoked when a Sandbox detaches from an endpoint. 317 func (d *driver) Leave(nid, eid string) error { 318 leave := &api.LeaveRequest{ 319 NetworkID: nid, 320 EndpointID: eid, 321 } 322 return d.call("Leave", leave, &api.LeaveResponse{}) 323 } 324 325 // ProgramExternalConnectivity is invoked to program the rules to allow external connectivity for the endpoint. 326 func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { 327 data := &api.ProgramExternalConnectivityRequest{ 328 NetworkID: nid, 329 EndpointID: eid, 330 Options: options, 331 } 332 err := d.call("ProgramExternalConnectivity", data, &api.ProgramExternalConnectivityResponse{}) 333 if err != nil && plugins.IsNotFound(err) { 334 // It is not mandatory yet to support this method 335 return nil 336 } 337 return err 338 } 339 340 // RevokeExternalConnectivity method is invoked to remove any external connectivity programming related to the endpoint. 341 func (d *driver) RevokeExternalConnectivity(nid, eid string) error { 342 data := &api.RevokeExternalConnectivityRequest{ 343 NetworkID: nid, 344 EndpointID: eid, 345 } 346 err := d.call("RevokeExternalConnectivity", data, &api.RevokeExternalConnectivityResponse{}) 347 if err != nil && plugins.IsNotFound(err) { 348 // It is not mandatory yet to support this method 349 return nil 350 } 351 return err 352 } 353 354 func (d *driver) Type() string { 355 return d.networkType 356 } 357 358 func (d *driver) IsBuiltIn() bool { 359 return false 360 } 361 362 // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster 363 func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { 364 if dType != discoverapi.NodeDiscovery { 365 return nil 366 } 367 notif := &api.DiscoveryNotification{ 368 DiscoveryType: dType, 369 DiscoveryData: data, 370 } 371 return d.call("DiscoverNew", notif, &api.DiscoveryResponse{}) 372 } 373 374 // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster 375 func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { 376 if dType != discoverapi.NodeDiscovery { 377 return nil 378 } 379 notif := &api.DiscoveryNotification{ 380 DiscoveryType: dType, 381 DiscoveryData: data, 382 } 383 return d.call("DiscoverDelete", notif, &api.DiscoveryResponse{}) 384 } 385 386 func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) { 387 var routes = make([]*types.StaticRoute, len(r.StaticRoutes)) 388 for i, inRoute := range r.StaticRoutes { 389 var err error 390 outRoute := &types.StaticRoute{RouteType: inRoute.RouteType} 391 392 if inRoute.Destination != "" { 393 if outRoute.Destination, err = types.ParseCIDR(inRoute.Destination); err != nil { 394 return nil, err 395 } 396 } 397 398 if inRoute.NextHop != "" { 399 outRoute.NextHop = net.ParseIP(inRoute.NextHop) 400 if outRoute.NextHop == nil { 401 return nil, fmt.Errorf("failed to parse nexthop IP %s", inRoute.NextHop) 402 } 403 } 404 405 routes[i] = outRoute 406 } 407 return routes, nil 408 } 409 410 // parseInterfaces validates all the parameters of an Interface and returns them. 411 func parseInterface(r api.CreateEndpointResponse) (*api.Interface, error) { 412 var outIf *api.Interface 413 414 inIf := r.Interface 415 if inIf != nil { 416 var err error 417 outIf = &api.Interface{} 418 if inIf.Address != "" { 419 if outIf.Address, err = types.ParseCIDR(inIf.Address); err != nil { 420 return nil, err 421 } 422 } 423 if inIf.AddressIPv6 != "" { 424 if outIf.AddressIPv6, err = types.ParseCIDR(inIf.AddressIPv6); err != nil { 425 return nil, err 426 } 427 } 428 if inIf.MacAddress != "" { 429 if outIf.MacAddress, err = net.ParseMAC(inIf.MacAddress); err != nil { 430 return nil, err 431 } 432 } 433 } 434 435 return outIf, nil 436 }