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