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