driver_test.go 15 KB

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