github.com/rawahars/moby@v24.0.4+incompatible/integration/network/network_test.go (about)

     1  package network // import "github.com/docker/docker/integration/network"
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"net/http"
     9  	"os/exec"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/docker/docker/api/types"
    14  	ntypes "github.com/docker/docker/api/types/network"
    15  	"github.com/docker/docker/integration/internal/container"
    16  	"github.com/docker/docker/integration/internal/network"
    17  	"github.com/docker/docker/testutil/daemon"
    18  	"github.com/docker/docker/testutil/request"
    19  	"gotest.tools/v3/assert"
    20  	is "gotest.tools/v3/assert/cmp"
    21  	"gotest.tools/v3/icmd"
    22  	"gotest.tools/v3/skip"
    23  )
    24  
    25  func TestRunContainerWithBridgeNone(t *testing.T) {
    26  	skip.If(t, testEnv.IsRemoteDaemon, "cannot start daemon on remote test run")
    27  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
    28  	skip.If(t, testEnv.IsUserNamespace)
    29  	skip.If(t, testEnv.IsRootless, "rootless mode has different view of network")
    30  
    31  	d := daemon.New(t)
    32  	d.StartWithBusybox(t, "-b", "none")
    33  	defer d.Stop(t)
    34  
    35  	c := d.NewClientT(t)
    36  	ctx := context.Background()
    37  
    38  	id1 := container.Run(ctx, t, c)
    39  	defer c.ContainerRemove(ctx, id1, types.ContainerRemoveOptions{Force: true})
    40  
    41  	result, err := container.Exec(ctx, c, id1, []string{"ip", "l"})
    42  	assert.NilError(t, err)
    43  	assert.Check(t, is.Equal(false, strings.Contains(result.Combined(), "eth0")), "There shouldn't be eth0 in container in default(bridge) mode when bridge network is disabled")
    44  
    45  	id2 := container.Run(ctx, t, c, container.WithNetworkMode("bridge"))
    46  	defer c.ContainerRemove(ctx, id2, types.ContainerRemoveOptions{Force: true})
    47  
    48  	result, err = container.Exec(ctx, c, id2, []string{"ip", "l"})
    49  	assert.NilError(t, err)
    50  	assert.Check(t, is.Equal(false, strings.Contains(result.Combined(), "eth0")), "There shouldn't be eth0 in container in bridge mode when bridge network is disabled")
    51  
    52  	nsCommand := "ls -l /proc/self/ns/net | awk -F '->' '{print $2}'"
    53  	cmd := exec.Command("sh", "-c", nsCommand)
    54  	stdout := bytes.NewBuffer(nil)
    55  	cmd.Stdout = stdout
    56  	err = cmd.Run()
    57  	assert.NilError(t, err, "Failed to get current process network namespace: %+v", err)
    58  
    59  	id3 := container.Run(ctx, t, c, container.WithNetworkMode("host"))
    60  	defer c.ContainerRemove(ctx, id3, types.ContainerRemoveOptions{Force: true})
    61  
    62  	result, err = container.Exec(ctx, c, id3, []string{"sh", "-c", nsCommand})
    63  	assert.NilError(t, err)
    64  	assert.Check(t, is.Equal(stdout.String(), result.Combined()), "The network namespace of container should be the same with host when --net=host and bridge network is disabled")
    65  }
    66  
    67  // TestNetworkInvalidJSON tests that POST endpoints that expect a body return
    68  // the correct error when sending invalid JSON requests.
    69  func TestNetworkInvalidJSON(t *testing.T) {
    70  	defer setupTest(t)()
    71  
    72  	// POST endpoints that accept / expect a JSON body;
    73  	endpoints := []string{
    74  		"/networks/create",
    75  		"/networks/bridge/connect",
    76  		"/networks/bridge/disconnect",
    77  	}
    78  
    79  	for _, ep := range endpoints {
    80  		ep := ep
    81  		t.Run(ep[1:], func(t *testing.T) {
    82  			t.Parallel()
    83  
    84  			t.Run("invalid content type", func(t *testing.T) {
    85  				res, body, err := request.Post(ep, request.RawString("{}"), request.ContentType("text/plain"))
    86  				assert.NilError(t, err)
    87  				assert.Check(t, is.Equal(res.StatusCode, http.StatusBadRequest))
    88  
    89  				buf, err := request.ReadBody(body)
    90  				assert.NilError(t, err)
    91  				assert.Check(t, is.Contains(string(buf), "unsupported Content-Type header (text/plain): must be 'application/json'"))
    92  			})
    93  
    94  			t.Run("invalid JSON", func(t *testing.T) {
    95  				res, body, err := request.Post(ep, request.RawString("{invalid json"), request.JSON)
    96  				assert.NilError(t, err)
    97  				assert.Check(t, is.Equal(res.StatusCode, http.StatusBadRequest))
    98  
    99  				buf, err := request.ReadBody(body)
   100  				assert.NilError(t, err)
   101  				assert.Check(t, is.Contains(string(buf), "invalid JSON: invalid character 'i' looking for beginning of object key string"))
   102  			})
   103  
   104  			t.Run("extra content after JSON", func(t *testing.T) {
   105  				res, body, err := request.Post(ep, request.RawString(`{} trailing content`), request.JSON)
   106  				assert.NilError(t, err)
   107  				assert.Check(t, is.Equal(res.StatusCode, http.StatusBadRequest))
   108  
   109  				buf, err := request.ReadBody(body)
   110  				assert.NilError(t, err)
   111  				assert.Check(t, is.Contains(string(buf), "unexpected content after JSON"))
   112  			})
   113  
   114  			t.Run("empty body", func(t *testing.T) {
   115  				// empty body should not produce an 500 internal server error, or
   116  				// any 5XX error (this is assuming the request does not produce
   117  				// an internal server error for another reason, but it shouldn't)
   118  				res, _, err := request.Post(ep, request.RawString(``), request.JSON)
   119  				assert.NilError(t, err)
   120  				assert.Check(t, res.StatusCode < http.StatusInternalServerError)
   121  			})
   122  		})
   123  	}
   124  }
   125  
   126  // TestNetworkList verifies that /networks returns a list of networks either
   127  // with, or without a trailing slash (/networks/). Regression test for https://github.com/moby/moby/issues/24595
   128  func TestNetworkList(t *testing.T) {
   129  	defer setupTest(t)()
   130  
   131  	endpoints := []string{
   132  		"/networks",
   133  		"/networks/",
   134  	}
   135  
   136  	for _, ep := range endpoints {
   137  		ep := ep
   138  		t.Run(ep, func(t *testing.T) {
   139  			t.Parallel()
   140  
   141  			res, body, err := request.Get(ep, request.JSON)
   142  			assert.NilError(t, err)
   143  			assert.Equal(t, res.StatusCode, http.StatusOK)
   144  
   145  			buf, err := request.ReadBody(body)
   146  			assert.NilError(t, err)
   147  			var nws []types.NetworkResource
   148  			err = json.Unmarshal(buf, &nws)
   149  			assert.NilError(t, err)
   150  			assert.Assert(t, len(nws) > 0)
   151  		})
   152  	}
   153  }
   154  
   155  func TestHostIPv4BridgeLabel(t *testing.T) {
   156  	skip.If(t, testEnv.OSType == "windows")
   157  	skip.If(t, testEnv.IsRemoteDaemon)
   158  	skip.If(t, testEnv.IsRootless, "rootless mode has different view of network")
   159  	d := daemon.New(t)
   160  	d.Start(t)
   161  	defer d.Stop(t)
   162  	c := d.NewClientT(t)
   163  	defer c.Close()
   164  	ctx := context.Background()
   165  
   166  	ipv4SNATAddr := "172.0.0.172"
   167  	// Create a bridge network with --opt com.docker.network.host_ipv4=172.0.0.172
   168  	bridgeName := "hostIPv4Bridge"
   169  	network.CreateNoError(ctx, t, c, bridgeName,
   170  		network.WithDriver("bridge"),
   171  		network.WithOption("com.docker.network.host_ipv4", ipv4SNATAddr),
   172  		network.WithOption("com.docker.network.bridge.name", bridgeName),
   173  	)
   174  	out, err := c.NetworkInspect(ctx, bridgeName, types.NetworkInspectOptions{Verbose: true})
   175  	assert.NilError(t, err)
   176  	assert.Assert(t, len(out.IPAM.Config) > 0)
   177  	// Make sure the SNAT rule exists
   178  	icmd.RunCommand("iptables", "-t", "nat", "-C", "POSTROUTING", "-s", out.IPAM.Config[0].Subnet, "!", "-o", bridgeName, "-j", "SNAT", "--to-source", ipv4SNATAddr).Assert(t, icmd.Success)
   179  }
   180  
   181  func TestDefaultNetworkOpts(t *testing.T) {
   182  	skip.If(t, testEnv.OSType == "windows")
   183  	skip.If(t, testEnv.IsRemoteDaemon)
   184  	skip.If(t, testEnv.IsRootless, "rootless mode has different view of network")
   185  
   186  	tests := []struct {
   187  		name       string
   188  		mtu        int
   189  		configFrom bool
   190  		args       []string
   191  	}{
   192  		{
   193  			name: "default value",
   194  			mtu:  1500,
   195  			args: []string{},
   196  		},
   197  		{
   198  			name: "cmdline value",
   199  			mtu:  1234,
   200  			args: []string{"--default-network-opt", "bridge=com.docker.network.driver.mtu=1234"},
   201  		},
   202  		{
   203  			name:       "config-from value",
   204  			configFrom: true,
   205  			mtu:        1233,
   206  			args:       []string{"--default-network-opt", "bridge=com.docker.network.driver.mtu=1234"},
   207  		},
   208  	}
   209  
   210  	for _, tc := range tests {
   211  		tc := tc
   212  		t.Run(tc.name, func(t *testing.T) {
   213  			d := daemon.New(t)
   214  			d.StartWithBusybox(t, tc.args...)
   215  			defer d.Stop(t)
   216  			c := d.NewClientT(t)
   217  			defer c.Close()
   218  			ctx := context.Background()
   219  
   220  			if tc.configFrom {
   221  				// Create a new network config
   222  				network.CreateNoError(ctx, t, c, "from-net", func(create *types.NetworkCreate) {
   223  					create.ConfigOnly = true
   224  					create.Options = map[string]string{
   225  						"com.docker.network.driver.mtu": fmt.Sprint(tc.mtu),
   226  					}
   227  				})
   228  				defer c.NetworkRemove(ctx, "from-net")
   229  			}
   230  
   231  			// Create a new network
   232  			networkName := "testnet"
   233  			network.CreateNoError(ctx, t, c, networkName, func(create *types.NetworkCreate) {
   234  				if tc.configFrom {
   235  					create.ConfigFrom = &ntypes.ConfigReference{
   236  						Network: "from-net",
   237  					}
   238  				}
   239  			})
   240  			defer c.NetworkRemove(ctx, networkName)
   241  
   242  			// Start a container to inspect the MTU of its network interface
   243  			id1 := container.Run(ctx, t, c, container.WithNetworkMode(networkName))
   244  			defer c.ContainerRemove(ctx, id1, types.ContainerRemoveOptions{Force: true})
   245  
   246  			result, err := container.Exec(ctx, c, id1, []string{"ip", "l", "show", "eth0"})
   247  			assert.NilError(t, err)
   248  			assert.Check(t, is.Contains(result.Combined(), fmt.Sprintf(" mtu %d ", tc.mtu)), "Network MTU should have been set to %d", tc.mtu)
   249  		})
   250  	}
   251  }