github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libnetwork/drivers/remote/driver_test.go (about) 1 package remote 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "io" 9 "net" 10 "net/http" 11 "net/http/httptest" 12 "os" 13 "path/filepath" 14 "runtime" 15 "testing" 16 17 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/discoverapi" 18 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/driverapi" 19 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/scope" 20 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/types" 21 "github.com/Prakhar-Agarwal-byte/moby/pkg/plugins" 22 ) 23 24 func decodeToMap(r *http.Request) (res map[string]interface{}, err error) { 25 err = json.NewDecoder(r.Body).Decode(&res) 26 return 27 } 28 29 func handle(t *testing.T, mux *http.ServeMux, method string, h func(map[string]interface{}) interface{}) { 30 mux.HandleFunc(fmt.Sprintf("/%s.%s", driverapi.NetworkPluginEndpointType, method), func(w http.ResponseWriter, r *http.Request) { 31 ask, err := decodeToMap(r) 32 if err != nil && err != io.EOF { 33 t.Fatal(err) 34 } 35 answer := h(ask) 36 err = json.NewEncoder(w).Encode(&answer) 37 if err != nil { 38 t.Fatal(err) 39 } 40 }) 41 } 42 43 func setupPlugin(t *testing.T, name string, mux *http.ServeMux) func() { 44 specPath := "/etc/docker/plugins" 45 if runtime.GOOS == "windows" { 46 specPath = filepath.Join(os.Getenv("programdata"), "docker", "plugins") 47 } 48 49 if err := os.MkdirAll(specPath, 0o755); err != nil { 50 t.Fatal(err) 51 } 52 53 defer func() { 54 if t.Failed() { 55 _ = os.RemoveAll(specPath) 56 } 57 }() 58 59 server := httptest.NewServer(mux) 60 if server == nil { 61 t.Fatal("Failed to start an HTTP Server") 62 } 63 64 if err := os.WriteFile(filepath.Join(specPath, name+".spec"), []byte(server.URL), 0o644); err != nil { 65 t.Fatal(err) 66 } 67 68 mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { 69 w.Header().Set("Content-Type", plugins.VersionMimetype) 70 fmt.Fprintf(w, `{"Implements": ["%s"]}`, driverapi.NetworkPluginEndpointType) 71 }) 72 73 return func() { 74 if err := os.RemoveAll(specPath); err != nil { 75 t.Fatal(err) 76 } 77 server.Close() 78 } 79 } 80 81 type testEndpoint struct { 82 t *testing.T 83 src string 84 dst string 85 address string 86 addressIPv6 string 87 macAddress string 88 gateway string 89 gatewayIPv6 string 90 resolvConfPath string 91 hostsPath string 92 nextHop string 93 destination string 94 routeType int 95 disableGatewayService bool 96 } 97 98 func (test *testEndpoint) Address() *net.IPNet { 99 if test.address == "" { 100 return nil 101 } 102 nw, _ := types.ParseCIDR(test.address) 103 return nw 104 } 105 106 func (test *testEndpoint) AddressIPv6() *net.IPNet { 107 if test.addressIPv6 == "" { 108 return nil 109 } 110 nw, _ := types.ParseCIDR(test.addressIPv6) 111 return nw 112 } 113 114 func (test *testEndpoint) MacAddress() net.HardwareAddr { 115 if test.macAddress == "" { 116 return nil 117 } 118 mac, _ := net.ParseMAC(test.macAddress) 119 return mac 120 } 121 122 func (test *testEndpoint) SetMacAddress(mac net.HardwareAddr) error { 123 if test.macAddress != "" { 124 return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", test.macAddress, mac) 125 } 126 if mac == nil { 127 return types.InvalidParameterErrorf("tried to set nil MAC address to endpoint interface") 128 } 129 test.macAddress = mac.String() 130 return nil 131 } 132 133 func (test *testEndpoint) SetIPAddress(address *net.IPNet) error { 134 if address.IP == nil { 135 return types.InvalidParameterErrorf("tried to set nil IP address to endpoint interface") 136 } 137 if address.IP.To4() == nil { 138 return setAddress(&test.addressIPv6, address) 139 } 140 return setAddress(&test.address, address) 141 } 142 143 func setAddress(ifaceAddr *string, address *net.IPNet) error { 144 if *ifaceAddr != "" { 145 return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address) 146 } 147 *ifaceAddr = address.String() 148 return nil 149 } 150 151 func (test *testEndpoint) InterfaceName() driverapi.InterfaceNameInfo { 152 return test 153 } 154 155 func compareIPs(t *testing.T, kind string, shouldBe string, supplied net.IP) { 156 ip := net.ParseIP(shouldBe) 157 if ip == nil { 158 t.Fatalf(`Invalid IP to test against: "%s"`, shouldBe) 159 } 160 if !ip.Equal(supplied) { 161 t.Fatalf(`%s IPs are not equal: expected "%s", got %v`, kind, shouldBe, supplied) 162 } 163 } 164 165 func compareIPNets(t *testing.T, kind string, shouldBe string, supplied net.IPNet) { 166 _, ipNet, _ := net.ParseCIDR(shouldBe) 167 if ipNet == nil { 168 t.Fatalf(`Invalid IP network to test against: "%s"`, shouldBe) 169 } 170 if !types.CompareIPNet(ipNet, &supplied) { 171 t.Fatalf(`%s IP networks are not equal: expected "%s", got %v`, kind, shouldBe, supplied) 172 } 173 } 174 175 func (test *testEndpoint) SetGateway(ipv4 net.IP) error { 176 compareIPs(test.t, "Gateway", test.gateway, ipv4) 177 return nil 178 } 179 180 func (test *testEndpoint) SetGatewayIPv6(ipv6 net.IP) error { 181 compareIPs(test.t, "GatewayIPv6", test.gatewayIPv6, ipv6) 182 return nil 183 } 184 185 func (test *testEndpoint) SetNames(src string, dst string) error { 186 if test.src != src { 187 test.t.Fatalf(`Wrong SrcName; expected "%s", got "%s"`, test.src, src) 188 } 189 if test.dst != dst { 190 test.t.Fatalf(`Wrong DstPrefix; expected "%s", got "%s"`, test.dst, dst) 191 } 192 return nil 193 } 194 195 func (test *testEndpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error { 196 compareIPNets(test.t, "Destination", test.destination, *destination) 197 compareIPs(test.t, "NextHop", test.nextHop, nextHop) 198 199 if test.routeType != routeType { 200 test.t.Fatalf(`Wrong RouteType; expected "%d", got "%d"`, test.routeType, routeType) 201 } 202 203 return nil 204 } 205 206 func (test *testEndpoint) DisableGatewayService() { 207 test.disableGatewayService = true 208 } 209 210 func (test *testEndpoint) AddTableEntry(tableName string, key string, value []byte) error { 211 return nil 212 } 213 214 func TestGetEmptyCapabilities(t *testing.T) { 215 plugin := "test-net-driver-empty-cap" 216 217 mux := http.NewServeMux() 218 defer setupPlugin(t, plugin, mux)() 219 220 handle(t, mux, "GetCapabilities", func(msg map[string]interface{}) interface{} { 221 return map[string]interface{}{} 222 }) 223 224 p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) 225 if err != nil { 226 t.Fatal(err) 227 } 228 229 client, err := getPluginClient(p) 230 if err != nil { 231 t.Fatal(err) 232 } 233 d := newDriver(plugin, client) 234 if d.Type() != plugin { 235 t.Fatal("Driver type does not match that given") 236 } 237 238 _, err = d.getCapabilities() 239 if err == nil { 240 t.Fatal("There should be error reported when get empty capability") 241 } 242 } 243 244 func TestGetExtraCapabilities(t *testing.T) { 245 plugin := "test-net-driver-extra-cap" 246 247 mux := http.NewServeMux() 248 defer setupPlugin(t, plugin, mux)() 249 250 handle(t, mux, "GetCapabilities", func(msg map[string]interface{}) interface{} { 251 return map[string]interface{}{ 252 "Scope": "local", 253 "foo": "bar", 254 "ConnectivityScope": "global", 255 } 256 }) 257 258 p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) 259 if err != nil { 260 t.Fatal(err) 261 } 262 263 client, err := getPluginClient(p) 264 if err != nil { 265 t.Fatal(err) 266 } 267 d := newDriver(plugin, client) 268 if d.Type() != plugin { 269 t.Fatal("Driver type does not match that given") 270 } 271 272 c, err := d.getCapabilities() 273 if err != nil { 274 t.Fatal(err) 275 } else if c.DataScope != scope.Local { 276 t.Fatalf("get capability '%s', expecting 'local'", c.DataScope) 277 } else if c.ConnectivityScope != scope.Global { 278 t.Fatalf("get capability '%s', expecting %q", c.ConnectivityScope, scope.Global) 279 } 280 } 281 282 func TestGetInvalidCapabilities(t *testing.T) { 283 plugin := "test-net-driver-invalid-cap" 284 285 mux := http.NewServeMux() 286 defer setupPlugin(t, plugin, mux)() 287 288 handle(t, mux, "GetCapabilities", func(msg map[string]interface{}) interface{} { 289 return map[string]interface{}{ 290 "Scope": "fake", 291 } 292 }) 293 294 p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) 295 if err != nil { 296 t.Fatal(err) 297 } 298 299 client, err := getPluginClient(p) 300 if err != nil { 301 t.Fatal(err) 302 } 303 d := newDriver(plugin, client) 304 if d.Type() != plugin { 305 t.Fatal("Driver type does not match that given") 306 } 307 308 _, err = d.getCapabilities() 309 if err == nil { 310 t.Fatal("There should be error reported when get invalid capability") 311 } 312 } 313 314 func TestRemoteDriver(t *testing.T) { 315 plugin := "test-net-driver" 316 317 ep := &testEndpoint{ 318 t: t, 319 src: "vethsrc", 320 dst: "vethdst", 321 address: "192.168.5.7/16", 322 addressIPv6: "2001:DB8::5:7/48", 323 macAddress: "ab:cd:ef:ee:ee:ee", 324 gateway: "192.168.0.1", 325 gatewayIPv6: "2001:DB8::1", 326 hostsPath: "/here/comes/the/host/path", 327 resolvConfPath: "/there/goes/the/resolv/conf", 328 destination: "10.0.0.0/8", 329 nextHop: "10.0.0.1", 330 routeType: 1, 331 } 332 333 mux := http.NewServeMux() 334 defer setupPlugin(t, plugin, mux)() 335 336 var networkID string 337 338 handle(t, mux, "GetCapabilities", func(msg map[string]interface{}) interface{} { 339 return map[string]interface{}{ 340 "Scope": "global", 341 } 342 }) 343 handle(t, mux, "CreateNetwork", func(msg map[string]interface{}) interface{} { 344 nid := msg["NetworkID"] 345 var ok bool 346 if networkID, ok = nid.(string); !ok { 347 t.Fatal("RPC did not include network ID string") 348 } 349 return map[string]interface{}{} 350 }) 351 handle(t, mux, "DeleteNetwork", func(msg map[string]interface{}) interface{} { 352 if nid, ok := msg["NetworkID"]; !ok || nid != networkID { 353 t.Fatal("Network ID missing or does not match that created") 354 } 355 return map[string]interface{}{} 356 }) 357 handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} { 358 iface := map[string]interface{}{ 359 "MacAddress": ep.macAddress, 360 "Address": ep.address, 361 "AddressIPv6": ep.addressIPv6, 362 } 363 return map[string]interface{}{ 364 "Interface": iface, 365 } 366 }) 367 handle(t, mux, "Join", func(msg map[string]interface{}) interface{} { 368 options := msg["Options"].(map[string]interface{}) 369 foo, ok := options["foo"].(string) 370 if !ok || foo != "fooValue" { 371 t.Fatalf("Did not receive expected foo string in request options: %+v", msg) 372 } 373 return map[string]interface{}{ 374 "Gateway": ep.gateway, 375 "GatewayIPv6": ep.gatewayIPv6, 376 "HostsPath": ep.hostsPath, 377 "ResolvConfPath": ep.resolvConfPath, 378 "InterfaceName": map[string]interface{}{ 379 "SrcName": ep.src, 380 "DstPrefix": ep.dst, 381 }, 382 "StaticRoutes": []map[string]interface{}{ 383 { 384 "Destination": ep.destination, 385 "RouteType": ep.routeType, 386 "NextHop": ep.nextHop, 387 }, 388 }, 389 } 390 }) 391 handle(t, mux, "Leave", func(msg map[string]interface{}) interface{} { 392 return map[string]string{} 393 }) 394 handle(t, mux, "DeleteEndpoint", func(msg map[string]interface{}) interface{} { 395 return map[string]interface{}{} 396 }) 397 handle(t, mux, "EndpointOperInfo", func(msg map[string]interface{}) interface{} { 398 return map[string]interface{}{ 399 "Value": map[string]string{ 400 "Arbitrary": "key", 401 "Value": "pairs?", 402 }, 403 } 404 }) 405 handle(t, mux, "DiscoverNew", func(msg map[string]interface{}) interface{} { 406 return map[string]string{} 407 }) 408 handle(t, mux, "DiscoverDelete", func(msg map[string]interface{}) interface{} { 409 return map[string]interface{}{} 410 }) 411 412 p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) 413 if err != nil { 414 t.Fatal(err) 415 } 416 417 client, err := getPluginClient(p) 418 if err != nil { 419 t.Fatal(err) 420 } 421 d := newDriver(plugin, client) 422 if d.Type() != plugin { 423 t.Fatal("Driver type does not match that given") 424 } 425 426 c, err := d.getCapabilities() 427 if err != nil { 428 t.Fatal(err) 429 } else if c.DataScope != scope.Global { 430 t.Fatalf("get capability '%s', expecting 'global'", c.DataScope) 431 } 432 433 netID := "dummy-network" 434 err = d.CreateNetwork(netID, map[string]interface{}{}, nil, nil, nil) 435 if err != nil { 436 t.Fatal(err) 437 } 438 439 endID := "dummy-endpoint" 440 ifInfo := &testEndpoint{} 441 err = d.CreateEndpoint(netID, endID, ifInfo, map[string]interface{}{}) 442 if err != nil { 443 t.Fatal(err) 444 } 445 446 if !bytes.Equal(ep.MacAddress(), ifInfo.MacAddress()) || !types.CompareIPNet(ep.Address(), ifInfo.Address()) || 447 !types.CompareIPNet(ep.AddressIPv6(), ifInfo.AddressIPv6()) { 448 t.Fatalf("Unexpected InterfaceInfo data. Expected (%s, %s, %s). Got (%v, %v, %v)", 449 ep.MacAddress(), ep.Address(), ep.AddressIPv6(), 450 ifInfo.MacAddress(), ifInfo.Address(), ifInfo.AddressIPv6()) 451 } 452 453 joinOpts := map[string]interface{}{"foo": "fooValue"} 454 err = d.Join(netID, endID, "sandbox-key", ep, joinOpts) 455 if err != nil { 456 t.Fatal(err) 457 } 458 if _, err = d.EndpointOperInfo(netID, endID); err != nil { 459 t.Fatal(err) 460 } 461 if err = d.Leave(netID, endID); err != nil { 462 t.Fatal(err) 463 } 464 if err = d.DeleteEndpoint(netID, endID); err != nil { 465 t.Fatal(err) 466 } 467 if err = d.DeleteNetwork(netID); err != nil { 468 t.Fatal(err) 469 } 470 471 data := discoverapi.NodeDiscoveryData{ 472 Address: "192.168.1.1", 473 } 474 if err = d.DiscoverNew(discoverapi.NodeDiscovery, data); err != nil { 475 t.Fatal(err) 476 } 477 if err = d.DiscoverDelete(discoverapi.NodeDiscovery, data); err != nil { 478 t.Fatal(err) 479 } 480 } 481 482 func TestDriverError(t *testing.T) { 483 plugin := "test-net-driver-error" 484 485 mux := http.NewServeMux() 486 defer setupPlugin(t, plugin, mux)() 487 488 handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} { 489 return map[string]interface{}{ 490 "Err": "this should get raised as an error", 491 } 492 }) 493 494 p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) 495 if err != nil { 496 t.Fatal(err) 497 } 498 499 client, err := getPluginClient(p) 500 if err != nil { 501 t.Fatal(err) 502 } 503 504 d := newDriver(plugin, client) 505 if err := d.CreateEndpoint("dummy", "dummy", &testEndpoint{t: t}, map[string]interface{}{}); err == nil { 506 t.Fatal("Expected error from driver") 507 } 508 } 509 510 func TestMissingValues(t *testing.T) { 511 plugin := "test-net-driver-missing" 512 513 mux := http.NewServeMux() 514 defer setupPlugin(t, plugin, mux)() 515 516 ep := &testEndpoint{ 517 t: t, 518 } 519 520 handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} { 521 iface := map[string]interface{}{ 522 "Address": ep.address, 523 "AddressIPv6": ep.addressIPv6, 524 "MacAddress": ep.macAddress, 525 } 526 return map[string]interface{}{ 527 "Interface": iface, 528 } 529 }) 530 531 p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) 532 if err != nil { 533 t.Fatal(err) 534 } 535 536 client, err := getPluginClient(p) 537 if err != nil { 538 t.Fatal(err) 539 } 540 541 d := newDriver(plugin, client) 542 if err := d.CreateEndpoint("dummy", "dummy", ep, map[string]interface{}{}); err != nil { 543 t.Fatal(err) 544 } 545 } 546 547 type rollbackEndpoint struct{} 548 549 func (r *rollbackEndpoint) Interface() *rollbackEndpoint { 550 return r 551 } 552 553 func (r *rollbackEndpoint) MacAddress() net.HardwareAddr { 554 return nil 555 } 556 557 func (r *rollbackEndpoint) Address() *net.IPNet { 558 return nil 559 } 560 561 func (r *rollbackEndpoint) AddressIPv6() *net.IPNet { 562 return nil 563 } 564 565 func (r *rollbackEndpoint) SetMacAddress(mac net.HardwareAddr) error { 566 return errors.New("invalid mac") 567 } 568 569 func (r *rollbackEndpoint) SetIPAddress(ip *net.IPNet) error { 570 return errors.New("invalid ip") 571 } 572 573 func TestRollback(t *testing.T) { 574 plugin := "test-net-driver-rollback" 575 576 mux := http.NewServeMux() 577 defer setupPlugin(t, plugin, mux)() 578 579 rolledback := false 580 581 handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} { 582 iface := map[string]interface{}{ 583 "Address": "192.168.4.5/16", 584 "AddressIPv6": "", 585 "MacAddress": "7a:12:34:56:78:90", 586 } 587 return map[string]interface{}{ 588 "Interface": interface{}(iface), 589 } 590 }) 591 handle(t, mux, "DeleteEndpoint", func(msg map[string]interface{}) interface{} { 592 rolledback = true 593 return map[string]interface{}{} 594 }) 595 596 p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) 597 if err != nil { 598 t.Fatal(err) 599 } 600 601 client, err := getPluginClient(p) 602 if err != nil { 603 t.Fatal(err) 604 } 605 606 d := newDriver(plugin, client) 607 ep := &rollbackEndpoint{} 608 if err := d.CreateEndpoint("dummy", "dummy", ep.Interface(), map[string]interface{}{}); err == nil { 609 t.Fatal("Expected error from driver") 610 } 611 if !rolledback { 612 t.Fatal("Expected to have had DeleteEndpoint called") 613 } 614 }