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