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