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