integration: HA cable-pull lifecycle test

Add DisconnectFromNetwork/ReconnectToNetwork on TailscaleClient
backed by pool.Client.DisconnectNetwork.

Exercise single-router fail+recover either side, sequential dual
failure, and simultaneous dual failure. The dual-failure legs
assert no flap to a known-bad primary; the single-router-return
legs check traffic only because docker network disconnect
transiently fails probes on sibling routers.

Fails on parent; passes after the fix.

Updates #3203
This commit is contained in:
Kristoffer Dalby
2026-04-29 12:25:40 +00:00
parent 863fa2f815
commit 7bb86f2c16
4 changed files with 310 additions and 0 deletions
+15
View File
@@ -807,6 +807,21 @@ func (t *TailscaleInContainer) Down() error {
return nil
}
// DisconnectFromNetwork detaches the container from network at the
// docker daemon level. The container's network interface for that
// network disappears and any in-flight TCP connection is left
// half-open at the peer — the same failure mode a real cable pull
// produces, which iptables-based simulations cannot reproduce.
func (t *TailscaleInContainer) DisconnectFromNetwork(network *dockertest.Network) error {
return dockertestutil.DisconnectContainerFromNetwork(t.pool, network, t.hostname)
}
// ReconnectToNetwork is the inverse of DisconnectFromNetwork: it
// re-attaches the container to network so traffic can flow again.
func (t *TailscaleInContainer) ReconnectToNetwork(network *dockertest.Network) error {
return dockertestutil.ReconnectContainerToNetwork(t.pool, network, t.hostname)
}
// IPs returns the netip.Addr of the Tailscale instance.
func (t *TailscaleInContainer) IPs() ([]netip.Addr, error) {
if len(t.ips) != 0 {