github.com/toplink-cn/moby@v0.0.0-20240305205811-460b4aebdf81/integration-cli/docker_api_network_test.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net"
     7  	"net/http"
     8  	"net/url"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/docker/docker/api/types"
    13  	"github.com/docker/docker/api/types/filters"
    14  	"github.com/docker/docker/api/types/network"
    15  	"github.com/docker/docker/integration-cli/cli"
    16  	"github.com/docker/docker/testutil"
    17  	"github.com/docker/docker/testutil/request"
    18  	"gotest.tools/v3/assert"
    19  )
    20  
    21  func (s *DockerAPISuite) TestAPINetworkGetDefaults(c *testing.T) {
    22  	testRequires(c, DaemonIsLinux)
    23  	// By default docker daemon creates 3 networks. check if they are present
    24  	defaults := []string{"bridge", "host", "none"}
    25  	for _, nn := range defaults {
    26  		assert.Assert(c, isNetworkAvailable(c, nn))
    27  	}
    28  }
    29  
    30  func (s *DockerAPISuite) TestAPINetworkFilter(c *testing.T) {
    31  	testRequires(c, DaemonIsLinux)
    32  	nr := getNetworkResource(c, getNetworkIDByName(c, "bridge"))
    33  	assert.Equal(c, nr.Name, "bridge")
    34  }
    35  
    36  func (s *DockerAPISuite) TestAPINetworkInspectBridge(c *testing.T) {
    37  	testRequires(c, DaemonIsLinux)
    38  	// Inspect default bridge network
    39  	nr := getNetworkResource(c, "bridge")
    40  	assert.Equal(c, nr.Name, "bridge")
    41  
    42  	// run a container and attach it to the default bridge network
    43  	out := cli.DockerCmd(c, "run", "-d", "--name", "test", "busybox", "top").Stdout()
    44  	containerID := strings.TrimSpace(out)
    45  	containerIP := findContainerIP(c, "test", "bridge")
    46  
    47  	// inspect default bridge network again and make sure the container is connected
    48  	nr = getNetworkResource(c, nr.ID)
    49  	assert.Equal(c, nr.Driver, "bridge")
    50  	assert.Equal(c, nr.Scope, "local")
    51  	assert.Equal(c, nr.Internal, false)
    52  	assert.Equal(c, nr.EnableIPv6, false)
    53  	assert.Equal(c, nr.IPAM.Driver, "default")
    54  	_, ok := nr.Containers[containerID]
    55  	assert.Assert(c, ok)
    56  
    57  	ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
    58  	assert.NilError(c, err)
    59  	assert.Equal(c, ip.String(), containerIP)
    60  }
    61  
    62  func (s *DockerAPISuite) TestAPINetworkInspectUserDefinedNetwork(c *testing.T) {
    63  	testRequires(c, DaemonIsLinux)
    64  	// IPAM configuration inspect
    65  	ipam := &network.IPAM{
    66  		Driver: "default",
    67  		Config: []network.IPAMConfig{{Subnet: "172.28.0.0/16", IPRange: "172.28.5.0/24", Gateway: "172.28.5.254"}},
    68  	}
    69  	config := types.NetworkCreateRequest{
    70  		Name: "br0",
    71  		NetworkCreate: types.NetworkCreate{
    72  			Driver:  "bridge",
    73  			IPAM:    ipam,
    74  			Options: map[string]string{"foo": "bar", "opts": "dopts"},
    75  		},
    76  	}
    77  	id0 := createNetwork(c, config, http.StatusCreated)
    78  	assert.Assert(c, isNetworkAvailable(c, "br0"))
    79  
    80  	nr := getNetworkResource(c, id0)
    81  	assert.Equal(c, len(nr.IPAM.Config), 1)
    82  	assert.Equal(c, nr.IPAM.Config[0].Subnet, "172.28.0.0/16")
    83  	assert.Equal(c, nr.IPAM.Config[0].IPRange, "172.28.5.0/24")
    84  	assert.Equal(c, nr.IPAM.Config[0].Gateway, "172.28.5.254")
    85  	assert.Equal(c, nr.Options["foo"], "bar")
    86  	assert.Equal(c, nr.Options["opts"], "dopts")
    87  
    88  	// delete the network and make sure it is deleted
    89  	deleteNetwork(c, id0, true)
    90  	assert.Assert(c, !isNetworkAvailable(c, "br0"))
    91  }
    92  
    93  func (s *DockerAPISuite) TestAPINetworkConnectDisconnect(c *testing.T) {
    94  	testRequires(c, DaemonIsLinux)
    95  	// Create test network
    96  	name := "testnetwork"
    97  	config := types.NetworkCreateRequest{
    98  		Name: name,
    99  	}
   100  	id := createNetwork(c, config, http.StatusCreated)
   101  	nr := getNetworkResource(c, id)
   102  	assert.Equal(c, nr.Name, name)
   103  	assert.Equal(c, nr.ID, id)
   104  	assert.Equal(c, len(nr.Containers), 0)
   105  
   106  	// run a container
   107  	out := cli.DockerCmd(c, "run", "-d", "--name", "test", "busybox", "top").Stdout()
   108  	containerID := strings.TrimSpace(out)
   109  
   110  	// connect the container to the test network
   111  	connectNetwork(c, nr.ID, containerID)
   112  
   113  	// inspect the network to make sure container is connected
   114  	nr = getNetworkResource(c, nr.ID)
   115  	assert.Equal(c, len(nr.Containers), 1)
   116  	_, ok := nr.Containers[containerID]
   117  	assert.Assert(c, ok)
   118  
   119  	// check if container IP matches network inspect
   120  	ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
   121  	assert.NilError(c, err)
   122  	containerIP := findContainerIP(c, "test", "testnetwork")
   123  	assert.Equal(c, ip.String(), containerIP)
   124  
   125  	// disconnect container from the network
   126  	disconnectNetwork(c, nr.ID, containerID)
   127  	nr = getNetworkResource(c, nr.ID)
   128  	assert.Equal(c, nr.Name, name)
   129  	assert.Equal(c, len(nr.Containers), 0)
   130  
   131  	// delete the network
   132  	deleteNetwork(c, nr.ID, true)
   133  }
   134  
   135  func (s *DockerAPISuite) TestAPINetworkIPAMMultipleBridgeNetworks(c *testing.T) {
   136  	testRequires(c, DaemonIsLinux)
   137  	// test0 bridge network
   138  	ipam0 := &network.IPAM{
   139  		Driver: "default",
   140  		Config: []network.IPAMConfig{{Subnet: "192.178.0.0/16", IPRange: "192.178.128.0/17", Gateway: "192.178.138.100"}},
   141  	}
   142  	config0 := types.NetworkCreateRequest{
   143  		Name: "test0",
   144  		NetworkCreate: types.NetworkCreate{
   145  			Driver: "bridge",
   146  			IPAM:   ipam0,
   147  		},
   148  	}
   149  	id0 := createNetwork(c, config0, http.StatusCreated)
   150  	assert.Assert(c, isNetworkAvailable(c, "test0"))
   151  
   152  	ipam1 := &network.IPAM{
   153  		Driver: "default",
   154  		Config: []network.IPAMConfig{{Subnet: "192.178.128.0/17", Gateway: "192.178.128.1"}},
   155  	}
   156  	// test1 bridge network overlaps with test0
   157  	config1 := types.NetworkCreateRequest{
   158  		Name: "test1",
   159  		NetworkCreate: types.NetworkCreate{
   160  			Driver: "bridge",
   161  			IPAM:   ipam1,
   162  		},
   163  	}
   164  	createNetwork(c, config1, http.StatusForbidden)
   165  	assert.Assert(c, !isNetworkAvailable(c, "test1"))
   166  
   167  	ipam2 := &network.IPAM{
   168  		Driver: "default",
   169  		Config: []network.IPAMConfig{{Subnet: "192.169.0.0/16", Gateway: "192.169.100.100"}},
   170  	}
   171  	// test2 bridge network does not overlap
   172  	config2 := types.NetworkCreateRequest{
   173  		Name: "test2",
   174  		NetworkCreate: types.NetworkCreate{
   175  			Driver: "bridge",
   176  			IPAM:   ipam2,
   177  		},
   178  	}
   179  	createNetwork(c, config2, http.StatusCreated)
   180  	assert.Assert(c, isNetworkAvailable(c, "test2"))
   181  
   182  	// remove test0 and retry to create test1
   183  	deleteNetwork(c, id0, true)
   184  	createNetwork(c, config1, http.StatusCreated)
   185  	assert.Assert(c, isNetworkAvailable(c, "test1"))
   186  
   187  	// for networks w/o ipam specified, docker will choose proper non-overlapping subnets
   188  	createNetwork(c, types.NetworkCreateRequest{Name: "test3"}, http.StatusCreated)
   189  	assert.Assert(c, isNetworkAvailable(c, "test3"))
   190  	createNetwork(c, types.NetworkCreateRequest{Name: "test4"}, http.StatusCreated)
   191  	assert.Assert(c, isNetworkAvailable(c, "test4"))
   192  	createNetwork(c, types.NetworkCreateRequest{Name: "test5"}, http.StatusCreated)
   193  	assert.Assert(c, isNetworkAvailable(c, "test5"))
   194  
   195  	for i := 1; i < 6; i++ {
   196  		deleteNetwork(c, fmt.Sprintf("test%d", i), true)
   197  	}
   198  }
   199  
   200  func (s *DockerAPISuite) TestAPICreateDeletePredefinedNetworks(c *testing.T) {
   201  	testRequires(c, DaemonIsLinux, SwarmInactive)
   202  	createDeletePredefinedNetwork(c, "bridge")
   203  	createDeletePredefinedNetwork(c, "none")
   204  	createDeletePredefinedNetwork(c, "host")
   205  }
   206  
   207  func createDeletePredefinedNetwork(c *testing.T, name string) {
   208  	// Create pre-defined network
   209  	config := types.NetworkCreateRequest{Name: name}
   210  	expectedStatus := http.StatusForbidden
   211  	createNetwork(c, config, expectedStatus)
   212  	deleteNetwork(c, name, false)
   213  }
   214  
   215  func isNetworkAvailable(c *testing.T, name string) bool {
   216  	resp, body, err := request.Get(testutil.GetContext(c), "/networks")
   217  	assert.NilError(c, err)
   218  	defer resp.Body.Close()
   219  	assert.Equal(c, resp.StatusCode, http.StatusOK)
   220  
   221  	var nJSON []types.NetworkResource
   222  	err = json.NewDecoder(body).Decode(&nJSON)
   223  	assert.NilError(c, err)
   224  
   225  	for _, n := range nJSON {
   226  		if n.Name == name {
   227  			return true
   228  		}
   229  	}
   230  	return false
   231  }
   232  
   233  func getNetworkIDByName(c *testing.T, name string) string {
   234  	filterJSON, err := filters.ToJSON(filters.NewArgs(filters.Arg("name", name)))
   235  	assert.NilError(c, err)
   236  	v := url.Values{}
   237  	v.Set("filters", filterJSON)
   238  
   239  	resp, body, err := request.Get(testutil.GetContext(c), "/networks?"+v.Encode())
   240  	assert.Equal(c, resp.StatusCode, http.StatusOK)
   241  	assert.NilError(c, err)
   242  
   243  	var nJSON []types.NetworkResource
   244  	err = json.NewDecoder(body).Decode(&nJSON)
   245  	assert.NilError(c, err)
   246  	var res string
   247  	for _, n := range nJSON {
   248  		// Find exact match
   249  		if n.Name == name {
   250  			res = n.ID
   251  		}
   252  	}
   253  	assert.Assert(c, res != "")
   254  
   255  	return res
   256  }
   257  
   258  func getNetworkResource(c *testing.T, id string) *types.NetworkResource {
   259  	_, obj, err := request.Get(testutil.GetContext(c), "/networks/"+id)
   260  	assert.NilError(c, err)
   261  
   262  	nr := types.NetworkResource{}
   263  	err = json.NewDecoder(obj).Decode(&nr)
   264  	assert.NilError(c, err)
   265  
   266  	return &nr
   267  }
   268  
   269  func createNetwork(c *testing.T, config types.NetworkCreateRequest, expectedStatusCode int) string {
   270  	resp, body, err := request.Post(testutil.GetContext(c), "/networks/create", request.JSONBody(config))
   271  	assert.NilError(c, err)
   272  	defer resp.Body.Close()
   273  
   274  	if expectedStatusCode >= 0 {
   275  		assert.Equal(c, resp.StatusCode, expectedStatusCode)
   276  	} else {
   277  		assert.Assert(c, resp.StatusCode != -expectedStatusCode)
   278  	}
   279  
   280  	if expectedStatusCode == http.StatusCreated || expectedStatusCode < 0 {
   281  		var nr types.NetworkCreateResponse
   282  		err = json.NewDecoder(body).Decode(&nr)
   283  		assert.NilError(c, err)
   284  
   285  		return nr.ID
   286  	}
   287  	return ""
   288  }
   289  
   290  func connectNetwork(c *testing.T, nid, cid string) {
   291  	config := types.NetworkConnect{
   292  		Container: cid,
   293  	}
   294  
   295  	resp, _, err := request.Post(testutil.GetContext(c), "/networks/"+nid+"/connect", request.JSONBody(config))
   296  	assert.Equal(c, resp.StatusCode, http.StatusOK)
   297  	assert.NilError(c, err)
   298  }
   299  
   300  func disconnectNetwork(c *testing.T, nid, cid string) {
   301  	config := types.NetworkConnect{
   302  		Container: cid,
   303  	}
   304  
   305  	resp, _, err := request.Post(testutil.GetContext(c), "/networks/"+nid+"/disconnect", request.JSONBody(config))
   306  	assert.Equal(c, resp.StatusCode, http.StatusOK)
   307  	assert.NilError(c, err)
   308  }
   309  
   310  func deleteNetwork(c *testing.T, id string, shouldSucceed bool) {
   311  	resp, _, err := request.Delete(testutil.GetContext(c), "/networks/"+id)
   312  	assert.NilError(c, err)
   313  	defer resp.Body.Close()
   314  	if !shouldSucceed {
   315  		assert.Assert(c, resp.StatusCode != http.StatusOK)
   316  		return
   317  	}
   318  	assert.Equal(c, resp.StatusCode, http.StatusNoContent)
   319  }