github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/drivers/remote/driver_test.go (about)

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