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