github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/libnetwork/ipams/remote/remote_test.go (about) 1 package remote 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "net" 9 "net/http" 10 "net/http/httptest" 11 "os" 12 "testing" 13 14 "github.com/docker/docker/pkg/plugins" 15 "github.com/docker/libnetwork/ipamapi" 16 _ "github.com/docker/libnetwork/testutils" 17 ) 18 19 func decodeToMap(r *http.Request) (res map[string]interface{}, err error) { 20 err = json.NewDecoder(r.Body).Decode(&res) 21 return 22 } 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", ipamapi.PluginEndpointType, 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 38 func setupPlugin(t *testing.T, name string, mux *http.ServeMux) func() { 39 if err := os.MkdirAll("/etc/docker/plugins", 0755); err != nil { 40 t.Fatal(err) 41 } 42 43 server := httptest.NewServer(mux) 44 if server == nil { 45 t.Fatal("Failed to start an HTTP Server") 46 } 47 48 if err := ioutil.WriteFile(fmt.Sprintf("/etc/docker/plugins/%s.spec", name), []byte(server.URL), 0644); err != nil { 49 t.Fatal(err) 50 } 51 52 mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { 53 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") 54 fmt.Fprintf(w, `{"Implements": ["%s"]}`, ipamapi.PluginEndpointType) 55 }) 56 57 return func() { 58 if err := os.RemoveAll("/etc/docker/plugins"); err != nil { 59 t.Fatal(err) 60 } 61 server.Close() 62 } 63 } 64 65 func TestGetCapabilities(t *testing.T) { 66 var plugin = "test-ipam-driver-capabilities" 67 68 mux := http.NewServeMux() 69 defer setupPlugin(t, plugin, mux)() 70 71 handle(t, mux, "GetCapabilities", func(msg map[string]interface{}) interface{} { 72 return map[string]interface{}{ 73 "RequiresMACAddress": true, 74 } 75 }) 76 77 p, err := plugins.Get(plugin, ipamapi.PluginEndpointType) 78 if err != nil { 79 t.Fatal(err) 80 } 81 82 client, err := getPluginClient(p) 83 if err != nil { 84 t.Fatal(err) 85 } 86 d := newAllocator(plugin, client) 87 88 caps, err := d.(*allocator).getCapabilities() 89 if err != nil { 90 t.Fatal(err) 91 } 92 93 if !caps.RequiresMACAddress || caps.RequiresRequestReplay { 94 t.Fatalf("Unexpected capability: %v", caps) 95 } 96 } 97 98 func TestGetCapabilitiesFromLegacyDriver(t *testing.T) { 99 var plugin = "test-ipam-legacy-driver" 100 101 mux := http.NewServeMux() 102 defer setupPlugin(t, plugin, mux)() 103 104 p, err := plugins.Get(plugin, ipamapi.PluginEndpointType) 105 if err != nil { 106 t.Fatal(err) 107 } 108 109 client, err := getPluginClient(p) 110 if err != nil { 111 t.Fatal(err) 112 } 113 114 d := newAllocator(plugin, client) 115 116 if _, err := d.(*allocator).getCapabilities(); err == nil { 117 t.Fatalf("Expected error, but got Success %v", err) 118 } 119 } 120 121 func TestGetDefaultAddressSpaces(t *testing.T) { 122 var plugin = "test-ipam-driver-addr-spaces" 123 124 mux := http.NewServeMux() 125 defer setupPlugin(t, plugin, mux)() 126 127 handle(t, mux, "GetDefaultAddressSpaces", func(msg map[string]interface{}) interface{} { 128 return map[string]interface{}{ 129 "LocalDefaultAddressSpace": "white", 130 "GlobalDefaultAddressSpace": "blue", 131 } 132 }) 133 134 p, err := plugins.Get(plugin, ipamapi.PluginEndpointType) 135 if err != nil { 136 t.Fatal(err) 137 } 138 139 client, err := getPluginClient(p) 140 if err != nil { 141 t.Fatal(err) 142 } 143 d := newAllocator(plugin, client) 144 145 l, g, err := d.(*allocator).GetDefaultAddressSpaces() 146 if err != nil { 147 t.Fatal(err) 148 } 149 150 if l != "white" || g != "blue" { 151 t.Fatalf("Unexpected default local and global address spaces: %s, %s", l, g) 152 } 153 } 154 155 func TestRemoteDriver(t *testing.T) { 156 var plugin = "test-ipam-driver" 157 158 mux := http.NewServeMux() 159 defer setupPlugin(t, plugin, mux)() 160 161 handle(t, mux, "GetDefaultAddressSpaces", func(msg map[string]interface{}) interface{} { 162 return map[string]interface{}{ 163 "LocalDefaultAddressSpace": "white", 164 "GlobalDefaultAddressSpace": "blue", 165 } 166 }) 167 168 handle(t, mux, "RequestPool", func(msg map[string]interface{}) interface{} { 169 as := "white" 170 if v, ok := msg["AddressSpace"]; ok && v.(string) != "" { 171 as = v.(string) 172 } 173 174 pl := "172.18.0.0/16" 175 sp := "" 176 if v, ok := msg["Pool"]; ok && v.(string) != "" { 177 pl = v.(string) 178 } 179 if v, ok := msg["SubPool"]; ok && v.(string) != "" { 180 sp = v.(string) 181 } 182 pid := fmt.Sprintf("%s/%s", as, pl) 183 if sp != "" { 184 pid = fmt.Sprintf("%s/%s", pid, sp) 185 } 186 return map[string]interface{}{ 187 "PoolID": pid, 188 "Pool": pl, 189 "Data": map[string]string{"DNS": "8.8.8.8"}, 190 } 191 }) 192 193 handle(t, mux, "ReleasePool", func(msg map[string]interface{}) interface{} { 194 if _, ok := msg["PoolID"]; !ok { 195 t.Fatal("Missing PoolID in Release request") 196 } 197 return map[string]interface{}{} 198 }) 199 200 handle(t, mux, "RequestAddress", func(msg map[string]interface{}) interface{} { 201 if _, ok := msg["PoolID"]; !ok { 202 t.Fatal("Missing PoolID in address request") 203 } 204 prefAddr := "" 205 if v, ok := msg["Address"]; ok { 206 prefAddr = v.(string) 207 } 208 ip := prefAddr 209 if ip == "" { 210 ip = "172.20.0.34" 211 } 212 ip = fmt.Sprintf("%s/16", ip) 213 return map[string]interface{}{ 214 "Address": ip, 215 } 216 }) 217 218 handle(t, mux, "ReleaseAddress", func(msg map[string]interface{}) interface{} { 219 if _, ok := msg["PoolID"]; !ok { 220 t.Fatal("Missing PoolID in address request") 221 } 222 if _, ok := msg["Address"]; !ok { 223 t.Fatal("Missing Address in release address request") 224 } 225 return map[string]interface{}{} 226 }) 227 228 p, err := plugins.Get(plugin, ipamapi.PluginEndpointType) 229 if err != nil { 230 t.Fatal(err) 231 } 232 233 client, err := getPluginClient(p) 234 if err != nil { 235 t.Fatal(err) 236 } 237 d := newAllocator(plugin, client) 238 239 l, g, err := d.(*allocator).GetDefaultAddressSpaces() 240 if err != nil { 241 t.Fatal(err) 242 } 243 if l != "white" || g != "blue" { 244 t.Fatalf("Unexpected default local/global address spaces: %s, %s", l, g) 245 } 246 247 // Request any pool 248 poolID, pool, _, err := d.RequestPool("white", "", "", nil, false) 249 if err != nil { 250 t.Fatal(err) 251 } 252 if poolID != "white/172.18.0.0/16" { 253 t.Fatalf("Unexpected pool id: %s", poolID) 254 } 255 if pool == nil || pool.String() != "172.18.0.0/16" { 256 t.Fatalf("Unexpected pool: %s", pool) 257 } 258 259 // Request specific pool 260 poolID2, pool2, ops, err := d.RequestPool("white", "172.20.0.0/16", "", nil, false) 261 if err != nil { 262 t.Fatal(err) 263 } 264 if poolID2 != "white/172.20.0.0/16" { 265 t.Fatalf("Unexpected pool id: %s", poolID2) 266 } 267 if pool2 == nil || pool2.String() != "172.20.0.0/16" { 268 t.Fatalf("Unexpected pool: %s", pool2) 269 } 270 if dns, ok := ops["DNS"]; !ok || dns != "8.8.8.8" { 271 t.Fatal("Missing options") 272 } 273 274 // Request specific pool and subpool 275 poolID3, pool3, _, err := d.RequestPool("white", "172.20.0.0/16", "172.20.3.0/24" /*nil*/, map[string]string{"culo": "yes"}, false) 276 if err != nil { 277 t.Fatal(err) 278 } 279 if poolID3 != "white/172.20.0.0/16/172.20.3.0/24" { 280 t.Fatalf("Unexpected pool id: %s", poolID3) 281 } 282 if pool3 == nil || pool3.String() != "172.20.0.0/16" { 283 t.Fatalf("Unexpected pool: %s", pool3) 284 } 285 286 // Request any address 287 addr, _, err := d.RequestAddress(poolID2, nil, nil) 288 if err != nil { 289 t.Fatal(err) 290 } 291 if addr == nil || addr.String() != "172.20.0.34/16" { 292 t.Fatalf("Unexpected address: %s", addr) 293 } 294 295 // Request specific address 296 addr2, _, err := d.RequestAddress(poolID2, net.ParseIP("172.20.1.45"), nil) 297 if err != nil { 298 t.Fatal(err) 299 } 300 if addr2 == nil || addr2.String() != "172.20.1.45/16" { 301 t.Fatalf("Unexpected address: %s", addr2) 302 } 303 304 // Release address 305 err = d.ReleaseAddress(poolID, net.ParseIP("172.18.1.45")) 306 if err != nil { 307 t.Fatal(err) 308 } 309 }