mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
Merge pull request #49823 from robmry/integration_test_bridge_addrs
Reset default bridge addresses after integration tests
This commit is contained in:
@@ -18,7 +18,7 @@ func TestDaemonDNSFallback(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon, "cannot start daemon on remote test run")
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
skip.If(t, testEnv.IsUserNamespace)
|
||||
ctx := testutil.StartSpan(baseContext, t)
|
||||
ctx := setupTest(t)
|
||||
|
||||
d := daemon.New(t)
|
||||
d.StartWithBusybox(ctx, t, "-b", "none", "--dns", "127.127.127.1", "--dns", "8.8.8.8")
|
||||
|
||||
@@ -36,7 +36,7 @@ func TestDaemonRestartWithLiveRestore(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
|
||||
skip.If(t, testEnv.IsRemoteDaemon)
|
||||
skip.If(t, testEnv.IsRootless, "rootless mode has different view of network")
|
||||
ctx := testutil.StartSpan(baseContext, t)
|
||||
ctx := setupTest(t)
|
||||
|
||||
d := daemon.New(t)
|
||||
defer d.Stop(t)
|
||||
@@ -67,7 +67,7 @@ func TestDaemonDefaultNetworkPools(t *testing.T) {
|
||||
// Remove docker0 bridge and the start daemon defining the predefined address pools
|
||||
skip.If(t, testEnv.IsRemoteDaemon)
|
||||
skip.If(t, testEnv.IsRootless, "rootless mode has different view of network")
|
||||
ctx := testutil.StartSpan(baseContext, t)
|
||||
ctx := setupTest(t)
|
||||
|
||||
defaultNetworkBridge := "docker0"
|
||||
delInterface(ctx, t, defaultNetworkBridge)
|
||||
@@ -112,7 +112,7 @@ func TestDaemonRestartWithExistingNetwork(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
|
||||
skip.If(t, testEnv.IsRemoteDaemon)
|
||||
skip.If(t, testEnv.IsRootless, "rootless mode has different view of network")
|
||||
ctx := testutil.StartSpan(baseContext, t)
|
||||
ctx := setupTest(t)
|
||||
|
||||
d := daemon.New(t)
|
||||
d.Start(t)
|
||||
@@ -148,7 +148,7 @@ func TestDaemonRestartWithExistingNetworkWithDefaultPoolRange(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon)
|
||||
skip.If(t, testEnv.IsRootless, "rootless mode has different view of network")
|
||||
|
||||
ctx := testutil.StartSpan(baseContext, t)
|
||||
ctx := setupTest(t)
|
||||
|
||||
d := daemon.New(t)
|
||||
d.Start(t)
|
||||
@@ -203,7 +203,7 @@ func TestDaemonWithBipAndDefaultNetworkPool(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon)
|
||||
skip.If(t, testEnv.IsRootless, "rootless mode has different view of network")
|
||||
|
||||
ctx := testutil.StartSpan(baseContext, t)
|
||||
ctx := setupTest(t)
|
||||
|
||||
d := daemon.New(t)
|
||||
defer d.Stop(t)
|
||||
|
||||
@@ -625,7 +625,7 @@ func TestDefaultBridgeIPv6(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "IPv6 ULA",
|
||||
fixed_cidr_v6: "fd00:1234::/64",
|
||||
fixed_cidr_v6: "fd00:1235::/64",
|
||||
},
|
||||
{
|
||||
name: "IPv6 LLA only",
|
||||
@@ -633,7 +633,7 @@ func TestDefaultBridgeIPv6(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "IPv6 nonstandard LLA only",
|
||||
fixed_cidr_v6: "fe80:1234::/64",
|
||||
fixed_cidr_v6: "fe80:1236::/64",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -731,16 +731,16 @@ func TestDefaultBridgeAddresses(t *testing.T) {
|
||||
// Modify that prefix, the default bridge's address must be deleted and re-added.
|
||||
// The bridge must still have an address in the required (standard) LL subnet.
|
||||
stepName: "Nonstandard LL prefix - address change",
|
||||
fixedCIDRV6: "fe80:1234::/32",
|
||||
expAddrs: []string{"fe80:1234::1/32", "fe80::"},
|
||||
fixedCIDRV6: "fe80:1237::/32",
|
||||
expAddrs: []string{"fe80:1237::1/32", "fe80::"},
|
||||
},
|
||||
{
|
||||
// Modify the prefix length, the addresses should not change.
|
||||
stepName: "Modify LL prefix - no address change",
|
||||
fixedCIDRV6: "fe80:1234::/64",
|
||||
fixedCIDRV6: "fe80:1238::/64",
|
||||
// The prefix length displayed by 'ip a' is not updated - it's informational, and
|
||||
// can't be changed without unnecessarily deleting and re-adding the address.
|
||||
expAddrs: []string{"fe80:1234::1/", "fe80::"},
|
||||
expAddrs: []string{"fe80:1238::1/", "fe80::"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1500,7 +1500,7 @@ func TestAdvertiseAddresses(t *testing.T) {
|
||||
network.WithIPAM("172.22.22.0/24", "172.22.22.1"),
|
||||
}, tc.netOpts...)
|
||||
if tc.ipv6LinkLocal {
|
||||
netOpts = append(netOpts, network.WithIPAM("fe80:1234::/64", "fe80:1234::1"))
|
||||
netOpts = append(netOpts, network.WithIPAM("fe80:1240::/64", "fe80:1240::1"))
|
||||
} else {
|
||||
netOpts = append(netOpts, network.WithIPAM("fd3c:e70a:962c::/64", "fd3c:e70a:962c::1"))
|
||||
}
|
||||
@@ -1523,7 +1523,7 @@ func TestAdvertiseAddresses(t *testing.T) {
|
||||
const ctr2Addr4 = "172.22.22.22"
|
||||
ctr2Addr6 := "fd3c:e70a:962c::2222"
|
||||
if tc.ipv6LinkLocal {
|
||||
ctr2Addr6 = "fe80:1234::2222"
|
||||
ctr2Addr6 = "fe80:1240::2222"
|
||||
}
|
||||
ctr2Id := container.Run(ctx, t, c,
|
||||
container.WithName(ctr2Name),
|
||||
|
||||
@@ -39,6 +39,7 @@ func (e *Execution) Clean(ctx context.Context, t testing.TB) {
|
||||
deleteAllNetworks(ctx, t, apiClient, platform, e.protectedElements.networks)
|
||||
if platform == "linux" {
|
||||
deleteAllPlugins(ctx, t, apiClient, e.protectedElements.plugins)
|
||||
restoreDefaultBridge(t, e.protectedElements.defaultBridgeInfo)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,11 +25,12 @@ var frozenImages = []string{
|
||||
}
|
||||
|
||||
type protectedElements struct {
|
||||
containers map[string]struct{}
|
||||
images map[string]struct{}
|
||||
networks map[string]struct{}
|
||||
plugins map[string]struct{}
|
||||
volumes map[string]struct{}
|
||||
containers map[string]struct{}
|
||||
defaultBridgeInfo *defaultBridgeInfo
|
||||
images map[string]struct{}
|
||||
networks map[string]struct{}
|
||||
plugins map[string]struct{}
|
||||
volumes map[string]struct{}
|
||||
}
|
||||
|
||||
func newProtectedElements() protectedElements {
|
||||
@@ -57,6 +58,7 @@ func ProtectAll(ctx context.Context, t testing.TB, testEnv *Execution) {
|
||||
ProtectNetworks(ctx, t, testEnv)
|
||||
ProtectVolumes(ctx, t, testEnv)
|
||||
if testEnv.DaemonInfo.OSType == "linux" {
|
||||
ProtectDefaultBridge(ctx, t, testEnv)
|
||||
ProtectPlugins(ctx, t, testEnv)
|
||||
}
|
||||
}
|
||||
|
||||
106
testutil/environment/protect_linux.go
Normal file
106
testutil/environment/protect_linux.go
Normal file
@@ -0,0 +1,106 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.22
|
||||
|
||||
package environment
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"maps"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/nlwrap"
|
||||
"github.com/docker/docker/libnetwork/drivers/bridge"
|
||||
"github.com/vishvananda/netlink"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
type defaultBridgeInfo struct {
|
||||
bridge netlink.Link
|
||||
addrs map[string]*netlink.Addr
|
||||
}
|
||||
|
||||
var _, llSubnet, _ = net.ParseCIDR("fe80::/64")
|
||||
|
||||
// ProtectDefaultBridge remembers default bridge settings so that, when a test
|
||||
// runs its own daemon and tramples settings of the bridge belonging to the
|
||||
// CI-started bridge, the bridge is restored to its old state before the next
|
||||
// test.
|
||||
//
|
||||
// For example, a test may enable IPv6 with a link-local fixed-cidr-v6. That's
|
||||
// likely to break later tests, even if they also start their own daemon
|
||||
// (because, in the absence of any specific settings, the daemon learns default
|
||||
// bridge config from addresses on an existing bridge device).
|
||||
func ProtectDefaultBridge(_ context.Context, t testing.TB, testEnv *Execution) {
|
||||
t.Helper()
|
||||
// Find the bridge - there should always be one, belonging to the daemon started by CI.
|
||||
br, err := nlwrap.LinkByName(bridge.DefaultBridgeName)
|
||||
if err != nil {
|
||||
var lnf netlink.LinkNotFoundError
|
||||
if !errors.As(err, &lnf) {
|
||||
t.Fatal("Getting default bridge before test:", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
testEnv.ProtectDefaultBridge(t, &defaultBridgeInfo{
|
||||
bridge: br,
|
||||
addrs: getAddrs(t, br),
|
||||
})
|
||||
}
|
||||
|
||||
func getAddrs(t testing.TB, br netlink.Link) map[string]*netlink.Addr {
|
||||
t.Helper()
|
||||
addrs, err := nlwrap.AddrList(br, netlink.FAMILY_ALL)
|
||||
assert.NilError(t, err, "Getting default bridge addresses before test")
|
||||
addrMap := map[string]*netlink.Addr{}
|
||||
for _, addr := range addrs {
|
||||
addrMap[addr.IPNet.String()] = &addr
|
||||
}
|
||||
return addrMap
|
||||
}
|
||||
|
||||
// ProtectDefaultBridge stores default bridge info, to be restored on clean.
|
||||
func (e *Execution) ProtectDefaultBridge(t testing.TB, info *defaultBridgeInfo) {
|
||||
e.protectedElements.defaultBridgeInfo = info
|
||||
}
|
||||
|
||||
func restoreDefaultBridge(t testing.TB, info *defaultBridgeInfo) {
|
||||
t.Helper()
|
||||
if info == nil {
|
||||
return
|
||||
}
|
||||
// Re-create the bridge if the test was antisocial enough to delete it.
|
||||
// Yes, I'm looking at you TestDockerDaemonSuite/TestBuildOnDisabledBridgeNetworkDaemon.
|
||||
br, err := nlwrap.LinkByName(bridge.DefaultBridgeName)
|
||||
if err != nil {
|
||||
var lnf netlink.LinkNotFoundError
|
||||
if !errors.As(err, &lnf) {
|
||||
t.Fatal("Failed to find default bridge after test:", err)
|
||||
}
|
||||
err := netlink.LinkAdd(info.bridge)
|
||||
assert.NilError(t, err, "Failed to re-create default bridge after test")
|
||||
br, err = nlwrap.LinkByName(bridge.DefaultBridgeName)
|
||||
assert.NilError(t, err, "Failed to find re-created default bridge after test")
|
||||
}
|
||||
addrs, err := nlwrap.AddrList(br, netlink.FAMILY_ALL)
|
||||
assert.NilError(t, err, "Failed get default bridge addresses after test")
|
||||
// Delete addresses the bridge didn't have before the test, apart from IPv6 LL
|
||||
// addresses - because the bridge doesn't get a kernel-assigned LL address until
|
||||
// the first veth is hooked up and, once that address is deleted, it's not
|
||||
// re-added.
|
||||
wantAddrs := maps.Clone(info.addrs)
|
||||
for _, addr := range addrs {
|
||||
if _, ok := wantAddrs[addr.IPNet.String()]; ok {
|
||||
delete(wantAddrs, addr.IPNet.String())
|
||||
} else if !llSubnet.Contains(addr.IP) {
|
||||
err := netlink.AddrDel(br, &netlink.Addr{IPNet: addr.IPNet})
|
||||
assert.NilError(t, err, "Failed to remove default bridge address '%s' after test", addr.IPNet.String())
|
||||
}
|
||||
}
|
||||
// Add missing addresses.
|
||||
for _, wantAddr := range wantAddrs {
|
||||
err = netlink.AddrAdd(br, wantAddr)
|
||||
assert.NilError(t, err, "Failed to add default bridge address '%s' after test", wantAddr.IPNet.String())
|
||||
}
|
||||
}
|
||||
16
testutil/environment/protect_others.go
Normal file
16
testutil/environment/protect_others.go
Normal file
@@ -0,0 +1,16 @@
|
||||
//go:build !linux
|
||||
|
||||
package environment
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type defaultBridgeInfo struct{}
|
||||
|
||||
func ProtectDefaultBridge(context.Context, testing.TB, *Execution) {
|
||||
return
|
||||
}
|
||||
|
||||
func restoreDefaultBridge(testing.TB, *defaultBridgeInfo) {}
|
||||
Reference in New Issue
Block a user