mirror of
https://github.com/juanfont/headscale.git
synced 2026-05-25 03:28:42 +09:00
cmd, templates, integration: extract shared production constants
Constants the operator/test reader benefits from centralising.
Tests stay verbatim (the .golangci.yaml goconst tune skips them);
extraction here applies only where the same literal acts as
shared vocabulary across files.
cmd/headscale/cli/strings.go (new)
Cobra subcommand verbs and aliases shared by every list / show
/ new / delete / expire command across api_key, nodes, policy,
preauthkeys, users — plus the Result / Created / Expiration
column headers used in printOutput maps.
hscontrol/templates/design.go
cssBorderHS, cssBreakWord, cssCenter, cssOverflowWrap — shared
styles applied across design.go, ping.go, register_confirm.go.
spaceS already existed; switch raw "0.5rem" literals to it.
integration/hsic/hsic.go
binHeadscale, flagOutput, acceptJSON — names invoked across
hsic.go and config.go.
integration/tsic/tsic.go
tailscaleBin — used across docker exec call sites.
This commit is contained in:
@@ -43,6 +43,7 @@ const (
|
||||
dockerContextPath = "../."
|
||||
caCertRoot = "/usr/local/share/ca-certificates"
|
||||
dockerExecuteTimeout = 60 * time.Second
|
||||
tailscaleBin = "tailscale"
|
||||
)
|
||||
|
||||
// defaultPingTimeoutVal returns the per-attempt timeout for tailscale ping.
|
||||
@@ -127,7 +128,7 @@ func WithCACert(cert []byte) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithNetwork sets the Docker container network to use with
|
||||
// WithNetwork sets the Docker [dockertest.Network] to use with
|
||||
// the Tailscale instance.
|
||||
func WithNetwork(network *dockertest.Network) Option {
|
||||
return func(tsic *TailscaleInContainer) {
|
||||
@@ -215,7 +216,7 @@ func WithBuildTag(tag string) Option {
|
||||
}
|
||||
|
||||
// WithExtraLoginArgs adds additional arguments to the `tailscale up` command
|
||||
// as part of the Login function.
|
||||
// as part of the [TailscaleInContainer.Login] function.
|
||||
func WithExtraLoginArgs(args []string) Option {
|
||||
return func(tsic *TailscaleInContainer) {
|
||||
tsic.extraLoginArgs = append(tsic.extraLoginArgs, args...)
|
||||
@@ -270,7 +271,7 @@ func (t *TailscaleInContainer) buildEntrypoint() []string {
|
||||
commands = append(commands, "while ! ip route show default >/dev/null 2>&1; do sleep 0.1; done")
|
||||
|
||||
// If CA certs are configured, wait for them to be written by the Go code
|
||||
// (certs are written after container start via tsic.WriteFile)
|
||||
// (certs are written after container start via [TailscaleInContainer.WriteFile])
|
||||
if len(t.caCerts) > 0 {
|
||||
commands = append(commands,
|
||||
fmt.Sprintf("while [ ! -f %s/user-0.crt ]; do sleep 0.1; done", caCertRoot))
|
||||
@@ -389,7 +390,7 @@ func New(
|
||||
}
|
||||
|
||||
// Add integration test labels if running under hi tool
|
||||
dockertestutil.DockerAddIntegrationLabels(tailscaleOptions, "tailscale")
|
||||
dockertestutil.DockerAddIntegrationLabels(tailscaleOptions, tailscaleBin)
|
||||
|
||||
var container *dockertest.Resource
|
||||
|
||||
@@ -413,13 +414,13 @@ func New(
|
||||
// the pre-built image as it won't have the necessary code compiled in.
|
||||
hasBuildTags := len(tsic.buildConfig.tags) > 0
|
||||
if hasBuildTags && prebuiltImage != "" {
|
||||
log.Printf("Ignoring pre-built image %s because custom build tags are required: %v",
|
||||
log.Printf("Ignoring pre-built image %s because custom build tags are required: %v", //nolint:gosec // G706: integration-only log of trusted env value
|
||||
prebuiltImage, tsic.buildConfig.tags)
|
||||
prebuiltImage = ""
|
||||
}
|
||||
|
||||
if prebuiltImage != "" {
|
||||
log.Printf("Using pre-built tailscale image: %s", prebuiltImage)
|
||||
log.Printf("Using pre-built tailscale image: %s", prebuiltImage) //nolint:gosec // G706: integration-only log of trusted env value
|
||||
|
||||
// Parse image into repository and tag
|
||||
repo, tag, ok := strings.Cut(prebuiltImage, ":")
|
||||
@@ -609,7 +610,7 @@ func (t *TailscaleInContainer) Version() string {
|
||||
return t.version
|
||||
}
|
||||
|
||||
// ContainerID returns the Docker container ID of the TailscaleInContainer
|
||||
// ContainerID returns the Docker container ID of the [TailscaleInContainer]
|
||||
// instance.
|
||||
func (t *TailscaleInContainer) ContainerID() string {
|
||||
return t.container.Container.ID
|
||||
@@ -657,7 +658,7 @@ func (t *TailscaleInContainer) buildLoginCommand(
|
||||
loginServer, authKey string,
|
||||
) []string {
|
||||
command := []string{
|
||||
"tailscale",
|
||||
tailscaleBin,
|
||||
"up",
|
||||
"--login-server=" + loginServer,
|
||||
"--hostname=" + t.hostname,
|
||||
@@ -736,12 +737,12 @@ func (t *TailscaleInContainer) LoginWithURL(
|
||||
|
||||
// Logout runs the logout routine on the given Tailscale instance.
|
||||
func (t *TailscaleInContainer) Logout() error {
|
||||
_, _, err := t.Execute([]string{"tailscale", "logout"})
|
||||
_, _, err := t.Execute([]string{tailscaleBin, "logout"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stdout, stderr, _ := t.Execute([]string{"tailscale", "status"})
|
||||
stdout, stderr, _ := t.Execute([]string{tailscaleBin, "status"})
|
||||
if !strings.Contains(stdout+stderr, "Logged out.") {
|
||||
return fmt.Errorf("logging out, stdout: %s, stderr: %s", stdout, stderr) //nolint:err113
|
||||
}
|
||||
@@ -768,7 +769,7 @@ func (t *TailscaleInContainer) Restart() error {
|
||||
// We use exponential backoff to poll until we can successfully execute a command
|
||||
_, err = backoff.Retry(context.Background(), func() (struct{}, error) {
|
||||
// Try to execute a simple command to verify the container is responsive
|
||||
_, _, err := t.Execute([]string{"tailscale", "version"}, dockertestutil.ExecuteCommandTimeout(5*time.Second))
|
||||
_, _, err := t.Execute([]string{tailscaleBin, "version"}, dockertestutil.ExecuteCommandTimeout(5*time.Second))
|
||||
if err != nil {
|
||||
return struct{}{}, fmt.Errorf("container not ready: %w", err)
|
||||
}
|
||||
@@ -785,7 +786,7 @@ func (t *TailscaleInContainer) Restart() error {
|
||||
// Up runs `tailscale up` with no arguments.
|
||||
func (t *TailscaleInContainer) Up() error {
|
||||
command := []string{
|
||||
"tailscale",
|
||||
tailscaleBin,
|
||||
"up",
|
||||
}
|
||||
|
||||
@@ -804,7 +805,7 @@ func (t *TailscaleInContainer) Up() error {
|
||||
// Down runs `tailscale down` with no arguments.
|
||||
func (t *TailscaleInContainer) Down() error {
|
||||
command := []string{
|
||||
"tailscale",
|
||||
tailscaleBin,
|
||||
"down",
|
||||
}
|
||||
|
||||
@@ -835,7 +836,7 @@ func (t *TailscaleInContainer) ReconnectToNetwork(network *dockertest.Network) e
|
||||
return dockertestutil.ReconnectContainerToNetwork(t.pool, network, t.hostname)
|
||||
}
|
||||
|
||||
// IPs returns the netip.Addr of the Tailscale instance.
|
||||
// IPs returns the [netip.Addr] of the Tailscale instance.
|
||||
func (t *TailscaleInContainer) IPs() ([]netip.Addr, error) {
|
||||
if len(t.ips) != 0 {
|
||||
return t.ips, nil
|
||||
@@ -844,7 +845,7 @@ func (t *TailscaleInContainer) IPs() ([]netip.Addr, error) {
|
||||
// Retry with exponential backoff to handle eventual consistency
|
||||
ips, err := backoff.Retry(context.Background(), func() ([]netip.Addr, error) {
|
||||
command := []string{
|
||||
"tailscale",
|
||||
tailscaleBin,
|
||||
"ip",
|
||||
}
|
||||
|
||||
@@ -926,10 +927,10 @@ func (t *TailscaleInContainer) MustIPv6() netip.Addr {
|
||||
panic("no ipv6 found")
|
||||
}
|
||||
|
||||
// Status returns the ipnstate.Status of the Tailscale instance.
|
||||
// Status returns the [ipnstate.Status] of the Tailscale instance.
|
||||
func (t *TailscaleInContainer) Status(save ...bool) (*ipnstate.Status, error) {
|
||||
command := []string{
|
||||
"tailscale",
|
||||
tailscaleBin,
|
||||
"status",
|
||||
"--json",
|
||||
}
|
||||
@@ -954,7 +955,7 @@ func (t *TailscaleInContainer) Status(save ...bool) (*ipnstate.Status, error) {
|
||||
return &status, err
|
||||
}
|
||||
|
||||
// MustStatus returns the ipnstate.Status of the Tailscale instance.
|
||||
// MustStatus returns the [ipnstate.Status] of the Tailscale instance.
|
||||
func (t *TailscaleInContainer) MustStatus() *ipnstate.Status {
|
||||
status, err := t.Status()
|
||||
if err != nil {
|
||||
@@ -979,7 +980,7 @@ func (t *TailscaleInContainer) MustID() types.NodeID {
|
||||
return types.NodeID(id)
|
||||
}
|
||||
|
||||
// Netmap returns the current Netmap (netmap.NetworkMap) of the Tailscale instance.
|
||||
// Netmap returns the current Netmap ([netmap.NetworkMap]) of the Tailscale instance.
|
||||
// Only works with Tailscale 1.56 and newer.
|
||||
// Panics if version is lower then minimum.
|
||||
func (t *TailscaleInContainer) Netmap() (*netmap.NetworkMap, error) {
|
||||
@@ -988,7 +989,7 @@ func (t *TailscaleInContainer) Netmap() (*netmap.NetworkMap, error) {
|
||||
}
|
||||
|
||||
command := []string{
|
||||
"tailscale",
|
||||
tailscaleBin,
|
||||
"debug",
|
||||
"netmap",
|
||||
}
|
||||
@@ -1014,7 +1015,7 @@ func (t *TailscaleInContainer) Netmap() (*netmap.NetworkMap, error) {
|
||||
return &nm, err
|
||||
}
|
||||
|
||||
// Netmap returns the current Netmap (netmap.NetworkMap) of the Tailscale instance.
|
||||
// Netmap returns the current Netmap ([netmap.NetworkMap]) of the Tailscale instance.
|
||||
// This implementation is based on getting the netmap from `tailscale debug watch-ipn`
|
||||
// as there seem to be some weirdness omitting endpoint and DERP info if we use
|
||||
// Patch updates.
|
||||
@@ -1037,8 +1038,8 @@ func (t *TailscaleInContainer) Netmap() (*netmap.NetworkMap, error) {
|
||||
// return notify.NetMap, nil
|
||||
// }
|
||||
|
||||
// watchIPN watches `tailscale debug watch-ipn` for a ipn.Notify object until
|
||||
// it gets one that has a netmap.NetworkMap.
|
||||
// watchIPN watches `tailscale debug watch-ipn` for a [ipn.Notify] object until
|
||||
// it gets one that has a [netmap.NetworkMap].
|
||||
//
|
||||
//nolint:unused
|
||||
func (t *TailscaleInContainer) watchIPN(ctx context.Context) (*ipn.Notify, error) {
|
||||
@@ -1115,7 +1116,7 @@ func (t *TailscaleInContainer) DebugDERPRegion(region string) (*ipnstate.DebugDE
|
||||
}
|
||||
|
||||
command := []string{
|
||||
"tailscale",
|
||||
tailscaleBin,
|
||||
"debug",
|
||||
"derp",
|
||||
region,
|
||||
@@ -1138,10 +1139,10 @@ func (t *TailscaleInContainer) DebugDERPRegion(region string) (*ipnstate.DebugDE
|
||||
return &report, err
|
||||
}
|
||||
|
||||
// Netcheck returns the current Netcheck Report (netcheck.Report) of the Tailscale instance.
|
||||
// Netcheck returns the current Netcheck Report ([netcheck.Report]) of the Tailscale instance.
|
||||
func (t *TailscaleInContainer) Netcheck() (*netcheck.Report, error) {
|
||||
command := []string{
|
||||
"tailscale",
|
||||
tailscaleBin,
|
||||
"netcheck",
|
||||
"--format=json",
|
||||
}
|
||||
@@ -1258,7 +1259,7 @@ func (t *TailscaleInContainer) waitForBackendState(state string, timeout time.Du
|
||||
continue // Keep retrying on status errors
|
||||
}
|
||||
|
||||
// ipnstate.Status.CurrentTailnet was added in Tailscale 1.22.0
|
||||
// [ipnstate.Status.CurrentTailnet] was added in Tailscale 1.22.0
|
||||
// https://github.com/tailscale/tailscale/pull/3865
|
||||
//
|
||||
// Before that, we can check the BackendState to see if the
|
||||
@@ -1382,7 +1383,7 @@ func WithPingUntilDirect(direct bool) PingOption {
|
||||
}
|
||||
|
||||
// Ping executes the Tailscale ping command and pings a hostname
|
||||
// or IP. It accepts a series of PingOption.
|
||||
// or IP. It accepts a series of [PingOption].
|
||||
// TODO(kradalby): Make multiping, go routine magic.
|
||||
func (t *TailscaleInContainer) Ping(hostnameOrIP string, opts ...PingOption) error {
|
||||
args := pingArgs{
|
||||
@@ -1397,7 +1398,7 @@ func (t *TailscaleInContainer) Ping(hostnameOrIP string, opts ...PingOption) err
|
||||
|
||||
command := make([]string, 0, 6)
|
||||
command = append(command,
|
||||
"tailscale", "ping",
|
||||
tailscaleBin, "ping",
|
||||
fmt.Sprintf("--timeout=%s", args.timeout),
|
||||
fmt.Sprintf("--c=%d", args.count),
|
||||
"--until-direct="+strconv.FormatBool(args.direct),
|
||||
@@ -1494,7 +1495,7 @@ const (
|
||||
)
|
||||
|
||||
// Curl executes the Tailscale curl command and curls a hostname
|
||||
// or IP. It accepts a series of CurlOption.
|
||||
// or IP. It accepts a series of [CurlOption].
|
||||
func (t *TailscaleInContainer) Curl(url string, opts ...CurlOption) (string, error) {
|
||||
args := curlArgs{
|
||||
connectionTimeout: defaultConnectionTimeout,
|
||||
@@ -1536,7 +1537,7 @@ func (t *TailscaleInContainer) Curl(url string, opts ...CurlOption) (string, err
|
||||
// curl exit 0 with an empty body usually means a mid-stream reset
|
||||
// after headers (HTTP 200 with the connection torn down before the
|
||||
// body arrived). Without this signal, callers wrapping the call in
|
||||
// EventuallyWithT see assert.NoError pass and assert.Len fail with
|
||||
// [assert.EventuallyWithT] see [assert.NoError] pass and [assert.Len] fail with
|
||||
// no error to drive a retry.
|
||||
if result == "" {
|
||||
return result, fmt.Errorf("%w: %s from %s", errCurlEmptyResponseBody, url, t.Hostname())
|
||||
@@ -1558,7 +1559,7 @@ func (t *TailscaleInContainer) CurlFailFast(url string) (string, error) {
|
||||
|
||||
func (t *TailscaleInContainer) Traceroute(ip netip.Addr) (util.Traceroute, error) {
|
||||
// -w 1: wait at most 1s for each probe response. busybox's default
|
||||
// is 5s, which means an EventuallyWithT loop at 200ms ticks
|
||||
// is 5s, which means an [assert.EventuallyWithT] loop at 200ms ticks
|
||||
// can spend 25 ticks worth of budget on a single Traceroute.
|
||||
// -q 1: send 1 probe per hop instead of 3. The HA tests only care
|
||||
// about the first hop's identity; the other probes are dead
|
||||
@@ -1603,7 +1604,7 @@ func (t *TailscaleInContainer) SaveLog(path string) (string, string, error) {
|
||||
}
|
||||
|
||||
// WriteLogs writes the current stdout/stderr log of the container to
|
||||
// the given io.Writers.
|
||||
// the given [io.Writer]s.
|
||||
func (t *TailscaleInContainer) WriteLogs(stdout, stderr io.Writer) error {
|
||||
return dockertestutil.WriteLog(t.pool, t.container, stdout, stderr)
|
||||
}
|
||||
@@ -1677,7 +1678,7 @@ func (t *TailscaleInContainer) GetNodePrivateKey() (*key.NodePrivate, error) {
|
||||
return &p.Persist.PrivateNodeKey, nil
|
||||
}
|
||||
|
||||
// ConnectToNetwork connects the Tailscale container to an additional Docker network.
|
||||
// ConnectToNetwork connects the Tailscale container to an additional Docker [dockertest.Network].
|
||||
func (t *TailscaleInContainer) ConnectToNetwork(network *dockertest.Network) error {
|
||||
return t.container.ConnectToNetwork(network)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user