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