Browse code

Add TestJoinError

Signed-off-by: Rob Murray <rob.murray@docker.com>

Rob Murray authored on 2025/09/11 19:39:22
Showing 1 changed files
... ...
@@ -1218,3 +1218,76 @@ func TestBridgeIPAMStatus(t *testing.T) {
1218 1218
 		})
1219 1219
 	})
1220 1220
 }
1221
+
1222
+// TestJoinError checks that if network connection fails late in the process, it's
1223
+// rolled back properly - the failed connection should not show up in container
1224
+// or network inspect, and the container should not gain a network interface.
1225
+func TestJoinError(t *testing.T) {
1226
+	ctx := setupTest(t)
1227
+	d := daemon.New(t)
1228
+	d.StartWithBusybox(ctx, t)
1229
+	defer d.Stop(t)
1230
+	c := d.NewClientT(t)
1231
+
1232
+	const intNet = "intnet"
1233
+	const gwAddr = "192.168.123.1"
1234
+	network.CreateNoError(ctx, t, c, intNet,
1235
+		network.WithInternal(),
1236
+		network.WithIPAM("192.168.123.0/24", gwAddr),
1237
+	)
1238
+	defer network.RemoveNoError(ctx, t, c, intNet)
1239
+
1240
+	const extNet = "extnet"
1241
+	network.CreateNoError(ctx, t, c, extNet)
1242
+	defer network.RemoveNoError(ctx, t, c, extNet)
1243
+
1244
+	cid := ctr.Run(ctx, t, c,
1245
+		ctr.WithNetworkMode(intNet),
1246
+		ctr.WithPrivileged(true),
1247
+	)
1248
+	defer c.ContainerRemove(ctx, cid, client.ContainerRemoveOptions{Force: true})
1249
+
1250
+	// Add a default route to the container, so that connecting extNet will fail to
1251
+	// set up its own default route.
1252
+	res := ctr.ExecT(ctx, t, c, cid, []string{"ip", "route", "add", "default", "via", gwAddr})
1253
+	assert.Equal(t, res.ExitCode, 0)
1254
+
1255
+	// Expect an error when connecting extNet.
1256
+	err := c.NetworkConnect(ctx, extNet, cid, &networktypes.EndpointSettings{})
1257
+	assert.Check(t, is.ErrorContains(err, "failed to set gateway: file exists"))
1258
+
1259
+	// Only intNet should show up in container inspect.
1260
+	ctrInsp := ctr.Inspect(ctx, t, c, cid)
1261
+	assert.Check(t, is.Len(ctrInsp.NetworkSettings.Networks, 1))
1262
+	assert.Check(t, is.Contains(ctrInsp.NetworkSettings.Networks, intNet))
1263
+
1264
+	// extNet should not report any attached containers
1265
+	extNetInsp, err := c.NetworkInspect(ctx, extNet, client.NetworkInspectOptions{})
1266
+	assert.Check(t, err)
1267
+	assert.Check(t, is.Len(extNetInsp.Containers, 0))
1268
+
1269
+	// The container should have an eth0, but no eth1.
1270
+	res = ctr.ExecT(ctx, t, c, cid, []string{"ip", "link", "show", "eth0"})
1271
+	assert.Check(t, is.Equal(res.ExitCode, 0), "container should have an eth0")
1272
+	res = ctr.ExecT(ctx, t, c, cid, []string{"ip", "link", "show", "eth1"})
1273
+	assert.Check(t, is.Contains(res.Stderr(), "can't find device"), "container should not have an eth1")
1274
+
1275
+	// Remove the dodgy route.
1276
+	res = ctr.ExecT(ctx, t, c, cid, []string{"ip", "route", "del", "default", "via", gwAddr})
1277
+	assert.Equal(t, res.ExitCode, 0)
1278
+
1279
+	// Check network connect now succeeds.
1280
+	err = c.NetworkConnect(ctx, extNet, cid, &networktypes.EndpointSettings{})
1281
+	assert.Check(t, err)
1282
+	ctrInsp = ctr.Inspect(ctx, t, c, cid)
1283
+	assert.Check(t, is.Len(ctrInsp.NetworkSettings.Networks, 2))
1284
+	assert.Check(t, is.Contains(ctrInsp.NetworkSettings.Networks, intNet))
1285
+	assert.Check(t, is.Contains(ctrInsp.NetworkSettings.Networks, extNet))
1286
+	extNetInsp, err = c.NetworkInspect(ctx, extNet, client.NetworkInspectOptions{})
1287
+	assert.Check(t, err)
1288
+	assert.Check(t, is.Len(extNetInsp.Containers, 1))
1289
+	res = ctr.ExecT(ctx, t, c, cid, []string{"ip", "link", "show", "eth0"})
1290
+	assert.Check(t, is.Equal(res.ExitCode, 0), "container should have an eth0")
1291
+	res = ctr.ExecT(ctx, t, c, cid, []string{"ip", "link", "show", "eth1"})
1292
+	assert.Check(t, is.Equal(res.ExitCode, 0), "container should have an eth1")
1293
+}