remote_test.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. package remote
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. "net"
  7. "net/http"
  8. "net/http/httptest"
  9. "os"
  10. "testing"
  11. "github.com/docker/docker/pkg/plugins"
  12. "github.com/docker/libnetwork/ipamapi"
  13. _ "github.com/docker/libnetwork/testutils"
  14. )
  15. func decodeToMap(r *http.Request) (res map[string]interface{}, err error) {
  16. err = json.NewDecoder(r.Body).Decode(&res)
  17. return
  18. }
  19. func handle(t *testing.T, mux *http.ServeMux, method string, h func(map[string]interface{}) interface{}) {
  20. mux.HandleFunc(fmt.Sprintf("/%s.%s", ipamapi.PluginEndpointType, method), func(w http.ResponseWriter, r *http.Request) {
  21. ask, err := decodeToMap(r)
  22. if err != nil {
  23. t.Fatal(err)
  24. }
  25. answer := h(ask)
  26. err = json.NewEncoder(w).Encode(&answer)
  27. if err != nil {
  28. t.Fatal(err)
  29. }
  30. })
  31. }
  32. func setupPlugin(t *testing.T, name string, mux *http.ServeMux) func() {
  33. if err := os.MkdirAll("/etc/docker/plugins", 0755); err != nil {
  34. t.Fatal(err)
  35. }
  36. server := httptest.NewServer(mux)
  37. if server == nil {
  38. t.Fatal("Failed to start a HTTP Server")
  39. }
  40. if err := ioutil.WriteFile(fmt.Sprintf("/etc/docker/plugins/%s.spec", name), []byte(server.URL), 0644); err != nil {
  41. t.Fatal(err)
  42. }
  43. mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
  44. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  45. fmt.Fprintf(w, `{"Implements": ["%s"]}`, ipamapi.PluginEndpointType)
  46. })
  47. return func() {
  48. if err := os.RemoveAll("/etc/docker/plugins"); err != nil {
  49. t.Fatal(err)
  50. }
  51. server.Close()
  52. }
  53. }
  54. func TestGetDefaultAddressSpaces(t *testing.T) {
  55. var plugin = "test-ipam-driver-addr-spaces"
  56. mux := http.NewServeMux()
  57. defer setupPlugin(t, plugin, mux)()
  58. handle(t, mux, "GetDefaultAddressSpaces", func(msg map[string]interface{}) interface{} {
  59. return map[string]interface{}{
  60. "LocalDefaultAddressSpace": "white",
  61. "GlobalDefaultAddressSpace": "blue",
  62. }
  63. })
  64. p, err := plugins.Get(plugin, ipamapi.PluginEndpointType)
  65. if err != nil {
  66. t.Fatal(err)
  67. }
  68. d := newAllocator(plugin, p.Client)
  69. l, g, err := d.(*allocator).GetDefaultAddressSpaces()
  70. if err != nil {
  71. t.Fatal(err)
  72. }
  73. if l != "white" || g != "blue" {
  74. t.Fatalf("Unexpected default local and global address spaces: %s, %s", l, g)
  75. }
  76. }
  77. func TestRemoteDriver(t *testing.T) {
  78. var plugin = "test-ipam-driver"
  79. mux := http.NewServeMux()
  80. defer setupPlugin(t, plugin, mux)()
  81. handle(t, mux, "GetDefaultAddressSpaces", func(msg map[string]interface{}) interface{} {
  82. return map[string]interface{}{
  83. "LocalDefaultAddressSpace": "white",
  84. "GlobalDefaultAddressSpace": "blue",
  85. }
  86. })
  87. handle(t, mux, "RequestPool", func(msg map[string]interface{}) interface{} {
  88. as := "white"
  89. if v, ok := msg["AddressSpace"]; ok && v.(string) != "" {
  90. as = v.(string)
  91. }
  92. pl := "172.18.0.0/16"
  93. sp := ""
  94. if v, ok := msg["Pool"]; ok && v.(string) != "" {
  95. pl = v.(string)
  96. }
  97. if v, ok := msg["SubPool"]; ok && v.(string) != "" {
  98. sp = v.(string)
  99. }
  100. pid := fmt.Sprintf("%s/%s", as, pl)
  101. if sp != "" {
  102. pid = fmt.Sprintf("%s/%s", pid, sp)
  103. }
  104. return map[string]interface{}{
  105. "PoolID": pid,
  106. "Pool": pl,
  107. "Data": map[string]string{"DNS": "8.8.8.8"},
  108. }
  109. })
  110. handle(t, mux, "ReleasePool", func(msg map[string]interface{}) interface{} {
  111. if _, ok := msg["PoolID"]; !ok {
  112. t.Fatalf("Missing PoolID in Release request")
  113. }
  114. return map[string]interface{}{}
  115. })
  116. handle(t, mux, "RequestAddress", func(msg map[string]interface{}) interface{} {
  117. if _, ok := msg["PoolID"]; !ok {
  118. t.Fatalf("Missing PoolID in address request")
  119. }
  120. prefAddr := ""
  121. if v, ok := msg["Address"]; ok {
  122. prefAddr = v.(string)
  123. }
  124. ip := prefAddr
  125. if ip == "" {
  126. ip = "172.20.0.34"
  127. }
  128. ip = fmt.Sprintf("%s/16", ip)
  129. return map[string]interface{}{
  130. "Address": ip,
  131. }
  132. })
  133. handle(t, mux, "ReleaseAddress", func(msg map[string]interface{}) interface{} {
  134. if _, ok := msg["PoolID"]; !ok {
  135. t.Fatalf("Missing PoolID in address request")
  136. }
  137. if _, ok := msg["Address"]; !ok {
  138. t.Fatalf("Missing Address in release address request")
  139. }
  140. return map[string]interface{}{}
  141. })
  142. p, err := plugins.Get(plugin, ipamapi.PluginEndpointType)
  143. if err != nil {
  144. t.Fatal(err)
  145. }
  146. d := newAllocator(plugin, p.Client)
  147. l, g, err := d.(*allocator).GetDefaultAddressSpaces()
  148. if err != nil {
  149. t.Fatal(err)
  150. }
  151. if l != "white" || g != "blue" {
  152. t.Fatalf("Unexpected default local/global address spaces: %s, %s", l, g)
  153. }
  154. // Request any pool
  155. poolID, pool, _, err := d.RequestPool("white", "", "", nil, false)
  156. if err != nil {
  157. t.Fatal(err)
  158. }
  159. if poolID != "white/172.18.0.0/16" {
  160. t.Fatalf("Unexpected pool id: %s", poolID)
  161. }
  162. if pool == nil || pool.String() != "172.18.0.0/16" {
  163. t.Fatalf("Unexpected pool: %s", pool)
  164. }
  165. // Request specific pool
  166. poolID2, pool2, ops, err := d.RequestPool("white", "172.20.0.0/16", "", nil, false)
  167. if err != nil {
  168. t.Fatal(err)
  169. }
  170. if poolID2 != "white/172.20.0.0/16" {
  171. t.Fatalf("Unexpected pool id: %s", poolID2)
  172. }
  173. if pool2 == nil || pool2.String() != "172.20.0.0/16" {
  174. t.Fatalf("Unexpected pool: %s", pool2)
  175. }
  176. if dns, ok := ops["DNS"]; !ok || dns != "8.8.8.8" {
  177. t.Fatalf("Missing options")
  178. }
  179. // Request specific pool and subpool
  180. poolID3, pool3, _, err := d.RequestPool("white", "172.20.0.0/16", "172.20.3.0/24" /*nil*/, map[string]string{"culo": "yes"}, false)
  181. if err != nil {
  182. t.Fatal(err)
  183. }
  184. if poolID3 != "white/172.20.0.0/16/172.20.3.0/24" {
  185. t.Fatalf("Unexpected pool id: %s", poolID3)
  186. }
  187. if pool3 == nil || pool3.String() != "172.20.0.0/16" {
  188. t.Fatalf("Unexpected pool: %s", pool3)
  189. }
  190. // Request any address
  191. addr, _, err := d.RequestAddress(poolID2, nil, nil)
  192. if err != nil {
  193. t.Fatal(err)
  194. }
  195. if addr == nil || addr.String() != "172.20.0.34/16" {
  196. t.Fatalf("Unexpected address: %s", addr)
  197. }
  198. // Request specific address
  199. addr2, _, err := d.RequestAddress(poolID2, net.ParseIP("172.20.1.45"), nil)
  200. if err != nil {
  201. t.Fatal(err)
  202. }
  203. if addr2 == nil || addr2.String() != "172.20.1.45/16" {
  204. t.Fatalf("Unexpected address: %s", addr2)
  205. }
  206. // Release address
  207. err = d.ReleaseAddress(poolID, net.ParseIP("172.18.1.45"))
  208. if err != nil {
  209. t.Fatal(err)
  210. }
  211. }