driver_test.go 15 KB

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