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  }