mirror of
https://github.com/juanfont/headscale.git
synced 2026-10-24 07:16:49 +09:00
integration: reproduce HA primary flap to offline node via docker disconnect
Add a docker-network-disconnect primitive — `DisconnectFromNetwork` / `ReconnectToNetwork` on `TailscaleClient`, backed by `pool.Client.DisconnectNetwork` — so an integration test can faithfully simulate the cable-pull scenario the issue reporter observed in Proxmox. Iptables-based simulations leave the socket open at the container kernel and miss the bug. Use it in `TestHASubnetRouterFailoverDockerDisconnect` to assert the no-flap invariant: once primary has failed over from r1 to r2 and r2 also loses connectivity, primary must not switch back to the still-offline r1. The assertion fails on the current branch — the all-unhealthy fallback in `electPrimaryRoutes` flips primary to the lowest-NodeID candidate regardless of online state. Locking the failure in via TDD before designing the fix. Updates #3203
This commit is contained in:
1 parent
2d04fff605
commit
5228818a12
4 files changed
+250
No files matched your search
@@ -91,6 +91,47 @@ func AddContainerToNetwork(
|
||||
return nil
|
||||
}
|
||||
|
||||
// DisconnectContainerFromNetwork removes the container from network at
|
||||
// the docker daemon level. Mirrors a physical cable pull: the
|
||||
// container's network interface for that network disappears and any
|
||||
// in-flight TCP connections are left half-open, exactly the failure
|
||||
// mode iptables-based simulations cannot reproduce.
|
||||
func DisconnectContainerFromNetwork(
|
||||
pool *dockertest.Pool,
|
||||
network *dockertest.Network,
|
||||
testContainer string,
|
||||
) error {
|
||||
containers, err := pool.Client.ListContainers(docker.ListContainersOptions{
|
||||
All: true,
|
||||
Filters: map[string][]string{
|
||||
"name": {testContainer},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(containers) == 0 {
|
||||
return fmt.Errorf("%w: %s", ErrContainerNotFound, testContainer)
|
||||
}
|
||||
|
||||
return pool.Client.DisconnectNetwork(network.Network.ID, docker.NetworkConnectionOptions{
|
||||
Container: containers[0].ID,
|
||||
Force: true,
|
||||
})
|
||||
}
|
||||
|
||||
// ReconnectContainerToNetwork is the inverse of
|
||||
// DisconnectContainerFromNetwork — re-attaches the container to the
|
||||
// network so traffic can flow again.
|
||||
func ReconnectContainerToNetwork(
|
||||
pool *dockertest.Pool,
|
||||
network *dockertest.Network,
|
||||
testContainer string,
|
||||
) error {
|
||||
return AddContainerToNetwork(pool, network, testContainer)
|
||||
}
|
||||
|
||||
// RandomFreeHostPort asks the kernel for a free open port that is ready to use.
|
||||
// (from https://github.com/phayes/freeport)
|
||||
func RandomFreeHostPort() (int, error) {
|
||||
|
||||
Reference in new issue
Block a user