Skip to content

Commit 59920a7

Browse files
authored
Merge pull request moby#49823 from robmry/integration_test_bridge_addrs
Reset default bridge addresses after integration tests
2 parents 0451e4f + 6083fad commit 59920a7

File tree

7 files changed

+144
-19
lines changed

7 files changed

+144
-19
lines changed

integration/network/dns_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func TestDaemonDNSFallback(t *testing.T) {
1818
skip.If(t, testEnv.IsRemoteDaemon, "cannot start daemon on remote test run")
1919
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
2020
skip.If(t, testEnv.IsUserNamespace)
21-
ctx := testutil.StartSpan(baseContext, t)
21+
ctx := setupTest(t)
2222

2323
d := daemon.New(t)
2424
d.StartWithBusybox(ctx, t, "-b", "none", "--dns", "127.127.127.1", "--dns", "8.8.8.8")

integration/network/service_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func TestDaemonRestartWithLiveRestore(t *testing.T) {
3636
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
3737
skip.If(t, testEnv.IsRemoteDaemon)
3838
skip.If(t, testEnv.IsRootless, "rootless mode has different view of network")
39-
ctx := testutil.StartSpan(baseContext, t)
39+
ctx := setupTest(t)
4040

4141
d := daemon.New(t)
4242
defer d.Stop(t)
@@ -67,7 +67,7 @@ func TestDaemonDefaultNetworkPools(t *testing.T) {
6767
// Remove docker0 bridge and the start daemon defining the predefined address pools
6868
skip.If(t, testEnv.IsRemoteDaemon)
6969
skip.If(t, testEnv.IsRootless, "rootless mode has different view of network")
70-
ctx := testutil.StartSpan(baseContext, t)
70+
ctx := setupTest(t)
7171

7272
defaultNetworkBridge := "docker0"
7373
delInterface(ctx, t, defaultNetworkBridge)
@@ -112,7 +112,7 @@ func TestDaemonRestartWithExistingNetwork(t *testing.T) {
112112
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
113113
skip.If(t, testEnv.IsRemoteDaemon)
114114
skip.If(t, testEnv.IsRootless, "rootless mode has different view of network")
115-
ctx := testutil.StartSpan(baseContext, t)
115+
ctx := setupTest(t)
116116

117117
d := daemon.New(t)
118118
d.Start(t)
@@ -148,7 +148,7 @@ func TestDaemonRestartWithExistingNetworkWithDefaultPoolRange(t *testing.T) {
148148
skip.If(t, testEnv.IsRemoteDaemon)
149149
skip.If(t, testEnv.IsRootless, "rootless mode has different view of network")
150150

151-
ctx := testutil.StartSpan(baseContext, t)
151+
ctx := setupTest(t)
152152

153153
d := daemon.New(t)
154154
d.Start(t)
@@ -203,7 +203,7 @@ func TestDaemonWithBipAndDefaultNetworkPool(t *testing.T) {
203203
skip.If(t, testEnv.IsRemoteDaemon)
204204
skip.If(t, testEnv.IsRootless, "rootless mode has different view of network")
205205

206-
ctx := testutil.StartSpan(baseContext, t)
206+
ctx := setupTest(t)
207207

208208
d := daemon.New(t)
209209
defer d.Stop(t)

integration/networking/bridge_linux_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -625,15 +625,15 @@ func TestDefaultBridgeIPv6(t *testing.T) {
625625
},
626626
{
627627
name: "IPv6 ULA",
628-
fixed_cidr_v6: "fd00:1234::/64",
628+
fixed_cidr_v6: "fd00:1235::/64",
629629
},
630630
{
631631
name: "IPv6 LLA only",
632632
fixed_cidr_v6: "fe80::/64",
633633
},
634634
{
635635
name: "IPv6 nonstandard LLA only",
636-
fixed_cidr_v6: "fe80:1234::/64",
636+
fixed_cidr_v6: "fe80:1236::/64",
637637
},
638638
}
639639

@@ -731,16 +731,16 @@ func TestDefaultBridgeAddresses(t *testing.T) {
731731
// Modify that prefix, the default bridge's address must be deleted and re-added.
732732
// The bridge must still have an address in the required (standard) LL subnet.
733733
stepName: "Nonstandard LL prefix - address change",
734-
fixedCIDRV6: "fe80:1234::/32",
735-
expAddrs: []string{"fe80:1234::1/32", "fe80::"},
734+
fixedCIDRV6: "fe80:1237::/32",
735+
expAddrs: []string{"fe80:1237::1/32", "fe80::"},
736736
},
737737
{
738738
// Modify the prefix length, the addresses should not change.
739739
stepName: "Modify LL prefix - no address change",
740-
fixedCIDRV6: "fe80:1234::/64",
740+
fixedCIDRV6: "fe80:1238::/64",
741741
// The prefix length displayed by 'ip a' is not updated - it's informational, and
742742
// can't be changed without unnecessarily deleting and re-adding the address.
743-
expAddrs: []string{"fe80:1234::1/", "fe80::"},
743+
expAddrs: []string{"fe80:1238::1/", "fe80::"},
744744
},
745745
},
746746
},
@@ -1500,7 +1500,7 @@ func TestAdvertiseAddresses(t *testing.T) {
15001500
network.WithIPAM("172.22.22.0/24", "172.22.22.1"),
15011501
}, tc.netOpts...)
15021502
if tc.ipv6LinkLocal {
1503-
netOpts = append(netOpts, network.WithIPAM("fe80:1234::/64", "fe80:1234::1"))
1503+
netOpts = append(netOpts, network.WithIPAM("fe80:1240::/64", "fe80:1240::1"))
15041504
} else {
15051505
netOpts = append(netOpts, network.WithIPAM("fd3c:e70a:962c::/64", "fd3c:e70a:962c::1"))
15061506
}
@@ -1523,7 +1523,7 @@ func TestAdvertiseAddresses(t *testing.T) {
15231523
const ctr2Addr4 = "172.22.22.22"
15241524
ctr2Addr6 := "fd3c:e70a:962c::2222"
15251525
if tc.ipv6LinkLocal {
1526-
ctr2Addr6 = "fe80:1234::2222"
1526+
ctr2Addr6 = "fe80:1240::2222"
15271527
}
15281528
ctr2Id := container.Run(ctx, t, c,
15291529
container.WithName(ctr2Name),

testutil/environment/clean.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func (e *Execution) Clean(ctx context.Context, t testing.TB) {
3939
deleteAllNetworks(ctx, t, apiClient, platform, e.protectedElements.networks)
4040
if platform == "linux" {
4141
deleteAllPlugins(ctx, t, apiClient, e.protectedElements.plugins)
42+
restoreDefaultBridge(t, e.protectedElements.defaultBridgeInfo)
4243
}
4344
}
4445

testutil/environment/protect.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ var frozenImages = []string{
2525
}
2626

2727
type protectedElements struct {
28-
containers map[string]struct{}
29-
images map[string]struct{}
30-
networks map[string]struct{}
31-
plugins map[string]struct{}
32-
volumes map[string]struct{}
28+
containers map[string]struct{}
29+
defaultBridgeInfo *defaultBridgeInfo
30+
images map[string]struct{}
31+
networks map[string]struct{}
32+
plugins map[string]struct{}
33+
volumes map[string]struct{}
3334
}
3435

3536
func newProtectedElements() protectedElements {
@@ -57,6 +58,7 @@ func ProtectAll(ctx context.Context, t testing.TB, testEnv *Execution) {
5758
ProtectNetworks(ctx, t, testEnv)
5859
ProtectVolumes(ctx, t, testEnv)
5960
if testEnv.DaemonInfo.OSType == "linux" {
61+
ProtectDefaultBridge(ctx, t, testEnv)
6062
ProtectPlugins(ctx, t, testEnv)
6163
}
6264
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
2+
//go:build go1.22
3+
4+
package environment
5+
6+
import (
7+
"context"
8+
"errors"
9+
"maps"
10+
"net"
11+
"testing"
12+
13+
"github.com/docker/docker/internal/nlwrap"
14+
"github.com/docker/docker/libnetwork/drivers/bridge"
15+
"github.com/vishvananda/netlink"
16+
"gotest.tools/v3/assert"
17+
)
18+
19+
type defaultBridgeInfo struct {
20+
bridge netlink.Link
21+
addrs map[string]*netlink.Addr
22+
}
23+
24+
var _, llSubnet, _ = net.ParseCIDR("fe80::/64")
25+
26+
// ProtectDefaultBridge remembers default bridge settings so that, when a test
27+
// runs its own daemon and tramples settings of the bridge belonging to the
28+
// CI-started bridge, the bridge is restored to its old state before the next
29+
// test.
30+
//
31+
// For example, a test may enable IPv6 with a link-local fixed-cidr-v6. That's
32+
// likely to break later tests, even if they also start their own daemon
33+
// (because, in the absence of any specific settings, the daemon learns default
34+
// bridge config from addresses on an existing bridge device).
35+
func ProtectDefaultBridge(_ context.Context, t testing.TB, testEnv *Execution) {
36+
t.Helper()
37+
// Find the bridge - there should always be one, belonging to the daemon started by CI.
38+
br, err := nlwrap.LinkByName(bridge.DefaultBridgeName)
39+
if err != nil {
40+
var lnf netlink.LinkNotFoundError
41+
if !errors.As(err, &lnf) {
42+
t.Fatal("Getting default bridge before test:", err)
43+
}
44+
return
45+
}
46+
testEnv.ProtectDefaultBridge(t, &defaultBridgeInfo{
47+
bridge: br,
48+
addrs: getAddrs(t, br),
49+
})
50+
}
51+
52+
func getAddrs(t testing.TB, br netlink.Link) map[string]*netlink.Addr {
53+
t.Helper()
54+
addrs, err := nlwrap.AddrList(br, netlink.FAMILY_ALL)
55+
assert.NilError(t, err, "Getting default bridge addresses before test")
56+
addrMap := map[string]*netlink.Addr{}
57+
for _, addr := range addrs {
58+
addrMap[addr.IPNet.String()] = &addr
59+
}
60+
return addrMap
61+
}
62+
63+
// ProtectDefaultBridge stores default bridge info, to be restored on clean.
64+
func (e *Execution) ProtectDefaultBridge(t testing.TB, info *defaultBridgeInfo) {
65+
e.protectedElements.defaultBridgeInfo = info
66+
}
67+
68+
func restoreDefaultBridge(t testing.TB, info *defaultBridgeInfo) {
69+
t.Helper()
70+
if info == nil {
71+
return
72+
}
73+
// Re-create the bridge if the test was antisocial enough to delete it.
74+
// Yes, I'm looking at you TestDockerDaemonSuite/TestBuildOnDisabledBridgeNetworkDaemon.
75+
br, err := nlwrap.LinkByName(bridge.DefaultBridgeName)
76+
if err != nil {
77+
var lnf netlink.LinkNotFoundError
78+
if !errors.As(err, &lnf) {
79+
t.Fatal("Failed to find default bridge after test:", err)
80+
}
81+
err := netlink.LinkAdd(info.bridge)
82+
assert.NilError(t, err, "Failed to re-create default bridge after test")
83+
br, err = nlwrap.LinkByName(bridge.DefaultBridgeName)
84+
assert.NilError(t, err, "Failed to find re-created default bridge after test")
85+
}
86+
addrs, err := nlwrap.AddrList(br, netlink.FAMILY_ALL)
87+
assert.NilError(t, err, "Failed get default bridge addresses after test")
88+
// Delete addresses the bridge didn't have before the test, apart from IPv6 LL
89+
// addresses - because the bridge doesn't get a kernel-assigned LL address until
90+
// the first veth is hooked up and, once that address is deleted, it's not
91+
// re-added.
92+
wantAddrs := maps.Clone(info.addrs)
93+
for _, addr := range addrs {
94+
if _, ok := wantAddrs[addr.IPNet.String()]; ok {
95+
delete(wantAddrs, addr.IPNet.String())
96+
} else if !llSubnet.Contains(addr.IP) {
97+
err := netlink.AddrDel(br, &netlink.Addr{IPNet: addr.IPNet})
98+
assert.NilError(t, err, "Failed to remove default bridge address '%s' after test", addr.IPNet.String())
99+
}
100+
}
101+
// Add missing addresses.
102+
for _, wantAddr := range wantAddrs {
103+
err = netlink.AddrAdd(br, wantAddr)
104+
assert.NilError(t, err, "Failed to add default bridge address '%s' after test", wantAddr.IPNet.String())
105+
}
106+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//go:build !linux
2+
3+
package environment
4+
5+
import (
6+
"context"
7+
"testing"
8+
)
9+
10+
type defaultBridgeInfo struct{}
11+
12+
func ProtectDefaultBridge(context.Context, testing.TB, *Execution) {
13+
return
14+
}
15+
16+
func restoreDefaultBridge(testing.TB, *defaultBridgeInfo) {}

0 commit comments

Comments
 (0)