1package remote 2 3import ( 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 24func decodeToMap(r *http.Request) (res map[string]interface{}, err error) { 25 err = json.NewDecoder(r.Body).Decode(&res) 26 return 27} 28 29func 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 43func 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 70type 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 87func (test *testEndpoint) Interface() driverapi.InterfaceInfo { 88 return test 89} 90 91func (test *testEndpoint) Address() *net.IPNet { 92 if test.address == "" { 93 return nil 94 } 95 nw, _ := types.ParseCIDR(test.address) 96 return nw 97} 98 99func (test *testEndpoint) AddressIPv6() *net.IPNet { 100 if test.addressIPv6 == "" { 101 return nil 102 } 103 nw, _ := types.ParseCIDR(test.addressIPv6) 104 return nw 105} 106 107func (test *testEndpoint) MacAddress() net.HardwareAddr { 108 if test.macAddress == "" { 109 return nil 110 } 111 mac, _ := net.ParseMAC(test.macAddress) 112 return mac 113} 114 115func (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 126func (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 136func 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 144func (test *testEndpoint) InterfaceName() driverapi.InterfaceNameInfo { 145 return test 146} 147 148func 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 158func 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 168func (test *testEndpoint) SetGateway(ipv4 net.IP) error { 169 compareIPs(test.t, "Gateway", test.gateway, ipv4) 170 return nil 171} 172 173func (test *testEndpoint) SetGatewayIPv6(ipv6 net.IP) error { 174 compareIPs(test.t, "GatewayIPv6", test.gatewayIPv6, ipv6) 175 return nil 176} 177 178func (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 188func (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 199func (test *testEndpoint) DisableGatewayService() { 200 test.disableGatewayService = true 201} 202 203func (test *testEndpoint) AddTableEntry(tableName string, key string, value []byte) error { 204 return nil 205} 206 207func 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 d := newDriver(plugin, p.Client()) 223 if d.Type() != plugin { 224 t.Fatal("Driver type does not match that given") 225 } 226 227 _, err = d.(*driver).getCapabilities() 228 if err == nil { 229 t.Fatal("There should be error reported when get empty capability") 230 } 231} 232 233func TestGetExtraCapabilities(t *testing.T) { 234 var plugin = "test-net-driver-extra-cap" 235 236 mux := http.NewServeMux() 237 defer setupPlugin(t, plugin, mux)() 238 239 handle(t, mux, "GetCapabilities", func(msg map[string]interface{}) interface{} { 240 return map[string]interface{}{ 241 "Scope": "local", 242 "foo": "bar", 243 "ConnectivityScope": "global", 244 } 245 }) 246 247 p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) 248 if err != nil { 249 t.Fatal(err) 250 } 251 252 d := newDriver(plugin, p.Client()) 253 if d.Type() != plugin { 254 t.Fatal("Driver type does not match that given") 255 } 256 257 c, err := d.(*driver).getCapabilities() 258 if err != nil { 259 t.Fatal(err) 260 } else if c.DataScope != datastore.LocalScope { 261 t.Fatalf("get capability '%s', expecting 'local'", c.DataScope) 262 } else if c.ConnectivityScope != datastore.GlobalScope { 263 t.Fatalf("get capability '%s', expecting %q", c.ConnectivityScope, datastore.GlobalScope) 264 } 265} 266 267func TestGetInvalidCapabilities(t *testing.T) { 268 var plugin = "test-net-driver-invalid-cap" 269 270 mux := http.NewServeMux() 271 defer setupPlugin(t, plugin, mux)() 272 273 handle(t, mux, "GetCapabilities", func(msg map[string]interface{}) interface{} { 274 return map[string]interface{}{ 275 "Scope": "fake", 276 } 277 }) 278 279 p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) 280 if err != nil { 281 t.Fatal(err) 282 } 283 284 d := newDriver(plugin, p.Client()) 285 if d.Type() != plugin { 286 t.Fatal("Driver type does not match that given") 287 } 288 289 _, err = d.(*driver).getCapabilities() 290 if err == nil { 291 t.Fatal("There should be error reported when get invalid capability") 292 } 293} 294 295func TestRemoteDriver(t *testing.T) { 296 var plugin = "test-net-driver" 297 298 ep := &testEndpoint{ 299 t: t, 300 src: "vethsrc", 301 dst: "vethdst", 302 address: "192.168.5.7/16", 303 addressIPv6: "2001:DB8::5:7/48", 304 macAddress: "ab:cd:ef:ee:ee:ee", 305 gateway: "192.168.0.1", 306 gatewayIPv6: "2001:DB8::1", 307 hostsPath: "/here/comes/the/host/path", 308 resolvConfPath: "/there/goes/the/resolv/conf", 309 destination: "10.0.0.0/8", 310 nextHop: "10.0.0.1", 311 routeType: 1, 312 } 313 314 mux := http.NewServeMux() 315 defer setupPlugin(t, plugin, mux)() 316 317 var networkID string 318 319 handle(t, mux, "GetCapabilities", func(msg map[string]interface{}) interface{} { 320 return map[string]interface{}{ 321 "Scope": "global", 322 } 323 }) 324 handle(t, mux, "CreateNetwork", func(msg map[string]interface{}) interface{} { 325 nid := msg["NetworkID"] 326 var ok bool 327 if networkID, ok = nid.(string); !ok { 328 t.Fatal("RPC did not include network ID string") 329 } 330 return map[string]interface{}{} 331 }) 332 handle(t, mux, "DeleteNetwork", func(msg map[string]interface{}) interface{} { 333 if nid, ok := msg["NetworkID"]; !ok || nid != networkID { 334 t.Fatal("Network ID missing or does not match that created") 335 } 336 return map[string]interface{}{} 337 }) 338 handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} { 339 iface := map[string]interface{}{ 340 "MacAddress": ep.macAddress, 341 "Address": ep.address, 342 "AddressIPv6": ep.addressIPv6, 343 } 344 return map[string]interface{}{ 345 "Interface": iface, 346 } 347 }) 348 handle(t, mux, "Join", func(msg map[string]interface{}) interface{} { 349 options := msg["Options"].(map[string]interface{}) 350 foo, ok := options["foo"].(string) 351 if !ok || foo != "fooValue" { 352 t.Fatalf("Did not receive expected foo string in request options: %+v", msg) 353 } 354 return map[string]interface{}{ 355 "Gateway": ep.gateway, 356 "GatewayIPv6": ep.gatewayIPv6, 357 "HostsPath": ep.hostsPath, 358 "ResolvConfPath": ep.resolvConfPath, 359 "InterfaceName": map[string]interface{}{ 360 "SrcName": ep.src, 361 "DstPrefix": ep.dst, 362 }, 363 "StaticRoutes": []map[string]interface{}{ 364 { 365 "Destination": ep.destination, 366 "RouteType": ep.routeType, 367 "NextHop": ep.nextHop, 368 }, 369 }, 370 } 371 }) 372 handle(t, mux, "Leave", func(msg map[string]interface{}) interface{} { 373 return map[string]string{} 374 }) 375 handle(t, mux, "DeleteEndpoint", func(msg map[string]interface{}) interface{} { 376 return map[string]interface{}{} 377 }) 378 handle(t, mux, "EndpointOperInfo", func(msg map[string]interface{}) interface{} { 379 return map[string]interface{}{ 380 "Value": map[string]string{ 381 "Arbitrary": "key", 382 "Value": "pairs?", 383 }, 384 } 385 }) 386 handle(t, mux, "DiscoverNew", func(msg map[string]interface{}) interface{} { 387 return map[string]string{} 388 }) 389 handle(t, mux, "DiscoverDelete", func(msg map[string]interface{}) interface{} { 390 return map[string]interface{}{} 391 }) 392 393 p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) 394 if err != nil { 395 t.Fatal(err) 396 } 397 398 d := newDriver(plugin, p.Client()) 399 if d.Type() != plugin { 400 t.Fatal("Driver type does not match that given") 401 } 402 403 c, err := d.(*driver).getCapabilities() 404 if err != nil { 405 t.Fatal(err) 406 } else if c.DataScope != datastore.GlobalScope { 407 t.Fatalf("get capability '%s', expecting 'global'", c.DataScope) 408 } 409 410 netID := "dummy-network" 411 err = d.CreateNetwork(netID, map[string]interface{}{}, nil, nil, nil) 412 if err != nil { 413 t.Fatal(err) 414 } 415 416 endID := "dummy-endpoint" 417 ifInfo := &testEndpoint{} 418 err = d.CreateEndpoint(netID, endID, ifInfo, map[string]interface{}{}) 419 if err != nil { 420 t.Fatal(err) 421 } 422 423 if !bytes.Equal(ep.MacAddress(), ifInfo.MacAddress()) || !types.CompareIPNet(ep.Address(), ifInfo.Address()) || 424 !types.CompareIPNet(ep.AddressIPv6(), ifInfo.AddressIPv6()) { 425 t.Fatalf("Unexpected InterfaceInfo data. Expected (%s, %s, %s). Got (%v, %v, %v)", 426 ep.MacAddress(), ep.Address(), ep.AddressIPv6(), 427 ifInfo.MacAddress(), ifInfo.Address(), ifInfo.AddressIPv6()) 428 } 429 430 joinOpts := map[string]interface{}{"foo": "fooValue"} 431 err = d.Join(netID, endID, "sandbox-key", ep, joinOpts) 432 if err != nil { 433 t.Fatal(err) 434 } 435 if _, err = d.EndpointOperInfo(netID, endID); err != nil { 436 t.Fatal(err) 437 } 438 if err = d.Leave(netID, endID); err != nil { 439 t.Fatal(err) 440 } 441 if err = d.DeleteEndpoint(netID, endID); err != nil { 442 t.Fatal(err) 443 } 444 if err = d.DeleteNetwork(netID); err != nil { 445 t.Fatal(err) 446 } 447 448 data := discoverapi.NodeDiscoveryData{ 449 Address: "192.168.1.1", 450 } 451 if err = d.DiscoverNew(discoverapi.NodeDiscovery, data); err != nil { 452 t.Fatal(err) 453 } 454 if err = d.DiscoverDelete(discoverapi.NodeDiscovery, data); err != nil { 455 t.Fatal(err) 456 } 457} 458 459func TestDriverError(t *testing.T) { 460 var plugin = "test-net-driver-error" 461 462 mux := http.NewServeMux() 463 defer setupPlugin(t, plugin, mux)() 464 465 handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} { 466 return map[string]interface{}{ 467 "Err": "this should get raised as an error", 468 } 469 }) 470 471 p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) 472 if err != nil { 473 t.Fatal(err) 474 } 475 476 driver := newDriver(plugin, p.Client()) 477 478 if err := driver.CreateEndpoint("dummy", "dummy", &testEndpoint{t: t}, map[string]interface{}{}); err == nil { 479 t.Fatal("Expected error from driver") 480 } 481} 482 483func TestMissingValues(t *testing.T) { 484 var plugin = "test-net-driver-missing" 485 486 mux := http.NewServeMux() 487 defer setupPlugin(t, plugin, mux)() 488 489 ep := &testEndpoint{ 490 t: t, 491 } 492 493 handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} { 494 iface := map[string]interface{}{ 495 "Address": ep.address, 496 "AddressIPv6": ep.addressIPv6, 497 "MacAddress": ep.macAddress, 498 } 499 return map[string]interface{}{ 500 "Interface": iface, 501 } 502 }) 503 504 p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) 505 if err != nil { 506 t.Fatal(err) 507 } 508 driver := newDriver(plugin, p.Client()) 509 510 if err := driver.CreateEndpoint("dummy", "dummy", ep, map[string]interface{}{}); err != nil { 511 t.Fatal(err) 512 } 513} 514 515type rollbackEndpoint struct { 516} 517 518func (r *rollbackEndpoint) Interface() driverapi.InterfaceInfo { 519 return r 520} 521 522func (r *rollbackEndpoint) MacAddress() net.HardwareAddr { 523 return nil 524} 525 526func (r *rollbackEndpoint) Address() *net.IPNet { 527 return nil 528} 529 530func (r *rollbackEndpoint) AddressIPv6() *net.IPNet { 531 return nil 532} 533 534func (r *rollbackEndpoint) SetMacAddress(mac net.HardwareAddr) error { 535 return errors.New("invalid mac") 536} 537 538func (r *rollbackEndpoint) SetIPAddress(ip *net.IPNet) error { 539 return errors.New("invalid ip") 540} 541 542func TestRollback(t *testing.T) { 543 var plugin = "test-net-driver-rollback" 544 545 mux := http.NewServeMux() 546 defer setupPlugin(t, plugin, mux)() 547 548 rolledback := false 549 550 handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} { 551 iface := map[string]interface{}{ 552 "Address": "192.168.4.5/16", 553 "AddressIPv6": "", 554 "MacAddress": "7a:12:34:56:78:90", 555 } 556 return map[string]interface{}{ 557 "Interface": interface{}(iface), 558 } 559 }) 560 handle(t, mux, "DeleteEndpoint", func(msg map[string]interface{}) interface{} { 561 rolledback = true 562 return map[string]interface{}{} 563 }) 564 565 p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) 566 if err != nil { 567 t.Fatal(err) 568 } 569 driver := newDriver(plugin, p.Client()) 570 571 ep := &rollbackEndpoint{} 572 573 if err := driver.CreateEndpoint("dummy", "dummy", ep.Interface(), map[string]interface{}{}); err == nil { 574 t.Fatal("Expected error from driver") 575 } 576 if !rolledback { 577 t.Fatal("Expected to have had DeleteEndpoint called") 578 } 579} 580