package bridge
import (
"errors"
"testing"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/daemon/libnetwork/drivers/bridge"
"github.com/moby/moby/v2/daemon/libnetwork/nlwrap"
"github.com/moby/moby/v2/integration/internal/network"
"github.com/moby/moby/v2/internal/testutil/daemon"
"github.com/vishvananda/netlink"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
// TestNetworkInitError checks that, if the default bridge network can't be restored on startup,
// it doesn't prevent the daemon from starting once the underlying problem is resolved.
// Regression test for https://github.com/moby/moby/issues/49291
func TestNetworkInitErrorDocker0(t *testing.T) {
d := daemon.New(t)
d.Start(t)
defer func() {
_ = d.StopWithError()
}()
const brName = "docker0"
d.SetEnvVar("DOCKER_TEST_BRIDGE_INIT_ERROR", brName)
err := d.RestartWithError()
assert.Assert(t, is.ErrorContains(err, "daemon exited during startup"))
d.SetEnvVar("DOCKER_TEST_BRIDGE_INIT_ERROR", "")
d.Start(t)
}
// TestNetworkInitErrorUserDefined is equivalent to TestNetworkInitErrorDocker0, for a
// user-defined network. But, the daemon doesn't try to delete a user-defined network
// and the daemon will still start if it can't be restored on startup. So, try to
// delete the network when it's failed to initialise, and check that it can be
// re-created when the initialisation problem has been resolved.
func TestNetworkInitErrorUserDefined(t *testing.T) {
ctx := setupTest(t)
d := daemon.New(t)
d.Start(t)
defer func() {
_ = d.StopWithError()
}()
c := d.NewClientT(t)
defer c.Close()
const netName = "testnet"
const brName = "br-" + netName
network.CreateNoError(ctx, t, c, netName,
network.WithOption(bridge.BridgeName, brName),
)
defer network.RemoveNoError(ctx, t, c, netName)
d.SetEnvVar("DOCKER_TEST_BRIDGE_INIT_ERROR", brName)
d.Restart(t)
_, err := c.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.NilError(t, err)
d.SetEnvVar("DOCKER_TEST_BRIDGE_INIT_ERROR", "")
d.Restart(t)
network.CreateNoError(ctx, t, c, netName,
network.WithOption(bridge.BridgeName, brName),
)
}
// TestNetworkCreateErrorNoBridge checks that no bridge device gets left around
// when there's an error during network creation.
func TestNetworkCreateErrorNoBridge(t *testing.T) {
ctx := setupTest(t)
d := daemon.New(t)
const netName = "testnet"
const brName = "br-" + netName
d.SetEnvVar("DOCKER_TEST_BRIDGE_INIT_ERROR", brName)
d.Start(t)
defer d.Stop(t)
c := d.NewClientT(t)
defer c.Close()
_, err := network.Create(ctx, c, netName, network.WithOption(bridge.BridgeName, brName))
if err == nil {
defer network.RemoveNoError(ctx, t, c, brName)
t.Fatalf("expected an error creating the network")
}
assert.Check(t, is.ErrorContains(err, "DOCKER_TEST_BRIDGE_INIT_ERROR"))
// Check there's no bridge device.
_, err = nlwrap.LinkByName(brName)
assert.Check(t, errors.As(err, &netlink.LinkNotFoundError{}), "expected LinkNotFoundError, got: %v", err)
}