integration: add ConnectToNetwork and peer relay ping support

Add ConnectToNetwork to TailscaleClient interface and
TailscaleInContainer, matching the existing pattern on
HeadscaleInContainer and DERPServerInContainer. This enables
dual-homing Tailscale containers to additional Docker networks
after creation.

Also accept "via relay" in the Ping helper's non-direct mode,
alongside "via DERP". Peer relay pings output "via peer-relay(...)"
which was previously rejected as errTailscalePingNotDERP.

Updates #2180
This commit is contained in:
Kristoffer Dalby
2026-03-23 08:22:41 +00:00
parent d6feadde88
commit abe1a3e768
2 changed files with 8 additions and 1 deletions

View File

@@ -10,6 +10,7 @@ import (
"github.com/juanfont/headscale/hscontrol/util" "github.com/juanfont/headscale/hscontrol/util"
"github.com/juanfont/headscale/integration/dockertestutil" "github.com/juanfont/headscale/integration/dockertestutil"
"github.com/juanfont/headscale/integration/tsic" "github.com/juanfont/headscale/integration/tsic"
"github.com/ory/dockertest/v3"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/net/netcheck" "tailscale.com/net/netcheck"
"tailscale.com/types/key" "tailscale.com/types/key"
@@ -56,6 +57,7 @@ type TailscaleClient interface {
MustID() types.NodeID MustID() types.NodeID
ReadFile(path string) ([]byte, error) ReadFile(path string) ([]byte, error)
PacketFilter() ([]filter.Match, error) PacketFilter() ([]filter.Match, error)
ConnectToNetwork(network *dockertest.Network) error
// FailingPeersAsString returns a formatted-ish multi-line-string of peers in the client // FailingPeersAsString returns a formatted-ish multi-line-string of peers in the client
// and a bool indicating if the clients online count and peer count is equal. // and a bool indicating if the clients online count and peer count is equal.

View File

@@ -1393,7 +1393,7 @@ func (t *TailscaleInContainer) Ping(hostnameOrIP string, opts ...PingOption) err
} }
if !args.direct { if !args.direct {
if strings.Contains(result, "via DERP") { if strings.Contains(result, "via DERP") || strings.Contains(result, "via relay") {
return nil return nil
} else { } else {
return errTailscalePingNotDERP return errTailscalePingNotDERP
@@ -1615,6 +1615,11 @@ func (t *TailscaleInContainer) GetNodePrivateKey() (*key.NodePrivate, error) {
return &p.Persist.PrivateNodeKey, nil return &p.Persist.PrivateNodeKey, nil
} }
// ConnectToNetwork connects the Tailscale container to an additional Docker network.
func (t *TailscaleInContainer) ConnectToNetwork(network *dockertest.Network) error {
return t.container.ConnectToNetwork(network)
}
// PacketFilter returns the current packet filter rules from the client's network map. // PacketFilter returns the current packet filter rules from the client's network map.
// This is useful for verifying that policy changes have propagated to the client. // This is useful for verifying that policy changes have propagated to the client.
func (t *TailscaleInContainer) PacketFilter() ([]filter.Match, error) { func (t *TailscaleInContainer) PacketFilter() ([]filter.Match, error) {