errors: rewrite errors to follow go best practices

Errors should not start capitalised and they should not contain the word error
or state that they "failed" as we already know it is an error

Signed-off-by: Kristoffer Dalby <kristoffer@dalby.cc>
This commit is contained in:
Kristoffer Dalby
2026-02-05 16:29:54 +00:00
parent 4a9a329339
commit 3acce2da87
30 changed files with 300 additions and 300 deletions

View File

@@ -149,7 +149,7 @@ var destroyUserCmd = &cobra.Command{
} }
if len(users.GetUsers()) != 1 { if len(users.GetUsers()) != 1 {
err := errors.New("Unable to determine user to delete, query returned multiple users, use ID") err := errors.New("multiple users match query, specify an ID")
ErrorOutput( ErrorOutput(
err, err,
"Error: "+status.Convert(err).Message(), "Error: "+status.Convert(err).Message(),
@@ -277,7 +277,7 @@ var renameUserCmd = &cobra.Command{
} }
if len(users.GetUsers()) != 1 { if len(users.GetUsers()) != 1 {
err := errors.New("Unable to determine user to delete, query returned multiple users, use ID") err := errors.New("multiple users match query, specify an ID")
ErrorOutput( ErrorOutput(
err, err,
"Error: "+status.Convert(err).Message(), "Error: "+status.Convert(err).Message(),

View File

@@ -138,17 +138,17 @@ func output(result any, override string, outputFormat string) string {
case "json": case "json":
jsonBytes, err = json.MarshalIndent(result, "", "\t") jsonBytes, err = json.MarshalIndent(result, "", "\t")
if err != nil { if err != nil {
log.Fatal().Err(err).Msg("failed to unmarshal output") log.Fatal().Err(err).Msg("unmarshalling output")
} }
case "json-line": case "json-line":
jsonBytes, err = json.Marshal(result) jsonBytes, err = json.Marshal(result)
if err != nil { if err != nil {
log.Fatal().Err(err).Msg("failed to unmarshal output") log.Fatal().Err(err).Msg("unmarshalling output")
} }
case "yaml": case "yaml":
jsonBytes, err = yaml.Marshal(result) jsonBytes, err = yaml.Marshal(result)
if err != nil { if err != nil {
log.Fatal().Err(err).Msg("failed to unmarshal output") log.Fatal().Err(err).Msg("unmarshalling output")
} }
default: default:
// nolint // nolint

View File

@@ -22,11 +22,11 @@ import (
func cleanupBeforeTest(ctx context.Context) error { func cleanupBeforeTest(ctx context.Context) error {
err := cleanupStaleTestContainers(ctx) err := cleanupStaleTestContainers(ctx)
if err != nil { if err != nil {
return fmt.Errorf("failed to clean stale test containers: %w", err) return fmt.Errorf("cleaning stale test containers: %w", err)
} }
if err := pruneDockerNetworks(ctx); err != nil { if err := pruneDockerNetworks(ctx); err != nil {
return fmt.Errorf("failed to prune networks: %w", err) return fmt.Errorf("pruning networks: %w", err)
} }
return nil return nil
@@ -39,14 +39,14 @@ func cleanupAfterTest(ctx context.Context, cli *client.Client, containerID, runI
Force: true, Force: true,
}) })
if err != nil { if err != nil {
return fmt.Errorf("failed to remove test container: %w", err) return fmt.Errorf("removing test container: %w", err)
} }
// Clean up integration test containers for this run only // Clean up integration test containers for this run only
if runID != "" { if runID != "" {
err := killTestContainersByRunID(ctx, runID) err := killTestContainersByRunID(ctx, runID)
if err != nil { if err != nil {
return fmt.Errorf("failed to clean up containers for run %s: %w", runID, err) return fmt.Errorf("cleaning up containers for run %s: %w", runID, err)
} }
} }
@@ -57,7 +57,7 @@ func cleanupAfterTest(ctx context.Context, cli *client.Client, containerID, runI
func killTestContainers(ctx context.Context) error { func killTestContainers(ctx context.Context) error {
cli, err := createDockerClient() cli, err := createDockerClient()
if err != nil { if err != nil {
return fmt.Errorf("failed to create Docker client: %w", err) return fmt.Errorf("creating Docker client: %w", err)
} }
defer cli.Close() defer cli.Close()
@@ -65,7 +65,7 @@ func killTestContainers(ctx context.Context) error {
All: true, All: true,
}) })
if err != nil { if err != nil {
return fmt.Errorf("failed to list containers: %w", err) return fmt.Errorf("listing containers: %w", err)
} }
removed := 0 removed := 0
@@ -109,7 +109,7 @@ func killTestContainers(ctx context.Context) error {
func killTestContainersByRunID(ctx context.Context, runID string) error { func killTestContainersByRunID(ctx context.Context, runID string) error {
cli, err := createDockerClient() cli, err := createDockerClient()
if err != nil { if err != nil {
return fmt.Errorf("failed to create Docker client: %w", err) return fmt.Errorf("creating Docker client: %w", err)
} }
defer cli.Close() defer cli.Close()
@@ -121,7 +121,7 @@ func killTestContainersByRunID(ctx context.Context, runID string) error {
), ),
}) })
if err != nil { if err != nil {
return fmt.Errorf("failed to list containers for run %s: %w", runID, err) return fmt.Errorf("listing containers for run %s: %w", runID, err)
} }
removed := 0 removed := 0
@@ -151,7 +151,7 @@ func killTestContainersByRunID(ctx context.Context, runID string) error {
func cleanupStaleTestContainers(ctx context.Context) error { func cleanupStaleTestContainers(ctx context.Context) error {
cli, err := createDockerClient() cli, err := createDockerClient()
if err != nil { if err != nil {
return fmt.Errorf("failed to create Docker client: %w", err) return fmt.Errorf("creating Docker client: %w", err)
} }
defer cli.Close() defer cli.Close()
@@ -164,7 +164,7 @@ func cleanupStaleTestContainers(ctx context.Context) error {
), ),
}) })
if err != nil { if err != nil {
return fmt.Errorf("failed to list stopped containers: %w", err) return fmt.Errorf("listing stopped containers: %w", err)
} }
removed := 0 removed := 0
@@ -225,13 +225,13 @@ func removeContainerWithRetry(ctx context.Context, cli *client.Client, container
func pruneDockerNetworks(ctx context.Context) error { func pruneDockerNetworks(ctx context.Context) error {
cli, err := createDockerClient() cli, err := createDockerClient()
if err != nil { if err != nil {
return fmt.Errorf("failed to create Docker client: %w", err) return fmt.Errorf("creating Docker client: %w", err)
} }
defer cli.Close() defer cli.Close()
report, err := cli.NetworksPrune(ctx, filters.Args{}) report, err := cli.NetworksPrune(ctx, filters.Args{})
if err != nil { if err != nil {
return fmt.Errorf("failed to prune networks: %w", err) return fmt.Errorf("pruning networks: %w", err)
} }
if len(report.NetworksDeleted) > 0 { if len(report.NetworksDeleted) > 0 {
@@ -247,7 +247,7 @@ func pruneDockerNetworks(ctx context.Context) error {
func cleanOldImages(ctx context.Context) error { func cleanOldImages(ctx context.Context) error {
cli, err := createDockerClient() cli, err := createDockerClient()
if err != nil { if err != nil {
return fmt.Errorf("failed to create Docker client: %w", err) return fmt.Errorf("creating Docker client: %w", err)
} }
defer cli.Close() defer cli.Close()
@@ -255,7 +255,7 @@ func cleanOldImages(ctx context.Context) error {
All: true, All: true,
}) })
if err != nil { if err != nil {
return fmt.Errorf("failed to list images: %w", err) return fmt.Errorf("listing images: %w", err)
} }
removed := 0 removed := 0
@@ -297,7 +297,7 @@ func cleanOldImages(ctx context.Context) error {
func cleanCacheVolume(ctx context.Context) error { func cleanCacheVolume(ctx context.Context) error {
cli, err := createDockerClient() cli, err := createDockerClient()
if err != nil { if err != nil {
return fmt.Errorf("failed to create Docker client: %w", err) return fmt.Errorf("creating Docker client: %w", err)
} }
defer cli.Close() defer cli.Close()
@@ -330,7 +330,7 @@ func cleanCacheVolume(ctx context.Context) error {
func cleanupSuccessfulTestArtifacts(logsDir string, verbose bool) error { func cleanupSuccessfulTestArtifacts(logsDir string, verbose bool) error {
entries, err := os.ReadDir(logsDir) entries, err := os.ReadDir(logsDir)
if err != nil { if err != nil {
return fmt.Errorf("failed to read logs directory: %w", err) return fmt.Errorf("reading logs directory: %w", err)
} }
var ( var (

View File

@@ -32,7 +32,7 @@ var (
func runTestContainer(ctx context.Context, config *RunConfig) error { func runTestContainer(ctx context.Context, config *RunConfig) error {
cli, err := createDockerClient() cli, err := createDockerClient()
if err != nil { if err != nil {
return fmt.Errorf("failed to create Docker client: %w", err) return fmt.Errorf("creating Docker client: %w", err)
} }
defer cli.Close() defer cli.Close()
@@ -48,12 +48,12 @@ func runTestContainer(ctx context.Context, config *RunConfig) error {
absLogsDir, err := filepath.Abs(logsDir) absLogsDir, err := filepath.Abs(logsDir)
if err != nil { if err != nil {
return fmt.Errorf("failed to get absolute path for logs directory: %w", err) return fmt.Errorf("getting absolute path for logs directory: %w", err)
} }
const dirPerm = 0o755 const dirPerm = 0o755
if err := os.MkdirAll(absLogsDir, dirPerm); err != nil { if err := os.MkdirAll(absLogsDir, dirPerm); err != nil {
return fmt.Errorf("failed to create logs directory: %w", err) return fmt.Errorf("creating logs directory: %w", err)
} }
if config.CleanBefore { if config.CleanBefore {
@@ -72,12 +72,12 @@ func runTestContainer(ctx context.Context, config *RunConfig) error {
imageName := "golang:" + config.GoVersion imageName := "golang:" + config.GoVersion
if err := ensureImageAvailable(ctx, cli, imageName, config.Verbose); err != nil { if err := ensureImageAvailable(ctx, cli, imageName, config.Verbose); err != nil {
return fmt.Errorf("failed to ensure image availability: %w", err) return fmt.Errorf("ensuring image availability: %w", err)
} }
resp, err := createGoTestContainer(ctx, cli, config, containerName, absLogsDir, goTestCmd) resp, err := createGoTestContainer(ctx, cli, config, containerName, absLogsDir, goTestCmd)
if err != nil { if err != nil {
return fmt.Errorf("failed to create container: %w", err) return fmt.Errorf("creating container: %w", err)
} }
if config.Verbose { if config.Verbose {
@@ -85,7 +85,7 @@ func runTestContainer(ctx context.Context, config *RunConfig) error {
} }
if err := cli.ContainerStart(ctx, resp.ID, container.StartOptions{}); err != nil { if err := cli.ContainerStart(ctx, resp.ID, container.StartOptions{}); err != nil {
return fmt.Errorf("failed to start container: %w", err) return fmt.Errorf("starting container: %w", err)
} }
log.Printf("Starting test: %s", config.TestPattern) log.Printf("Starting test: %s", config.TestPattern)
@@ -176,7 +176,7 @@ func runTestContainer(ctx context.Context, config *RunConfig) error {
} }
if err != nil { if err != nil {
return fmt.Errorf("test execution failed: %w", err) return fmt.Errorf("executing test: %w", err)
} }
if exitCode != 0 { if exitCode != 0 {
@@ -210,7 +210,7 @@ func buildGoTestCommand(config *RunConfig) []string {
func createGoTestContainer(ctx context.Context, cli *client.Client, config *RunConfig, containerName, logsDir string, goTestCmd []string) (container.CreateResponse, error) { func createGoTestContainer(ctx context.Context, cli *client.Client, config *RunConfig, containerName, logsDir string, goTestCmd []string) (container.CreateResponse, error) {
pwd, err := os.Getwd() pwd, err := os.Getwd()
if err != nil { if err != nil {
return container.CreateResponse{}, fmt.Errorf("failed to get working directory: %w", err) return container.CreateResponse{}, fmt.Errorf("getting working directory: %w", err)
} }
projectRoot := findProjectRoot(pwd) projectRoot := findProjectRoot(pwd)
@@ -312,7 +312,7 @@ func streamAndWait(ctx context.Context, cli *client.Client, containerID string)
Follow: true, Follow: true,
}) })
if err != nil { if err != nil {
return -1, fmt.Errorf("failed to get container logs: %w", err) return -1, fmt.Errorf("getting container logs: %w", err)
} }
defer out.Close() defer out.Close()
@@ -324,7 +324,7 @@ func streamAndWait(ctx context.Context, cli *client.Client, containerID string)
select { select {
case err := <-errCh: case err := <-errCh:
if err != nil { if err != nil {
return -1, fmt.Errorf("error waiting for container: %w", err) return -1, fmt.Errorf("waiting for container: %w", err)
} }
case status := <-statusCh: case status := <-statusCh:
return int(status.StatusCode), nil return int(status.StatusCode), nil
@@ -338,7 +338,7 @@ func waitForContainerFinalization(ctx context.Context, cli *client.Client, testC
// First, get all related test containers // First, get all related test containers
containers, err := cli.ContainerList(ctx, container.ListOptions{All: true}) containers, err := cli.ContainerList(ctx, container.ListOptions{All: true})
if err != nil { if err != nil {
return fmt.Errorf("failed to list containers: %w", err) return fmt.Errorf("listing containers: %w", err)
} }
testContainers := getCurrentTestContainers(containers, testContainerID, verbose) testContainers := getCurrentTestContainers(containers, testContainerID, verbose)
@@ -462,12 +462,12 @@ func getCurrentDockerContext() (*DockerContext, error) {
cmd := exec.Command("docker", "context", "inspect") cmd := exec.Command("docker", "context", "inspect")
output, err := cmd.Output() output, err := cmd.Output()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get docker context: %w", err) return nil, fmt.Errorf("getting docker context: %w", err)
} }
var contexts []DockerContext var contexts []DockerContext
if err := json.Unmarshal(output, &contexts); err != nil { if err := json.Unmarshal(output, &contexts); err != nil {
return nil, fmt.Errorf("failed to parse docker context: %w", err) return nil, fmt.Errorf("parsing docker context: %w", err)
} }
if len(contexts) > 0 { if len(contexts) > 0 {
@@ -491,7 +491,7 @@ func checkImageAvailableLocally(ctx context.Context, cli *client.Client, imageNa
if client.IsErrNotFound(err) { if client.IsErrNotFound(err) {
return false, nil return false, nil
} }
return false, fmt.Errorf("failed to inspect image %s: %w", imageName, err) return false, fmt.Errorf("inspecting image %s: %w", imageName, err)
} }
return true, nil return true, nil
@@ -502,7 +502,7 @@ func ensureImageAvailable(ctx context.Context, cli *client.Client, imageName str
// First check if image is available locally // First check if image is available locally
available, err := checkImageAvailableLocally(ctx, cli, imageName) available, err := checkImageAvailableLocally(ctx, cli, imageName)
if err != nil { if err != nil {
return fmt.Errorf("failed to check local image availability: %w", err) return fmt.Errorf("checking local image availability: %w", err)
} }
if available { if available {
@@ -519,19 +519,19 @@ func ensureImageAvailable(ctx context.Context, cli *client.Client, imageName str
reader, err := cli.ImagePull(ctx, imageName, image.PullOptions{}) reader, err := cli.ImagePull(ctx, imageName, image.PullOptions{})
if err != nil { if err != nil {
return fmt.Errorf("failed to pull image %s: %w", imageName, err) return fmt.Errorf("pulling image %s: %w", imageName, err)
} }
defer reader.Close() defer reader.Close()
if verbose { if verbose {
_, err = io.Copy(os.Stdout, reader) _, err = io.Copy(os.Stdout, reader)
if err != nil { if err != nil {
return fmt.Errorf("failed to read pull output: %w", err) return fmt.Errorf("reading pull output: %w", err)
} }
} else { } else {
_, err = io.Copy(io.Discard, reader) _, err = io.Copy(io.Discard, reader)
if err != nil { if err != nil {
return fmt.Errorf("failed to read pull output: %w", err) return fmt.Errorf("reading pull output: %w", err)
} }
log.Printf("Image %s pulled successfully", imageName) log.Printf("Image %s pulled successfully", imageName)
} }
@@ -598,14 +598,14 @@ func listControlFiles(logsDir string) {
func extractArtifactsFromContainers(ctx context.Context, testContainerID, logsDir string, verbose bool) error { func extractArtifactsFromContainers(ctx context.Context, testContainerID, logsDir string, verbose bool) error {
cli, err := createDockerClient() cli, err := createDockerClient()
if err != nil { if err != nil {
return fmt.Errorf("failed to create Docker client: %w", err) return fmt.Errorf("creating Docker client: %w", err)
} }
defer cli.Close() defer cli.Close()
// List all containers // List all containers
containers, err := cli.ContainerList(ctx, container.ListOptions{All: true}) containers, err := cli.ContainerList(ctx, container.ListOptions{All: true})
if err != nil { if err != nil {
return fmt.Errorf("failed to list containers: %w", err) return fmt.Errorf("listing containers: %w", err)
} }
// Get containers from the specific test run // Get containers from the specific test run
@@ -691,12 +691,12 @@ func getCurrentTestContainers(containers []container.Summary, testContainerID st
func extractContainerArtifacts(ctx context.Context, cli *client.Client, containerID, containerName, logsDir string, verbose bool) error { func extractContainerArtifacts(ctx context.Context, cli *client.Client, containerID, containerName, logsDir string, verbose bool) error {
// Ensure the logs directory exists // Ensure the logs directory exists
if err := os.MkdirAll(logsDir, 0o755); err != nil { if err := os.MkdirAll(logsDir, 0o755); err != nil {
return fmt.Errorf("failed to create logs directory: %w", err) return fmt.Errorf("creating logs directory: %w", err)
} }
// Extract container logs // Extract container logs
if err := extractContainerLogs(ctx, cli, containerID, containerName, logsDir, verbose); err != nil { if err := extractContainerLogs(ctx, cli, containerID, containerName, logsDir, verbose); err != nil {
return fmt.Errorf("failed to extract logs: %w", err) return fmt.Errorf("extracting logs: %w", err)
} }
// Extract tar files for headscale containers only // Extract tar files for headscale containers only
@@ -723,7 +723,7 @@ func extractContainerLogs(ctx context.Context, cli *client.Client, containerID,
Tail: "all", Tail: "all",
}) })
if err != nil { if err != nil {
return fmt.Errorf("failed to get container logs: %w", err) return fmt.Errorf("getting container logs: %w", err)
} }
defer logReader.Close() defer logReader.Close()
@@ -737,17 +737,17 @@ func extractContainerLogs(ctx context.Context, cli *client.Client, containerID,
// Demultiplex the Docker logs stream to separate stdout and stderr // Demultiplex the Docker logs stream to separate stdout and stderr
_, err = stdcopy.StdCopy(&stdoutBuf, &stderrBuf, logReader) _, err = stdcopy.StdCopy(&stdoutBuf, &stderrBuf, logReader)
if err != nil { if err != nil {
return fmt.Errorf("failed to demultiplex container logs: %w", err) return fmt.Errorf("demultiplexing container logs: %w", err)
} }
// Write stdout logs // Write stdout logs
if err := os.WriteFile(stdoutPath, stdoutBuf.Bytes(), 0o644); err != nil { if err := os.WriteFile(stdoutPath, stdoutBuf.Bytes(), 0o644); err != nil {
return fmt.Errorf("failed to write stdout log: %w", err) return fmt.Errorf("writing stdout log: %w", err)
} }
// Write stderr logs // Write stderr logs
if err := os.WriteFile(stderrPath, stderrBuf.Bytes(), 0o644); err != nil { if err := os.WriteFile(stderrPath, stderrBuf.Bytes(), 0o644); err != nil {
return fmt.Errorf("failed to write stderr log: %w", err) return fmt.Errorf("writing stderr log: %w", err)
} }
if verbose { if verbose {

View File

@@ -47,7 +47,7 @@ type StatsCollector struct {
func NewStatsCollector() (*StatsCollector, error) { func NewStatsCollector() (*StatsCollector, error) {
cli, err := createDockerClient() cli, err := createDockerClient()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create Docker client: %w", err) return nil, fmt.Errorf("creating Docker client: %w", err)
} }
return &StatsCollector{ return &StatsCollector{

View File

@@ -121,7 +121,7 @@ func NewHeadscale(cfg *types.Config) (*Headscale, error) {
noisePrivateKey, err := readOrCreatePrivateKey(cfg.NoisePrivateKeyPath) noisePrivateKey, err := readOrCreatePrivateKey(cfg.NoisePrivateKeyPath)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read or create Noise protocol private key: %w", err) return nil, fmt.Errorf("reading or creating Noise protocol private key: %w", err)
} }
s, err := state.NewState(cfg) s, err := state.NewState(cfg)
@@ -206,7 +206,7 @@ func NewHeadscale(cfg *types.Config) (*Headscale, error) {
if cfg.DERP.ServerEnabled { if cfg.DERP.ServerEnabled {
derpServerKey, err := readOrCreatePrivateKey(cfg.DERP.ServerPrivateKeyPath) derpServerKey, err := readOrCreatePrivateKey(cfg.DERP.ServerPrivateKeyPath)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read or create DERP server private key: %w", err) return nil, fmt.Errorf("reading or creating DERP server private key: %w", err)
} }
if derpServerKey.Equal(*noisePrivateKey) { if derpServerKey.Equal(*noisePrivateKey) {
@@ -339,7 +339,7 @@ func (h *Headscale) grpcAuthenticationInterceptor(ctx context.Context,
if !ok { if !ok {
return ctx, status.Errorf( return ctx, status.Errorf(
codes.InvalidArgument, codes.InvalidArgument,
"Retrieving metadata is failed", "retrieving metadata",
) )
} }
@@ -347,7 +347,7 @@ func (h *Headscale) grpcAuthenticationInterceptor(ctx context.Context,
if !ok { if !ok {
return ctx, status.Errorf( return ctx, status.Errorf(
codes.Unauthenticated, codes.Unauthenticated,
"Authorization token is not supplied", "authorization token not supplied",
) )
} }
@@ -362,7 +362,7 @@ func (h *Headscale) grpcAuthenticationInterceptor(ctx context.Context,
valid, err := h.state.ValidateAPIKey(strings.TrimPrefix(token, AuthPrefix)) valid, err := h.state.ValidateAPIKey(strings.TrimPrefix(token, AuthPrefix))
if err != nil { if err != nil {
return ctx, status.Error(codes.Internal, "failed to validate token") return ctx, status.Error(codes.Internal, "validating token")
} }
if !valid { if !valid {
@@ -526,7 +526,7 @@ func (h *Headscale) Serve() error {
derpMap, err := derp.GetDERPMap(h.cfg.DERP) derpMap, err := derp.GetDERPMap(h.cfg.DERP)
if err != nil { if err != nil {
return fmt.Errorf("failed to get DERPMap: %w", err) return fmt.Errorf("getting DERPMap: %w", err)
} }
if h.cfg.DERP.ServerEnabled && h.cfg.DERP.AutomaticallyAddEmbeddedDerpRegion { if h.cfg.DERP.ServerEnabled && h.cfg.DERP.AutomaticallyAddEmbeddedDerpRegion {
@@ -586,7 +586,7 @@ func (h *Headscale) Serve() error {
err = h.ensureUnixSocketIsAbsent() err = h.ensureUnixSocketIsAbsent()
if err != nil { if err != nil {
return fmt.Errorf("unable to remove old socket file: %w", err) return fmt.Errorf("removing old socket file: %w", err)
} }
socketDir := filepath.Dir(h.cfg.UnixSocket) socketDir := filepath.Dir(h.cfg.UnixSocket)
@@ -597,12 +597,12 @@ func (h *Headscale) Serve() error {
socketListener, err := net.Listen("unix", h.cfg.UnixSocket) socketListener, err := net.Listen("unix", h.cfg.UnixSocket)
if err != nil { if err != nil {
return fmt.Errorf("failed to set up gRPC socket: %w", err) return fmt.Errorf("setting up gRPC socket: %w", err)
} }
// Change socket permissions // Change socket permissions
if err := os.Chmod(h.cfg.UnixSocket, h.cfg.UnixSocketPermission); err != nil { if err := os.Chmod(h.cfg.UnixSocket, h.cfg.UnixSocketPermission); err != nil {
return fmt.Errorf("failed change permission of gRPC socket: %w", err) return fmt.Errorf("changing gRPC socket permission: %w", err)
} }
grpcGatewayMux := grpcRuntime.NewServeMux() grpcGatewayMux := grpcRuntime.NewServeMux()
@@ -687,7 +687,7 @@ func (h *Headscale) Serve() error {
grpcListener, err = net.Listen("tcp", h.cfg.GRPCAddr) grpcListener, err = net.Listen("tcp", h.cfg.GRPCAddr)
if err != nil { if err != nil {
return fmt.Errorf("failed to bind to TCP address: %w", err) return fmt.Errorf("binding to TCP address: %w", err)
} }
errorGroup.Go(func() error { return grpcServer.Serve(grpcListener) }) errorGroup.Go(func() error { return grpcServer.Serve(grpcListener) })
@@ -722,7 +722,7 @@ func (h *Headscale) Serve() error {
httpListener, err = net.Listen("tcp", h.cfg.Addr) httpListener, err = net.Listen("tcp", h.cfg.Addr)
} }
if err != nil { if err != nil {
return fmt.Errorf("failed to bind to TCP address: %w", err) return fmt.Errorf("binding to TCP address: %w", err)
} }
errorGroup.Go(func() error { return httpServer.Serve(httpListener) }) errorGroup.Go(func() error { return httpServer.Serve(httpListener) })
@@ -738,7 +738,7 @@ func (h *Headscale) Serve() error {
if h.cfg.MetricsAddr != "" { if h.cfg.MetricsAddr != "" {
debugHTTPListener, err = (&net.ListenConfig{}).Listen(ctx, "tcp", h.cfg.MetricsAddr) debugHTTPListener, err = (&net.ListenConfig{}).Listen(ctx, "tcp", h.cfg.MetricsAddr)
if err != nil { if err != nil {
return fmt.Errorf("failed to bind to TCP address: %w", err) return fmt.Errorf("binding to TCP address: %w", err)
} }
debugHTTPServer = h.debugHTTPServer() debugHTTPServer = h.debugHTTPServer()
@@ -977,14 +977,14 @@ func readOrCreatePrivateKey(path string) (*key.MachinePrivate, error) {
machineKeyStr, err := machineKey.MarshalText() machineKeyStr, err := machineKey.MarshalText()
if err != nil { if err != nil {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"failed to convert private key to string for saving: %w", "converting private key to string for saving: %w",
err, err,
) )
} }
err = os.WriteFile(path, machineKeyStr, privateKeyFileMode) err = os.WriteFile(path, machineKeyStr, privateKeyFileMode)
if err != nil { if err != nil {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"failed to save private key to disk at path %q: %w", "saving private key to disk at path %q: %w",
path, path,
err, err,
) )
@@ -992,14 +992,14 @@ func readOrCreatePrivateKey(path string) (*key.MachinePrivate, error) {
return &machineKey, nil return &machineKey, nil
} else if err != nil { } else if err != nil {
return nil, fmt.Errorf("failed to read private key file: %w", err) return nil, fmt.Errorf("reading private key file: %w", err)
} }
trimmedPrivateKey := strings.TrimSpace(string(privateKey)) trimmedPrivateKey := strings.TrimSpace(string(privateKey))
var machineKey key.MachinePrivate var machineKey key.MachinePrivate
if err = machineKey.UnmarshalText([]byte(trimmedPrivateKey)); err != nil { if err = machineKey.UnmarshalText([]byte(trimmedPrivateKey)); err != nil {
return nil, fmt.Errorf("failed to parse private key: %w", err) return nil, fmt.Errorf("parsing private key: %w", err)
} }
return &machineKey, nil return &machineKey, nil

View File

@@ -78,7 +78,7 @@ func (hsdb *HSDatabase) CreateAPIKey(
} }
if err := hsdb.DB.Save(&key).Error; err != nil { if err := hsdb.DB.Save(&key).Error; err != nil {
return "", nil, fmt.Errorf("failed to save API key to database: %w", err) return "", nil, fmt.Errorf("saving API key to database: %w", err)
} }
return keyStr, &key, nil return keyStr, &key, nil

View File

@@ -290,7 +290,7 @@ func (db *HSDatabase) BackfillNodeIPs(i *IPAllocator) ([]string, error) {
if i.prefix4 != nil && node.IPv4 == nil { if i.prefix4 != nil && node.IPv4 == nil {
ret4, err := i.nextLocked(i.prev4, i.prefix4) ret4, err := i.nextLocked(i.prev4, i.prefix4)
if err != nil { if err != nil {
return fmt.Errorf("failed to allocate ipv4 for node(%d): %w", node.ID, err) return fmt.Errorf("allocating IPv4 for node(%d): %w", node.ID, err)
} }
node.IPv4 = ret4 node.IPv4 = ret4
@@ -302,7 +302,7 @@ func (db *HSDatabase) BackfillNodeIPs(i *IPAllocator) ([]string, error) {
if i.prefix6 != nil && node.IPv6 == nil { if i.prefix6 != nil && node.IPv6 == nil {
ret6, err := i.nextLocked(i.prev6, i.prefix6) ret6, err := i.nextLocked(i.prev6, i.prefix6)
if err != nil { if err != nil {
return fmt.Errorf("failed to allocate ipv6 for node(%d): %w", node.ID, err) return fmt.Errorf("allocating IPv6 for node(%d): %w", node.ID, err)
} }
node.IPv6 = ret6 node.IPv6 = ret6

View File

@@ -290,7 +290,7 @@ func RenameNode(tx *gorm.DB,
err = tx.Model(&types.Node{}).Where("given_name = ? AND id != ?", newName, nodeID).Count(&count).Error err = tx.Model(&types.Node{}).Where("given_name = ? AND id != ?", newName, nodeID).Count(&count).Error
if err != nil { if err != nil {
return fmt.Errorf("failed to check name uniqueness: %w", err) return fmt.Errorf("checking name uniqueness: %w", err)
} }
if count > 0 { if count > 0 {
@@ -298,7 +298,7 @@ func RenameNode(tx *gorm.DB,
} }
if err := tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("given_name", newName).Error; err != nil { if err := tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("given_name", newName).Error; err != nil {
return fmt.Errorf("failed to rename node in the database: %w", err) return fmt.Errorf("renaming node in database: %w", err)
} }
return nil return nil
@@ -396,7 +396,7 @@ func RegisterNodeForTest(tx *gorm.DB, node types.Node, ipv4 *netip.Addr, ipv6 *n
// adding it to the registrationCache // adding it to the registrationCache
if node.IPv4 != nil || node.IPv6 != nil { if node.IPv4 != nil || node.IPv6 != nil {
if err := tx.Save(&node).Error; err != nil { if err := tx.Save(&node).Error; err != nil {
return nil, fmt.Errorf("failed register existing node in the database: %w", err) return nil, fmt.Errorf("registering existing node in database: %w", err)
} }
log.Trace(). log.Trace().
@@ -425,14 +425,14 @@ func RegisterNodeForTest(tx *gorm.DB, node types.Node, ipv4 *netip.Addr, ipv6 *n
if node.GivenName == "" { if node.GivenName == "" {
givenName, err := EnsureUniqueGivenName(tx, node.Hostname) givenName, err := EnsureUniqueGivenName(tx, node.Hostname)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to ensure unique given name: %w", err) return nil, fmt.Errorf("ensuring unique given name: %w", err)
} }
node.GivenName = givenName node.GivenName = givenName
} }
if err := tx.Save(&node).Error; err != nil { if err := tx.Save(&node).Error; err != nil {
return nil, fmt.Errorf("failed register(save) node in the database: %w", err) return nil, fmt.Errorf("saving node to database: %w", err)
} }
log.Trace(). log.Trace().

View File

@@ -139,7 +139,7 @@ func CreatePreAuthKey(
} }
if err := tx.Save(&key).Error; err != nil { if err := tx.Save(&key).Error; err != nil {
return nil, fmt.Errorf("failed to create key in the database: %w", err) return nil, fmt.Errorf("creating key in database: %w", err)
} }
return &types.PreAuthKeyNew{ return &types.PreAuthKeyNew{
@@ -296,7 +296,7 @@ func DestroyPreAuthKey(tx *gorm.DB, id uint64) error {
Where("auth_key_id = ?", id). Where("auth_key_id = ?", id).
Update("auth_key_id", nil).Error Update("auth_key_id", nil).Error
if err != nil { if err != nil {
return fmt.Errorf("failed to clear auth_key_id on nodes: %w", err) return fmt.Errorf("clearing auth_key_id on nodes: %w", err)
} }
// Then delete the pre-auth key // Then delete the pre-auth key
@@ -325,7 +325,7 @@ func (hsdb *HSDatabase) DeletePreAuthKey(id uint64) error {
func UsePreAuthKey(tx *gorm.DB, k *types.PreAuthKey) error { func UsePreAuthKey(tx *gorm.DB, k *types.PreAuthKey) error {
err := tx.Model(k).Update("used", true).Error err := tx.Model(k).Update("used", true).Error
if err != nil { if err != nil {
return fmt.Errorf("failed to update key used status in the database: %w", err) return fmt.Errorf("updating key used status in database: %w", err)
} }
k.Used = true k.Used = true

View File

@@ -24,7 +24,7 @@ func maybeInstantiatePtr(rv reflect.Value) {
} }
func decodingError(name string, err error) error { func decodingError(name string, err error) error {
return fmt.Errorf("error decoding to %s: %w", name, err) return fmt.Errorf("decoding to %s: %w", name, err)
} }
// TextSerialiser implements the Serialiser interface for fields that // TextSerialiser implements the Serialiser interface for fields that
@@ -48,7 +48,7 @@ func (TextSerialiser) Scan(ctx context.Context, field *schema.Field, dst reflect
case string: case string:
bytes = []byte(v) bytes = []byte(v)
default: default:
return fmt.Errorf("failed to unmarshal text value: %#v", dbValue) return fmt.Errorf("unmarshalling text value: %#v", dbValue)
} }
if isTextUnmarshaler(fieldValue) { if isTextUnmarshaler(fieldValue) {

View File

@@ -55,7 +55,7 @@ func (api headscaleV1APIServer) CreateUser(
} }
user, policyChanged, err := api.h.state.CreateUser(newUser) user, policyChanged, err := api.h.state.CreateUser(newUser)
if err != nil { if err != nil {
return nil, status.Errorf(codes.Internal, "failed to create user: %s", err) return nil, status.Errorf(codes.Internal, "creating user: %s", err)
} }
// CreateUser returns a policy change response if the user creation affected policy. // CreateUser returns a policy change response if the user creation affected policy.
@@ -423,7 +423,7 @@ func validateTag(tag string) error {
return errors.New("tag should be lowercase") return errors.New("tag should be lowercase")
} }
if len(strings.Fields(tag)) > 1 { if len(strings.Fields(tag)) > 1 {
return errors.New("tag should not contains space") return errors.New("tags must not contain spaces")
} }
return nil return nil
} }
@@ -817,7 +817,7 @@ func (api headscaleV1APIServer) Health(
response := &v1.HealthResponse{} response := &v1.HealthResponse{}
if err := api.h.state.PingDB(ctx); err != nil { if err := api.h.state.PingDB(ctx); err != nil {
healthErr = fmt.Errorf("database ping failed: %w", err) healthErr = fmt.Errorf("pinging database: %w", err)
} else { } else {
response.DatabaseConnectivity = true response.DatabaseConnectivity = true
} }

View File

@@ -64,7 +64,7 @@ func NewHTTPError(code int, msg string, err error) HTTPError {
var errMethodNotAllowed = NewHTTPError(http.StatusMethodNotAllowed, "method not allowed", nil) var errMethodNotAllowed = NewHTTPError(http.StatusMethodNotAllowed, "method not allowed", nil)
var ErrRegisterMethodCLIDoesNotSupportExpire = errors.New( var ErrRegisterMethodCLIDoesNotSupportExpire = errors.New(
"machines registered with CLI does not support expire", "machines registered with CLI do not support expiry",
) )
func parseCapabilityVersion(req *http.Request) (tailcfg.CapabilityVersion, error) { func parseCapabilityVersion(req *http.Request) (tailcfg.CapabilityVersion, error) {
@@ -76,7 +76,7 @@ func parseCapabilityVersion(req *http.Request) (tailcfg.CapabilityVersion, error
clientCapabilityVersion, err := strconv.Atoi(clientCapabilityStr) clientCapabilityVersion, err := strconv.Atoi(clientCapabilityStr)
if err != nil { if err != nil {
return 0, NewHTTPError(http.StatusBadRequest, "invalid capability version", fmt.Errorf("failed to parse capability version: %w", err)) return 0, NewHTTPError(http.StatusBadRequest, "invalid capability version", fmt.Errorf("parsing capability version: %w", err))
} }
return tailcfg.CapabilityVersion(clientCapabilityVersion), nil return tailcfg.CapabilityVersion(clientCapabilityVersion), nil
@@ -88,12 +88,12 @@ func (h *Headscale) handleVerifyRequest(
) error { ) error {
body, err := io.ReadAll(req.Body) body, err := io.ReadAll(req.Body)
if err != nil { if err != nil {
return fmt.Errorf("cannot read request body: %w", err) return fmt.Errorf("reading request body: %w", err)
} }
var derpAdmitClientRequest tailcfg.DERPAdmitClientRequest var derpAdmitClientRequest tailcfg.DERPAdmitClientRequest
if err := json.Unmarshal(body, &derpAdmitClientRequest); err != nil { if err := json.Unmarshal(body, &derpAdmitClientRequest); err != nil {
return NewHTTPError(http.StatusBadRequest, "Bad Request: invalid JSON", fmt.Errorf("cannot parse derpAdmitClientRequest: %w", err)) return NewHTTPError(http.StatusBadRequest, "Bad Request: invalid JSON", fmt.Errorf("parsing DERP client request: %w", err))
} }
nodes := h.state.ListNodes() nodes := h.state.ListNodes()

View File

@@ -81,7 +81,7 @@ func (b *LockFreeBatcher) AddNode(id types.NodeID, c chan<- *tailcfg.MapResponse
if err != nil { if err != nil {
nlog.Error().Err(err).Msg("initial map generation failed") nlog.Error().Err(err).Msg("initial map generation failed")
nodeConn.removeConnectionByChannel(c) nodeConn.removeConnectionByChannel(c)
return fmt.Errorf("failed to generate initial map for node %d: %w", id, err) return fmt.Errorf("generating initial map for node %d: %w", id, err)
} }
// Use a blocking send with timeout for initial map since the channel should be ready // Use a blocking send with timeout for initial map since the channel should be ready
@@ -94,7 +94,7 @@ func (b *LockFreeBatcher) AddNode(id types.NodeID, c chan<- *tailcfg.MapResponse
nlog.Debug().Caller().Dur("timeout.duration", 5*time.Second). //nolint:mnd nlog.Debug().Caller().Dur("timeout.duration", 5*time.Second). //nolint:mnd
Msg("initial map send timed out because channel was blocked or receiver not ready") Msg("initial map send timed out because channel was blocked or receiver not ready")
nodeConn.removeConnectionByChannel(c) nodeConn.removeConnectionByChannel(c)
return fmt.Errorf("failed to send initial map to node %d: timeout", id) return fmt.Errorf("sending initial map to node %d: timeout", id)
} }
// Update connection status // Update connection status

View File

@@ -79,7 +79,7 @@ func (h *Headscale) NoiseUpgradeHandler(
noiseServer.earlyNoise, noiseServer.earlyNoise,
) )
if err != nil { if err != nil {
httpError(writer, fmt.Errorf("noise upgrade failed: %w", err)) httpError(writer, fmt.Errorf("upgrading noise connection: %w", err))
return return
} }

View File

@@ -32,8 +32,8 @@ const (
var ( var (
errEmptyOIDCCallbackParams = errors.New("empty OIDC callback params") errEmptyOIDCCallbackParams = errors.New("empty OIDC callback params")
errNoOIDCIDToken = errors.New("could not extract ID Token for OIDC callback") errNoOIDCIDToken = errors.New("extracting ID token")
errNoOIDCRegistrationInfo = errors.New("could not get registration info from cache") errNoOIDCRegistrationInfo = errors.New("registration info not in cache")
errOIDCAllowedDomains = errors.New( errOIDCAllowedDomains = errors.New(
"authenticated principal does not match any allowed domain", "authenticated principal does not match any allowed domain",
) )
@@ -377,7 +377,7 @@ func (a *AuthProviderOIDC) getOauth2Token(
oauth2Token, err := a.oauth2Config.Exchange(ctx, code, exchangeOpts...) oauth2Token, err := a.oauth2Config.Exchange(ctx, code, exchangeOpts...)
if err != nil { if err != nil {
return nil, NewHTTPError(http.StatusForbidden, "invalid code", fmt.Errorf("could not exchange code for token: %w", err)) return nil, NewHTTPError(http.StatusForbidden, "invalid code", fmt.Errorf("exchanging code for token: %w", err))
} }
return oauth2Token, err return oauth2Token, err
@@ -396,7 +396,7 @@ func (a *AuthProviderOIDC) extractIDToken(
verifier := a.oidcProvider.Verifier(&oidc.Config{ClientID: a.cfg.ClientID}) verifier := a.oidcProvider.Verifier(&oidc.Config{ClientID: a.cfg.ClientID})
idToken, err := verifier.Verify(ctx, rawIDToken) idToken, err := verifier.Verify(ctx, rawIDToken)
if err != nil { if err != nil {
return nil, NewHTTPError(http.StatusForbidden, "failed to verify id_token", fmt.Errorf("failed to verify ID token: %w", err)) return nil, NewHTTPError(http.StatusForbidden, "failed to verify id_token", fmt.Errorf("verifying ID token: %w", err))
} }
return idToken, nil return idToken, nil
@@ -561,7 +561,7 @@ func (a *AuthProviderOIDC) handleRegistration(
util.RegisterMethodOIDC, util.RegisterMethodOIDC,
) )
if err != nil { if err != nil {
return false, fmt.Errorf("could not register node: %w", err) return false, fmt.Errorf("registering node: %w", err)
} }
// This is a bit of a back and forth, but we have a bit of a chicken and egg // This is a bit of a back and forth, but we have a bit of a chicken and egg

View File

@@ -138,7 +138,7 @@ func (u Username) Validate() error {
if isUser(string(u)) { if isUser(string(u)) {
return nil return nil
} }
return fmt.Errorf("Username has to contain @, got: %q", u) return fmt.Errorf("username must contain @, got: %q", u)
} }
func (u *Username) String() string { func (u *Username) String() string {
@@ -243,7 +243,7 @@ func (g Group) Validate() error {
if isGroup(string(g)) { if isGroup(string(g)) {
return nil return nil
} }
return fmt.Errorf(`Group has to start with "group:", got: %q`, g) return fmt.Errorf(`group must start with "group:", got: %q`, g)
} }
func (g *Group) UnmarshalJSON(b []byte) error { func (g *Group) UnmarshalJSON(b []byte) error {
@@ -354,7 +354,7 @@ func (h Host) Validate() error {
if isHost(string(h)) { if isHost(string(h)) {
return nil return nil
} }
return fmt.Errorf("Hostname %q is invalid", h) return fmt.Errorf("hostname %q is invalid", h)
} }
func (h *Host) UnmarshalJSON(b []byte) error { func (h *Host) UnmarshalJSON(b []byte) error {
@@ -372,7 +372,7 @@ func (h Host) Resolve(p *Policy, _ types.Users, nodes views.Slice[types.NodeView
pref, ok := p.Hosts[h] pref, ok := p.Hosts[h]
if !ok { if !ok {
return nil, fmt.Errorf("unable to resolve host: %q", h) return nil, fmt.Errorf("resolving host: %q", h)
} }
err := pref.Validate() err := pref.Validate()
if err != nil { if err != nil {
@@ -406,7 +406,7 @@ func (p Prefix) Validate() error {
if netip.Prefix(p).IsValid() { if netip.Prefix(p).IsValid() {
return nil return nil
} }
return fmt.Errorf("Prefix %q is invalid", p) return fmt.Errorf("prefix %q is invalid", p)
} }
func (p Prefix) String() string { func (p Prefix) String() string {
@@ -505,7 +505,7 @@ func (ag AutoGroup) Validate() error {
return nil return nil
} }
return fmt.Errorf("AutoGroup is invalid, got: %q, must be one of %v", ag, autogroups) return fmt.Errorf("autogroup is invalid, got: %q, must be one of %v", ag, autogroups)
} }
func (ag *AutoGroup) UnmarshalJSON(b []byte) error { func (ag *AutoGroup) UnmarshalJSON(b []byte) error {
@@ -1003,14 +1003,14 @@ func (g *Groups) UnmarshalJSON(b []byte) error {
if str, ok := item.(string); ok { if str, ok := item.(string); ok {
stringSlice = append(stringSlice, str) stringSlice = append(stringSlice, str)
} else { } else {
return fmt.Errorf(`Group "%s" contains invalid member type, expected string but got %T`, key, item) return fmt.Errorf(`group "%s" contains invalid member type, expected string but got %T`, key, item)
} }
} }
rawGroups[key] = stringSlice rawGroups[key] = stringSlice
case string: case string:
return fmt.Errorf(`Group "%s" value must be an array of users, got string: "%s"`, key, v) return fmt.Errorf(`group "%s" value must be an array of users, got string: "%s"`, key, v)
default: default:
return fmt.Errorf(`Group "%s" value must be an array of users, got %T`, key, v) return fmt.Errorf(`group "%s" value must be an array of users, got %T`, key, v)
} }
} }
@@ -1024,7 +1024,7 @@ func (g *Groups) UnmarshalJSON(b []byte) error {
username := Username(u) username := Username(u)
if err := username.Validate(); err != nil { if err := username.Validate(); err != nil {
if isGroup(u) { if isGroup(u) {
return fmt.Errorf("Nested groups are not allowed, found %q inside %q", u, group) return fmt.Errorf("nested groups are not allowed, found %q inside %q", u, group)
} }
return err return err
@@ -1056,7 +1056,7 @@ func (h *Hosts) UnmarshalJSON(b []byte) error {
var prefix Prefix var prefix Prefix
if err := prefix.parseString(value); err != nil { if err := prefix.parseString(value); err != nil {
return fmt.Errorf(`Hostname "%s" contains an invalid IP address: "%s"`, key, value) return fmt.Errorf(`hostname "%s" contains an invalid IP address: "%s"`, key, value)
} }
(*h)[host] = prefix (*h)[host] = prefix
@@ -1128,7 +1128,7 @@ func (to TagOwners) Contains(tagOwner *Tag) error {
} }
} }
return fmt.Errorf(`Tag %q is not defined in the Policy, please define or remove the reference to it`, tagOwner) return fmt.Errorf(`tag %q is not defined in the policy, please define or remove the reference to it`, tagOwner)
} }
type AutoApproverPolicy struct { type AutoApproverPolicy struct {
@@ -1750,7 +1750,7 @@ func (p *Policy) validate() error {
case *Host: case *Host:
h := src h := src
if !p.Hosts.exist(*h) { if !p.Hosts.exist(*h) {
errs = append(errs, fmt.Errorf(`Host %q is not defined in the Policy, please define or remove the reference to it`, *h)) errs = append(errs, fmt.Errorf(`host %q is not defined in the policy, please define or remove the reference to it`, *h))
} }
case *AutoGroup: case *AutoGroup:
ag := src ag := src
@@ -1782,7 +1782,7 @@ func (p *Policy) validate() error {
case *Host: case *Host:
h := dst.Alias.(*Host) h := dst.Alias.(*Host)
if !p.Hosts.exist(*h) { if !p.Hosts.exist(*h) {
errs = append(errs, fmt.Errorf(`Host %q is not defined in the Policy, please define or remove the reference to it`, *h)) errs = append(errs, fmt.Errorf(`host %q is not defined in the policy, please define or remove the reference to it`, *h))
} }
case *AutoGroup: case *AutoGroup:
ag := dst.Alias.(*AutoGroup) ag := dst.Alias.(*AutoGroup)

View File

@@ -380,7 +380,7 @@ func TestUnmarshalPolicy(t *testing.T) {
}, },
} }
`, `,
wantErr: `Username has to contain @, got: "invalid"`, wantErr: `username must contain @, got: "invalid"`,
}, },
{ {
name: "invalid-group", name: "invalid-group",
@@ -393,7 +393,7 @@ func TestUnmarshalPolicy(t *testing.T) {
}, },
} }
`, `,
wantErr: `Group has to start with "group:", got: "grou:example"`, wantErr: `group must start with "group:", got: "grou:example"`,
}, },
{ {
name: "group-in-group", name: "group-in-group",
@@ -407,8 +407,8 @@ func TestUnmarshalPolicy(t *testing.T) {
}, },
} }
`, `,
// wantErr: `Username has to contain @, got: "group:inner"`, // wantErr: `username must contain @, got: "group:inner"`,
wantErr: `Nested groups are not allowed, found "group:inner" inside "group:example"`, wantErr: `nested groups are not allowed, found "group:inner" inside "group:example"`,
}, },
{ {
name: "invalid-addr", name: "invalid-addr",
@@ -419,7 +419,7 @@ func TestUnmarshalPolicy(t *testing.T) {
}, },
} }
`, `,
wantErr: `Hostname "derp" contains an invalid IP address: "10.0"`, wantErr: `hostname "derp" contains an invalid IP address: "10.0"`,
}, },
{ {
name: "invalid-prefix", name: "invalid-prefix",
@@ -430,7 +430,7 @@ func TestUnmarshalPolicy(t *testing.T) {
}, },
} }
`, `,
wantErr: `Hostname "derp" contains an invalid IP address: "10.0/42"`, wantErr: `hostname "derp" contains an invalid IP address: "10.0/42"`,
}, },
// TODO(kradalby): Figure out why this doesn't work. // TODO(kradalby): Figure out why this doesn't work.
// { // {
@@ -459,7 +459,7 @@ func TestUnmarshalPolicy(t *testing.T) {
], ],
} }
`, `,
wantErr: `AutoGroup is invalid, got: "autogroup:invalid", must be one of [autogroup:internet autogroup:member autogroup:nonroot autogroup:tagged autogroup:self]`, wantErr: `autogroup is invalid, got: "autogroup:invalid", must be one of [autogroup:internet autogroup:member autogroup:nonroot autogroup:tagged autogroup:self]`,
}, },
{ {
name: "undefined-hostname-errors-2490", name: "undefined-hostname-errors-2490",
@@ -478,7 +478,7 @@ func TestUnmarshalPolicy(t *testing.T) {
] ]
} }
`, `,
wantErr: `Host "user1" is not defined in the Policy, please define or remove the reference to it`, wantErr: `host "user1" is not defined in the policy, please define or remove the reference to it`,
}, },
{ {
name: "defined-hostname-does-not-err-2490", name: "defined-hostname-does-not-err-2490",
@@ -854,7 +854,7 @@ func TestUnmarshalPolicy(t *testing.T) {
] ]
} }
`, `,
wantErr: `Tag "tag:notdefined" is not defined in the Policy, please define or remove the reference to it`, wantErr: `tag "tag:notdefined" is not defined in the policy, please define or remove the reference to it`,
}, },
{ {
name: "tag-must-be-defined-acl-dst", name: "tag-must-be-defined-acl-dst",
@@ -873,7 +873,7 @@ func TestUnmarshalPolicy(t *testing.T) {
] ]
} }
`, `,
wantErr: `Tag "tag:notdefined" is not defined in the Policy, please define or remove the reference to it`, wantErr: `tag "tag:notdefined" is not defined in the policy, please define or remove the reference to it`,
}, },
{ {
name: "tag-must-be-defined-acl-ssh-src", name: "tag-must-be-defined-acl-ssh-src",
@@ -892,7 +892,7 @@ func TestUnmarshalPolicy(t *testing.T) {
] ]
} }
`, `,
wantErr: `Tag "tag:notdefined" is not defined in the Policy, please define or remove the reference to it`, wantErr: `tag "tag:notdefined" is not defined in the policy, please define or remove the reference to it`,
}, },
{ {
name: "tag-must-be-defined-acl-ssh-dst", name: "tag-must-be-defined-acl-ssh-dst",
@@ -914,7 +914,7 @@ func TestUnmarshalPolicy(t *testing.T) {
] ]
} }
`, `,
wantErr: `Tag "tag:notdefined" is not defined in the Policy, please define or remove the reference to it`, wantErr: `tag "tag:notdefined" is not defined in the policy, please define or remove the reference to it`,
}, },
{ {
name: "tag-must-be-defined-acl-autoapprover-route", name: "tag-must-be-defined-acl-autoapprover-route",
@@ -927,7 +927,7 @@ func TestUnmarshalPolicy(t *testing.T) {
}, },
} }
`, `,
wantErr: `Tag "tag:notdefined" is not defined in the Policy, please define or remove the reference to it`, wantErr: `tag "tag:notdefined" is not defined in the policy, please define or remove the reference to it`,
}, },
{ {
name: "tag-must-be-defined-acl-autoapprover-exitnode", name: "tag-must-be-defined-acl-autoapprover-exitnode",
@@ -938,7 +938,7 @@ func TestUnmarshalPolicy(t *testing.T) {
}, },
} }
`, `,
wantErr: `Tag "tag:notdefined" is not defined in the Policy, please define or remove the reference to it`, wantErr: `tag "tag:notdefined" is not defined in the policy, please define or remove the reference to it`,
}, },
{ {
name: "missing-dst-port-is-err", name: "missing-dst-port-is-err",
@@ -1010,7 +1010,7 @@ func TestUnmarshalPolicy(t *testing.T) {
} }
} }
`, `,
wantErr: `Group has to start with "group:", got: "INVALID_GROUP_FIELD"`, wantErr: `group must start with "group:", got: "INVALID_GROUP_FIELD"`,
}, },
{ {
name: "invalid-group-datatype", name: "invalid-group-datatype",
@@ -1022,7 +1022,7 @@ func TestUnmarshalPolicy(t *testing.T) {
} }
} }
`, `,
wantErr: `Group "group:invalid" value must be an array of users, got string: "should fail"`, wantErr: `group "group:invalid" value must be an array of users, got string: "should fail"`,
}, },
{ {
name: "invalid-group-name-and-datatype-fails-on-name-first", name: "invalid-group-name-and-datatype-fails-on-name-first",
@@ -1034,7 +1034,7 @@ func TestUnmarshalPolicy(t *testing.T) {
} }
} }
`, `,
wantErr: `Group has to start with "group:", got: "INVALID_GROUP_FIELD"`, wantErr: `group must start with "group:", got: "INVALID_GROUP_FIELD"`,
}, },
{ {
name: "disallow-unsupported-fields-hosts-level", name: "disallow-unsupported-fields-hosts-level",
@@ -1046,7 +1046,7 @@ func TestUnmarshalPolicy(t *testing.T) {
} }
} }
`, `,
wantErr: `Hostname "INVALID_HOST_FIELD" contains an invalid IP address: "should fail"`, wantErr: `hostname "INVALID_HOST_FIELD" contains an invalid IP address: "should fail"`,
}, },
{ {
name: "disallow-unsupported-fields-tagowners-level", name: "disallow-unsupported-fields-tagowners-level",
@@ -2045,7 +2045,7 @@ func TestResolvePolicy(t *testing.T) {
"testhost": p("100.100.101.102/32"), "testhost": p("100.100.101.102/32"),
}, },
}, },
wantErr: `unable to resolve host: "invalidhost"`, wantErr: `resolving host: "invalidhost"`,
}, },
{ {
name: "multiple-groups", name: "multiple-groups",
@@ -2909,7 +2909,7 @@ func TestNodeCanHaveTag(t *testing.T) {
node: nodes[0], node: nodes[0],
tag: "tag:test", tag: "tag:test",
want: false, want: false,
wantErr: "Username has to contain @", wantErr: "username must contain @",
}, },
{ {
name: "node-cannot-have-tag", name: "node-cannot-have-tag",

View File

@@ -119,12 +119,12 @@ func NewState(cfg *types.Config) (*State, error) {
registrationCache, registrationCache,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("init database: %w", err) return nil, fmt.Errorf("initializing database: %w", err)
} }
ipAlloc, err := hsdb.NewIPAllocator(db, cfg.PrefixV4, cfg.PrefixV6, cfg.IPAllocation) ipAlloc, err := hsdb.NewIPAllocator(db, cfg.PrefixV4, cfg.PrefixV6, cfg.IPAllocation)
if err != nil { if err != nil {
return nil, fmt.Errorf("init ip allocatior: %w", err) return nil, fmt.Errorf("initializing IP allocator: %w", err)
} }
nodes, err := db.ListNodes() nodes, err := db.ListNodes()
@@ -150,7 +150,7 @@ func NewState(cfg *types.Config) (*State, error) {
polMan, err := policy.NewPolicyManager(pol, users, nodes.ViewSlice()) polMan, err := policy.NewPolicyManager(pol, users, nodes.ViewSlice())
if err != nil { if err != nil {
return nil, fmt.Errorf("init policy manager: %w", err) return nil, fmt.Errorf("initializing policy manager: %w", err)
} }
// Apply defaults for NodeStore batch configuration if not set. // Apply defaults for NodeStore batch configuration if not set.
@@ -268,7 +268,7 @@ func (s *State) CreateUser(user types.User) (*types.User, change.Change, error)
c, err := s.updatePolicyManagerUsers() c, err := s.updatePolicyManagerUsers()
if err != nil { if err != nil {
// Log the error but don't fail the user creation // Log the error but don't fail the user creation
return &user, change.Change{}, fmt.Errorf("failed to update policy manager after user creation: %w", err) return &user, change.Change{}, fmt.Errorf("updating policy manager after user creation: %w", err)
} }
// Even if the policy manager doesn't detect a filter change, SSH policies // Even if the policy manager doesn't detect a filter change, SSH policies
@@ -313,7 +313,7 @@ func (s *State) UpdateUser(userID types.UserID, updateFn func(*types.User) error
// Check if policy manager needs updating // Check if policy manager needs updating
c, err := s.updatePolicyManagerUsers() c, err := s.updatePolicyManagerUsers()
if err != nil { if err != nil {
return user, change.Change{}, fmt.Errorf("failed to update policy manager after user update: %w", err) return user, change.Change{}, fmt.Errorf("updating policy manager after user update: %w", err)
} }
// TODO(kradalby): We might want to update nodestore with the user data // TODO(kradalby): We might want to update nodestore with the user data
@@ -422,7 +422,7 @@ func (s *State) persistNodeToDB(node types.NodeView) (types.NodeView, change.Cha
// Check if policy manager needs updating // Check if policy manager needs updating
c, err := s.updatePolicyManagerNodes() c, err := s.updatePolicyManagerNodes()
if err != nil { if err != nil {
return nodePtr.View(), change.Change{}, fmt.Errorf("failed to update policy manager after node save: %w", err) return nodePtr.View(), change.Change{}, fmt.Errorf("updating policy manager after node save: %w", err)
} }
if c.IsEmpty() { if c.IsEmpty() {
@@ -459,7 +459,7 @@ func (s *State) DeleteNode(node types.NodeView) (change.Change, error) {
// Check if policy manager needs updating after node deletion // Check if policy manager needs updating after node deletion
policyChange, err := s.updatePolicyManagerNodes() policyChange, err := s.updatePolicyManagerNodes()
if err != nil { if err != nil {
return change.Change{}, fmt.Errorf("failed to update policy manager after node deletion: %w", err) return change.Change{}, fmt.Errorf("updating policy manager after node deletion: %w", err)
} }
if !policyChange.IsEmpty() { if !policyChange.IsEmpty() {
@@ -797,7 +797,7 @@ func (s *State) BackfillNodeIPs() ([]string, error) {
if len(changes) > 0 { if len(changes) > 0 {
nodes, err := s.db.ListNodes() nodes, err := s.db.ListNodes()
if err != nil { if err != nil {
return changes, fmt.Errorf("failed to refresh NodeStore after IP backfill: %w", err) return changes, fmt.Errorf("refreshing NodeStore after IP backfill: %w", err)
} }
for _, node := range nodes { for _, node := range nodes {
@@ -1242,7 +1242,7 @@ func (s *State) applyAuthNodeUpdate(params authNodeUpdateParams) (types.NodeView
_, err := hsdb.Write(s.db.DB, func(tx *gorm.DB) (*types.Node, error) { _, err := hsdb.Write(s.db.DB, func(tx *gorm.DB) (*types.Node, error) {
err := tx.Omit("AuthKeyID", "AuthKey").Updates(updatedNodeView.AsStruct()).Error err := tx.Omit("AuthKeyID", "AuthKey").Updates(updatedNodeView.AsStruct()).Error
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to save node: %w", err) return nil, fmt.Errorf("saving node: %w", err)
} }
return nil, nil //nolint:nilnil // side-effect only write return nil, nil //nolint:nilnil // side-effect only write
@@ -1373,7 +1373,7 @@ func (s *State) createAndSaveNewNode(params newNodeParams) (types.NodeView, erro
if nodeToRegister.GivenName == "" { if nodeToRegister.GivenName == "" {
givenName, err := hsdb.EnsureUniqueGivenName(s.db.DB, nodeToRegister.Hostname) givenName, err := hsdb.EnsureUniqueGivenName(s.db.DB, nodeToRegister.Hostname)
if err != nil { if err != nil {
return types.NodeView{}, fmt.Errorf("failed to ensure unique given name: %w", err) return types.NodeView{}, fmt.Errorf("ensuring unique given name: %w", err)
} }
nodeToRegister.GivenName = givenName nodeToRegister.GivenName = givenName
@@ -1383,7 +1383,7 @@ func (s *State) createAndSaveNewNode(params newNodeParams) (types.NodeView, erro
savedNode, err := hsdb.Write(s.db.DB, func(tx *gorm.DB) (*types.Node, error) { savedNode, err := hsdb.Write(s.db.DB, func(tx *gorm.DB) (*types.Node, error) {
err := tx.Save(&nodeToRegister).Error err := tx.Save(&nodeToRegister).Error
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to save node: %w", err) return nil, fmt.Errorf("saving node: %w", err)
} }
if params.PreAuthKey != nil && !params.PreAuthKey.Reusable { if params.PreAuthKey != nil && !params.PreAuthKey.Reusable {
@@ -1527,7 +1527,7 @@ func (s *State) HandleNodeFromAuthPath(
// Get the user // Get the user
user, err := s.db.GetUserByID(userID) user, err := s.db.GetUserByID(userID)
if err != nil { if err != nil {
return types.NodeView{}, change.Change{}, fmt.Errorf("failed to find user: %w", err) return types.NodeView{}, change.Change{}, fmt.Errorf("finding user: %w", err)
} }
// Ensure we have a valid hostname from the registration cache entry // Ensure we have a valid hostname from the registration cache entry
@@ -1632,12 +1632,12 @@ func (s *State) HandleNodeFromAuthPath(
// Update policy managers // Update policy managers
usersChange, err := s.updatePolicyManagerUsers() usersChange, err := s.updatePolicyManagerUsers()
if err != nil { if err != nil {
return finalNode, change.NodeAdded(finalNode.ID()), fmt.Errorf("failed to update policy manager users: %w", err) return finalNode, change.NodeAdded(finalNode.ID()), fmt.Errorf("updating policy manager users: %w", err)
} }
nodesChange, err := s.updatePolicyManagerNodes() nodesChange, err := s.updatePolicyManagerNodes()
if err != nil { if err != nil {
return finalNode, change.NodeAdded(finalNode.ID()), fmt.Errorf("failed to update policy manager nodes: %w", err) return finalNode, change.NodeAdded(finalNode.ID()), fmt.Errorf("updating policy manager nodes: %w", err)
} }
var c change.Change var c change.Change
@@ -1840,7 +1840,7 @@ func (s *State) HandleNodeFromPreAuthKey(
// Omit AuthKeyID/AuthKey to prevent stale PreAuthKey references from causing FK errors. // Omit AuthKeyID/AuthKey to prevent stale PreAuthKey references from causing FK errors.
err := tx.Omit("AuthKeyID", "AuthKey").Updates(updatedNodeView.AsStruct()).Error err := tx.Omit("AuthKeyID", "AuthKey").Updates(updatedNodeView.AsStruct()).Error
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to save node: %w", err) return nil, fmt.Errorf("saving node: %w", err)
} }
if !pak.Reusable { if !pak.Reusable {
@@ -1922,12 +1922,12 @@ func (s *State) HandleNodeFromPreAuthKey(
// Update policy managers // Update policy managers
usersChange, err := s.updatePolicyManagerUsers() usersChange, err := s.updatePolicyManagerUsers()
if err != nil { if err != nil {
return finalNode, change.NodeAdded(finalNode.ID()), fmt.Errorf("failed to update policy manager users: %w", err) return finalNode, change.NodeAdded(finalNode.ID()), fmt.Errorf("updating policy manager users: %w", err)
} }
nodesChange, err := s.updatePolicyManagerNodes() nodesChange, err := s.updatePolicyManagerNodes()
if err != nil { if err != nil {
return finalNode, change.NodeAdded(finalNode.ID()), fmt.Errorf("failed to update policy manager nodes: %w", err) return finalNode, change.NodeAdded(finalNode.ID()), fmt.Errorf("updating policy manager nodes: %w", err)
} }
var c change.Change var c change.Change

View File

@@ -25,8 +25,8 @@ import (
) )
var ( var (
ErrNodeAddressesInvalid = errors.New("failed to parse node addresses") ErrNodeAddressesInvalid = errors.New("parsing node addresses")
ErrHostnameTooLong = errors.New("hostname too long, cannot except 255 ASCII chars") ErrHostnameTooLong = errors.New("hostname too long, cannot accept more than 255 ASCII chars")
ErrNodeHasNoGivenName = errors.New("node has no given name") ErrNodeHasNoGivenName = errors.New("node has no given name")
ErrNodeUserHasNoName = errors.New("node user has no name") ErrNodeUserHasNoName = errors.New("node user has no name")
ErrCannotRemoveAllTags = errors.New("cannot remove all tags from node") ErrCannotRemoveAllTags = errors.New("cannot remove all tags from node")
@@ -417,7 +417,7 @@ func (node *Node) Proto() *v1.Node {
func (node *Node) GetFQDN(baseDomain string) (string, error) { func (node *Node) GetFQDN(baseDomain string) (string, error) {
if node.GivenName == "" { if node.GivenName == "" {
return "", fmt.Errorf("failed to create valid FQDN: %w", ErrNodeHasNoGivenName) return "", fmt.Errorf("creating valid FQDN: %w", ErrNodeHasNoGivenName)
} }
hostname := node.GivenName hostname := node.GivenName
@@ -432,7 +432,7 @@ func (node *Node) GetFQDN(baseDomain string) (string, error) {
if len(hostname) > MaxHostnameLength { if len(hostname) > MaxHostnameLength {
return "", fmt.Errorf( return "", fmt.Errorf(
"failed to create valid FQDN (%s): %w", "creating valid FQDN (%s): %w",
hostname, hostname,
ErrHostnameTooLong, ErrHostnameTooLong,
) )
@@ -897,7 +897,7 @@ func (nv NodeView) PeerChangeFromMapRequest(req tailcfg.MapRequest) tailcfg.Peer
// GetFQDN returns the fully qualified domain name for the node. // GetFQDN returns the fully qualified domain name for the node.
func (nv NodeView) GetFQDN(baseDomain string) (string, error) { func (nv NodeView) GetFQDN(baseDomain string) (string, error) {
if !nv.Valid() { if !nv.Valid() {
return "", errors.New("failed to create valid FQDN: node view is invalid") return "", errors.New("creating valid FQDN: node view is invalid")
} }
return nv.ж.GetFQDN(baseDomain) return nv.ж.GetFQDN(baseDomain)

View File

@@ -165,7 +165,7 @@ func TestNodeFQDN(t *testing.T) {
}, },
}, },
domain: "example.com", domain: "example.com",
wantErr: "failed to create valid FQDN: node has no given name", wantErr: "creating valid FQDN: node has no given name",
}, },
{ {
name: "too-long-username", name: "too-long-username",
@@ -173,7 +173,7 @@ func TestNodeFQDN(t *testing.T) {
GivenName: strings.Repeat("a", 256), GivenName: strings.Repeat("a", 256),
}, },
domain: "example.com", domain: "example.com",
wantErr: fmt.Sprintf("failed to create valid FQDN (%s.example.com.): hostname too long, cannot except 255 ASCII chars", strings.Repeat("a", 256)), wantErr: fmt.Sprintf("creating valid FQDN (%s.example.com.): hostname too long, cannot accept more than 255 ASCII chars", strings.Repeat("a", 256)),
}, },
{ {
name: "no-dnsconfig", name: "no-dnsconfig",

View File

@@ -231,7 +231,7 @@ func (bit *FlexibleBoolean) UnmarshalJSON(data []byte) error {
var val any var val any
err := json.Unmarshal(data, &val) err := json.Unmarshal(data, &val)
if err != nil { if err != nil {
return fmt.Errorf("could not unmarshal data: %w", err) return fmt.Errorf("unmarshalling data: %w", err)
} }
switch v := val.(type) { switch v := val.(type) {
@@ -240,12 +240,12 @@ func (bit *FlexibleBoolean) UnmarshalJSON(data []byte) error {
case string: case string:
pv, err := strconv.ParseBool(v) pv, err := strconv.ParseBool(v)
if err != nil { if err != nil {
return fmt.Errorf("could not parse %s as boolean: %w", v, err) return fmt.Errorf("parsing %s as boolean: %w", v, err)
} }
*bit = FlexibleBoolean(pv) *bit = FlexibleBoolean(pv)
default: default:
return fmt.Errorf("could not parse %v as boolean", v) return fmt.Errorf("parsing %v as boolean", v)
} }
return nil return nil

View File

@@ -5,6 +5,6 @@ import (
) )
var ( var (
ErrCannotDecryptResponse = errors.New("cannot decrypt response") ErrCannotDecryptResponse = errors.New("decrypting response")
ZstdCompression = "zstd" ZstdCompression = "zstd"
) )

View File

@@ -48,7 +48,7 @@ func ParseLoginURLFromCLILogin(output string) (*url.URL, error) {
loginURL, err := url.Parse(urlStr) loginURL, err := url.Parse(urlStr)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to parse URL: %w", err) return nil, fmt.Errorf("parsing URL: %w", err)
} }
return loginURL, nil return loginURL, nil

View File

@@ -75,7 +75,7 @@ func WithOrCreateNetwork(network *dockertest.Network) Option {
dsic.hostname+"-network", dsic.hostname+"-network",
) )
if err != nil { if err != nil {
log.Fatalf("failed to create network: %s", err) log.Fatalf("creating network: %s", err)
} }
dsic.networks = append(dsic.networks, network) dsic.networks = append(dsic.networks, network)
@@ -161,7 +161,7 @@ func New(
} }
tlsCert, tlsKey, err := integrationutil.CreateCertificate(hostname) tlsCert, tlsKey, err := integrationutil.CreateCertificate(hostname)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create certificates for headscale test: %w", err) return nil, fmt.Errorf("creating certificates for headscale test: %w", err)
} }
dsic := &DERPServerInContainer{ dsic := &DERPServerInContainer{
version: version, version: version,
@@ -243,7 +243,7 @@ func New(
) )
if err != nil { if err != nil {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"%s could not start tailscale DERPer container (version: %s): %w", "%s starting tailscale DERPer container (version: %s): %w",
hostname, hostname,
version, version,
err, err,
@@ -256,19 +256,19 @@ func New(
for i, cert := range dsic.caCerts { for i, cert := range dsic.caCerts {
err = dsic.WriteFile(fmt.Sprintf("%s/user-%d.crt", caCertRoot, i), cert) err = dsic.WriteFile(fmt.Sprintf("%s/user-%d.crt", caCertRoot, i), cert)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to write TLS certificate to container: %w", err) return nil, fmt.Errorf("writing TLS certificate to container: %w", err)
} }
} }
if len(dsic.tlsCert) != 0 { if len(dsic.tlsCert) != 0 {
err = dsic.WriteFile(fmt.Sprintf("%s/%s.crt", DERPerCertRoot, dsic.hostname), dsic.tlsCert) err = dsic.WriteFile(fmt.Sprintf("%s/%s.crt", DERPerCertRoot, dsic.hostname), dsic.tlsCert)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to write TLS certificate to container: %w", err) return nil, fmt.Errorf("writing TLS certificate to container: %w", err)
} }
} }
if len(dsic.tlsKey) != 0 { if len(dsic.tlsKey) != 0 {
err = dsic.WriteFile(fmt.Sprintf("%s/%s.key", DERPerCertRoot, dsic.hostname), dsic.tlsKey) err = dsic.WriteFile(fmt.Sprintf("%s/%s.key", DERPerCertRoot, dsic.hostname), dsic.tlsKey)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to write TLS key to container: %w", err) return nil, fmt.Errorf("writing TLS key to container: %w", err)
} }
} }
@@ -280,9 +280,9 @@ func (t *DERPServerInContainer) Shutdown() error {
err := t.SaveLog("/tmp/control") err := t.SaveLog("/tmp/control")
if err != nil { if err != nil {
log.Printf( log.Printf(
"Failed to save log from %s: %s", "saving log from %s: %s",
t.hostname, t.hostname,
fmt.Errorf("failed to save log: %w", err), fmt.Errorf("saving log: %w", err),
) )
} }
@@ -336,7 +336,7 @@ func (t *DERPServerInContainer) WaitForRunning() error {
return t.pool.Retry(func() error { return t.pool.Retry(func() error {
resp, err := client.Get(url) //nolint resp, err := client.Get(url) //nolint
if err != nil { if err != nil {
return fmt.Errorf("headscale is not ready: %w", err) return fmt.Errorf("DERPer is not ready: %w", err)
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {

View File

@@ -924,7 +924,7 @@ func oidcMockUser(username string, emailVerified bool) mockoidc.MockUser {
func GetUserByName(headscale ControlServer, username string) (*v1.User, error) { func GetUserByName(headscale ControlServer, username string) (*v1.User, error) {
users, err := headscale.ListUsers() users, err := headscale.ListUsers()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to list users: %w", err) return nil, fmt.Errorf("listing users: %w", err)
} }
for _, u := range users { for _, u := range users {
@@ -973,13 +973,13 @@ func (s *Scenario) AddAndLoginClient(
// Get the original client list // Get the original client list
originalClients, err := s.ListTailscaleClients(username) originalClients, err := s.ListTailscaleClients(username)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to list original clients: %w", err) return nil, fmt.Errorf("listing original clients: %w", err)
} }
// Create the new node // Create the new node
err = s.CreateTailscaleNodesInUser(username, version, 1, tsOpts...) err = s.CreateTailscaleNodesInUser(username, version, 1, tsOpts...)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create tailscale node: %w", err) return nil, fmt.Errorf("creating tailscale node: %w", err)
} }
// Wait for the new node to appear in the client list // Wait for the new node to appear in the client list
@@ -988,7 +988,7 @@ func (s *Scenario) AddAndLoginClient(
_, err = backoff.Retry(t.Context(), func() (struct{}, error) { _, err = backoff.Retry(t.Context(), func() (struct{}, error) {
updatedClients, err := s.ListTailscaleClients(username) updatedClients, err := s.ListTailscaleClients(username)
if err != nil { if err != nil {
return struct{}{}, fmt.Errorf("failed to list updated clients: %w", err) return struct{}{}, fmt.Errorf("listing updated clients: %w", err)
} }
if len(updatedClients) != len(originalClients)+1 { if len(updatedClients) != len(originalClients)+1 {
@@ -997,7 +997,7 @@ func (s *Scenario) AddAndLoginClient(
newClient, err = FindNewClient(originalClients, updatedClients) newClient, err = FindNewClient(originalClients, updatedClients)
if err != nil { if err != nil {
return struct{}{}, fmt.Errorf("failed to find new client: %w", err) return struct{}{}, fmt.Errorf("finding new client: %w", err)
} }
return struct{}{}, nil return struct{}{}, nil
@@ -1009,18 +1009,18 @@ func (s *Scenario) AddAndLoginClient(
// Get the user and create preauth key // Get the user and create preauth key
user, err := GetUserByName(headscale, username) user, err := GetUserByName(headscale, username)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get user: %w", err) return nil, fmt.Errorf("getting user: %w", err)
} }
authKey, err := s.CreatePreAuthKey(user.GetId(), true, false) authKey, err := s.CreatePreAuthKey(user.GetId(), true, false)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create preauth key: %w", err) return nil, fmt.Errorf("creating preauth key: %w", err)
} }
// Login the new client // Login the new client
err = newClient.Login(headscale.GetEndpoint(), authKey.GetKey()) err = newClient.Login(headscale.GetEndpoint(), authKey.GetKey())
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to login new client: %w", err) return nil, fmt.Errorf("logging in new client: %w", err)
} }
return newClient, nil return newClient, nil

View File

@@ -117,7 +117,7 @@ func WithTLS() Option {
return func(hsic *HeadscaleInContainer) { return func(hsic *HeadscaleInContainer) {
cert, key, err := integrationutil.CreateCertificate(hsic.hostname) cert, key, err := integrationutil.CreateCertificate(hsic.hostname)
if err != nil { if err != nil {
log.Fatalf("failed to create certificates for headscale test: %s", err) log.Fatalf("creating certificates for headscale test: %s", err)
} }
hsic.tlsCert = cert hsic.tlsCert = cert
@@ -239,7 +239,7 @@ func WithDERPConfig(derpMap tailcfg.DERPMap) Option {
return func(hsic *HeadscaleInContainer) { return func(hsic *HeadscaleInContainer) {
contents, err := yaml.Marshal(derpMap) contents, err := yaml.Marshal(derpMap)
if err != nil { if err != nil {
log.Fatalf("failed to marshal DERP map: %s", err) log.Fatalf("marshalling DERP map: %s", err)
return return
} }
@@ -504,7 +504,7 @@ func New(
dockertestutil.DockerAllowNetworkAdministration, dockertestutil.DockerAllowNetworkAdministration,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("could not run pre-built headscale container %q: %w", prebuiltImage, err) return nil, fmt.Errorf("running pre-built headscale container %q: %w", prebuiltImage, err)
} }
} else if util.IsCI() { } else if util.IsCI() {
return nil, errHeadscaleImageRequiredInCI return nil, errHeadscaleImageRequiredInCI
@@ -536,16 +536,16 @@ func New(
if buildErr != nil { if buildErr != nil {
// The diagnostic build also failed - this is the real error // The diagnostic build also failed - this is the real error
return nil, fmt.Errorf("could not start headscale container: %w\n\nDocker build failed. Last %d lines of output:\n%s", err, maxLines, relevantOutput) return nil, fmt.Errorf("starting headscale container: %w\n\nDocker build failed. Last %d lines of output:\n%s", err, maxLines, relevantOutput)
} }
if buildOutput != "" { if buildOutput != "" {
// Build succeeded on retry but container creation still failed // Build succeeded on retry but container creation still failed
return nil, fmt.Errorf("could not start headscale container: %w\n\nDocker build succeeded on retry, but container creation failed. Last %d lines of build output:\n%s", err, maxLines, relevantOutput) return nil, fmt.Errorf("starting headscale container: %w\n\nDocker build succeeded on retry, but container creation failed. Last %d lines of build output:\n%s", err, maxLines, relevantOutput)
} }
// No output at all - diagnostic build command may have failed // No output at all - diagnostic build command may have failed
return nil, fmt.Errorf("could not start headscale container: %w\n\nUnable to get diagnostic build output (command may have failed silently)", err) return nil, fmt.Errorf("starting headscale container: %w\n\nUnable to get diagnostic build output (command may have failed silently)", err)
} }
} }
log.Printf("Created %s container\n", hsic.hostname) log.Printf("Created %s container\n", hsic.hostname)
@@ -566,13 +566,13 @@ func New(
for i, cert := range hsic.caCerts { for i, cert := range hsic.caCerts {
err = hsic.WriteFile(fmt.Sprintf("%s/user-%d.crt", caCertRoot, i), cert) err = hsic.WriteFile(fmt.Sprintf("%s/user-%d.crt", caCertRoot, i), cert)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to write TLS certificate to container: %w", err) return nil, fmt.Errorf("writing TLS certificate to container: %w", err)
} }
} }
err = hsic.WriteFile("/etc/headscale/config.yaml", []byte(MinimumConfigYAML())) err = hsic.WriteFile("/etc/headscale/config.yaml", []byte(MinimumConfigYAML()))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to write headscale config to container: %w", err) return nil, fmt.Errorf("writing headscale config to container: %w", err)
} }
if hsic.aclPolicy != nil { if hsic.aclPolicy != nil {
@@ -585,18 +585,18 @@ func New(
if hsic.hasTLS() { if hsic.hasTLS() {
err = hsic.WriteFile(tlsCertPath, hsic.tlsCert) err = hsic.WriteFile(tlsCertPath, hsic.tlsCert)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to write TLS certificate to container: %w", err) return nil, fmt.Errorf("writing TLS certificate to container: %w", err)
} }
err = hsic.WriteFile(tlsKeyPath, hsic.tlsKey) err = hsic.WriteFile(tlsKeyPath, hsic.tlsKey)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to write TLS key to container: %w", err) return nil, fmt.Errorf("writing TLS key to container: %w", err)
} }
} }
for _, f := range hsic.filesInContainer { for _, f := range hsic.filesInContainer {
if err := hsic.WriteFile(f.path, f.contents); err != nil { if err := hsic.WriteFile(f.path, f.contents); err != nil {
return nil, fmt.Errorf("failed to write %q: %w", f.path, err) return nil, fmt.Errorf("writing %q: %w", f.path, err)
} }
} }
@@ -625,15 +625,15 @@ func (t *HeadscaleInContainer) Shutdown() (string, string, error) {
stdoutPath, stderrPath, err := t.SaveLog("/tmp/control") stdoutPath, stderrPath, err := t.SaveLog("/tmp/control")
if err != nil { if err != nil {
log.Printf( log.Printf(
"Failed to save log from control: %s", "saving log from control: %s",
fmt.Errorf("failed to save log from control: %w", err), fmt.Errorf("saving log from control: %w", err),
) )
} }
err = t.SaveMetrics(fmt.Sprintf("/tmp/control/%s_metrics.txt", t.hostname)) err = t.SaveMetrics(fmt.Sprintf("/tmp/control/%s_metrics.txt", t.hostname))
if err != nil { if err != nil {
log.Printf( log.Printf(
"Failed to metrics from control: %s", "saving metrics from control: %s",
err, err,
) )
} }
@@ -644,24 +644,24 @@ func (t *HeadscaleInContainer) Shutdown() (string, string, error) {
err = t.SendInterrupt() err = t.SendInterrupt()
if err != nil { if err != nil {
log.Printf( log.Printf(
"Failed to send graceful interrupt to control: %s", "sending graceful interrupt to control: %s",
fmt.Errorf("failed to send graceful interrupt to control: %w", err), fmt.Errorf("sending graceful interrupt to control: %w", err),
) )
} }
err = t.SaveProfile("/tmp/control") err = t.SaveProfile("/tmp/control")
if err != nil { if err != nil {
log.Printf( log.Printf(
"Failed to save profile from control: %s", "saving profile from control: %s",
fmt.Errorf("failed to save profile from control: %w", err), fmt.Errorf("saving profile from control: %w", err),
) )
} }
err = t.SaveMapResponses("/tmp/control") err = t.SaveMapResponses("/tmp/control")
if err != nil { if err != nil {
log.Printf( log.Printf(
"Failed to save mapresponses from control: %s", "saving mapresponses from control: %s",
fmt.Errorf("failed to save mapresponses from control: %w", err), fmt.Errorf("saving mapresponses from control: %w", err),
) )
} }
@@ -670,8 +670,8 @@ func (t *HeadscaleInContainer) Shutdown() (string, string, error) {
err = t.SaveDatabase("/tmp/control") err = t.SaveDatabase("/tmp/control")
if err != nil { if err != nil {
log.Printf( log.Printf(
"Failed to save database from control: %s", "saving database from control: %s",
fmt.Errorf("failed to save database from control: %w", err), fmt.Errorf("saving database from control: %w", err),
) )
} }
} }
@@ -718,7 +718,7 @@ func (t *HeadscaleInContainer) SaveMetrics(savePath string) error {
// extractTarToDirectory extracts a tar archive to a directory. // extractTarToDirectory extracts a tar archive to a directory.
func extractTarToDirectory(tarData []byte, targetDir string) error { func extractTarToDirectory(tarData []byte, targetDir string) error {
if err := os.MkdirAll(targetDir, 0o755); err != nil { if err := os.MkdirAll(targetDir, 0o755); err != nil {
return fmt.Errorf("failed to create directory %s: %w", targetDir, err) return fmt.Errorf("creating directory %s: %w", targetDir, err)
} }
tarReader := tar.NewReader(bytes.NewReader(tarData)) tarReader := tar.NewReader(bytes.NewReader(tarData))
@@ -732,7 +732,7 @@ func extractTarToDirectory(tarData []byte, targetDir string) error {
break break
} }
if err != nil { if err != nil {
return fmt.Errorf("failed to read tar header: %w", err) return fmt.Errorf("reading tar header: %w", err)
} }
if header.Typeflag == tar.TypeDir && topLevelDir == "" { if header.Typeflag == tar.TypeDir && topLevelDir == "" {
@@ -748,7 +748,7 @@ func extractTarToDirectory(tarData []byte, targetDir string) error {
break break
} }
if err != nil { if err != nil {
return fmt.Errorf("failed to read tar header: %w", err) return fmt.Errorf("reading tar header: %w", err)
} }
// Clean the path to prevent directory traversal // Clean the path to prevent directory traversal
@@ -776,29 +776,29 @@ func extractTarToDirectory(tarData []byte, targetDir string) error {
case tar.TypeDir: case tar.TypeDir:
// Create directory // Create directory
if err := os.MkdirAll(targetPath, os.FileMode(header.Mode)); err != nil { if err := os.MkdirAll(targetPath, os.FileMode(header.Mode)); err != nil {
return fmt.Errorf("failed to create directory %s: %w", targetPath, err) return fmt.Errorf("creating directory %s: %w", targetPath, err)
} }
case tar.TypeReg: case tar.TypeReg:
// Ensure parent directories exist // Ensure parent directories exist
if err := os.MkdirAll(filepath.Dir(targetPath), 0o755); err != nil { if err := os.MkdirAll(filepath.Dir(targetPath), 0o755); err != nil {
return fmt.Errorf("failed to create parent directories for %s: %w", targetPath, err) return fmt.Errorf("creating parent directories for %s: %w", targetPath, err)
} }
// Create file // Create file
outFile, err := os.Create(targetPath) outFile, err := os.Create(targetPath)
if err != nil { if err != nil {
return fmt.Errorf("failed to create file %s: %w", targetPath, err) return fmt.Errorf("creating file %s: %w", targetPath, err)
} }
if _, err := io.Copy(outFile, tarReader); err != nil { if _, err := io.Copy(outFile, tarReader); err != nil {
outFile.Close() outFile.Close()
return fmt.Errorf("failed to copy file contents: %w", err) return fmt.Errorf("copying file contents: %w", err)
} }
outFile.Close() outFile.Close()
// Set file permissions // Set file permissions
if err := os.Chmod(targetPath, os.FileMode(header.Mode)); err != nil { if err := os.Chmod(targetPath, os.FileMode(header.Mode)); err != nil {
return fmt.Errorf("failed to set file permissions: %w", err) return fmt.Errorf("setting file permissions: %w", err)
} }
} }
} }
@@ -853,7 +853,7 @@ func (t *HeadscaleInContainer) SaveDatabase(savePath string) error {
// Check if the database has any tables (schema) // Check if the database has any tables (schema)
schemaCheck, err := t.Execute([]string{"sqlite3", dbPath, ".schema"}) schemaCheck, err := t.Execute([]string{"sqlite3", dbPath, ".schema"})
if err != nil { if err != nil {
return fmt.Errorf("failed to check database schema (sqlite3 command failed): %w", err) return fmt.Errorf("checking database schema (sqlite3 command failed): %w", err)
} }
if strings.TrimSpace(schemaCheck) == "" { if strings.TrimSpace(schemaCheck) == "" {
@@ -862,7 +862,7 @@ func (t *HeadscaleInContainer) SaveDatabase(savePath string) error {
tarFile, err := t.FetchPath("/tmp/integration_test_db.sqlite3") tarFile, err := t.FetchPath("/tmp/integration_test_db.sqlite3")
if err != nil { if err != nil {
return fmt.Errorf("failed to fetch database file: %w", err) return fmt.Errorf("fetching database file: %w", err)
} }
// For database, extract the first regular file (should be the SQLite file) // For database, extract the first regular file (should be the SQLite file)
@@ -873,7 +873,7 @@ func (t *HeadscaleInContainer) SaveDatabase(savePath string) error {
break break
} }
if err != nil { if err != nil {
return fmt.Errorf("failed to read tar header: %w", err) return fmt.Errorf("reading tar header: %w", err)
} }
log.Printf( log.Printf(
@@ -888,13 +888,13 @@ func (t *HeadscaleInContainer) SaveDatabase(savePath string) error {
dbPath := path.Join(savePath, t.hostname+".db") dbPath := path.Join(savePath, t.hostname+".db")
outFile, err := os.Create(dbPath) outFile, err := os.Create(dbPath)
if err != nil { if err != nil {
return fmt.Errorf("failed to create database file: %w", err) return fmt.Errorf("creating database file: %w", err)
} }
written, err := io.Copy(outFile, tarReader) written, err := io.Copy(outFile, tarReader)
outFile.Close() outFile.Close()
if err != nil { if err != nil {
return fmt.Errorf("failed to copy database file: %w", err) return fmt.Errorf("copying database file: %w", err)
} }
log.Printf( log.Printf(
@@ -1061,7 +1061,7 @@ func (t *HeadscaleInContainer) CreateUser(
var u v1.User var u v1.User
err = json.Unmarshal([]byte(result), &u) err = json.Unmarshal([]byte(result), &u)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to unmarshal user: %w", err) return nil, fmt.Errorf("unmarshalling user: %w", err)
} }
return &u, nil return &u, nil
@@ -1119,14 +1119,14 @@ func (t *HeadscaleInContainer) CreateAuthKeyWithOptions(opts AuthKeyOptions) (*v
[]string{}, []string{},
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to execute create auth key command: %w", err) return nil, fmt.Errorf("executing create auth key command: %w", err)
} }
var preAuthKey v1.PreAuthKey var preAuthKey v1.PreAuthKey
err = json.Unmarshal([]byte(result), &preAuthKey) err = json.Unmarshal([]byte(result), &preAuthKey)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to unmarshal auth key: %w", err) return nil, fmt.Errorf("unmarshalling auth key: %w", err)
} }
return &preAuthKey, nil return &preAuthKey, nil
@@ -1182,7 +1182,7 @@ func (t *HeadscaleInContainer) DeleteAuthKey(
[]string{}, []string{},
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to execute delete auth key command: %w", err) return fmt.Errorf("executing delete auth key command: %w", err)
} }
return nil return nil
@@ -1202,13 +1202,13 @@ func (t *HeadscaleInContainer) ListNodes(
[]string{}, []string{},
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to execute list node command: %w", err) return fmt.Errorf("executing list node command: %w", err)
} }
var nodes []*v1.Node var nodes []*v1.Node
err = json.Unmarshal([]byte(result), &nodes) err = json.Unmarshal([]byte(result), &nodes)
if err != nil { if err != nil {
return fmt.Errorf("failed to unmarshal nodes: %w", err) return fmt.Errorf("unmarshalling nodes: %w", err)
} }
ret = append(ret, nodes...) ret = append(ret, nodes...)
@@ -1257,7 +1257,7 @@ func (t *HeadscaleInContainer) DeleteNode(nodeID uint64) error {
[]string{}, []string{},
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to execute delete node command: %w", err) return fmt.Errorf("executing delete node command: %w", err)
} }
return nil return nil
@@ -1305,13 +1305,13 @@ func (t *HeadscaleInContainer) ListUsers() ([]*v1.User, error) {
[]string{}, []string{},
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to execute list node command: %w", err) return nil, fmt.Errorf("executing list node command: %w", err)
} }
var users []*v1.User var users []*v1.User
err = json.Unmarshal([]byte(result), &users) err = json.Unmarshal([]byte(result), &users)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to unmarshal nodes: %w", err) return nil, fmt.Errorf("unmarshalling nodes: %w", err)
} }
return users, nil return users, nil
@@ -1352,7 +1352,7 @@ func (t *HeadscaleInContainer) DeleteUser(userID uint64) error {
[]string{}, []string{},
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to execute delete user command: %w", err) return fmt.Errorf("executing delete user command: %w", err)
} }
return nil return nil
@@ -1402,7 +1402,7 @@ func (h *HeadscaleInContainer) reloadDatabasePolicy() error {
func (h *HeadscaleInContainer) writePolicy(pol *policyv2.Policy) error { func (h *HeadscaleInContainer) writePolicy(pol *policyv2.Policy) error {
pBytes, err := json.Marshal(pol) pBytes, err := json.Marshal(pol)
if err != nil { if err != nil {
return fmt.Errorf("marshalling pol: %w", err) return fmt.Errorf("marshalling policy: %w", err)
} }
err = h.WriteFile(aclPolicyPath, pBytes) err = h.WriteFile(aclPolicyPath, pBytes)
@@ -1486,7 +1486,7 @@ func (t *HeadscaleInContainer) ApproveRoutes(id uint64, routes []netip.Prefix) (
) )
if err != nil { if err != nil {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"failed to execute approve routes command (node %d, routes %v): %w", "executing approve routes command (node %d, routes %v): %w",
id, id,
routes, routes,
err, err,
@@ -1496,7 +1496,7 @@ func (t *HeadscaleInContainer) ApproveRoutes(id uint64, routes []netip.Prefix) (
var node *v1.Node var node *v1.Node
err = json.Unmarshal([]byte(result), &node) err = json.Unmarshal([]byte(result), &node)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to unmarshal node response: %q, error: %w", result, err) return nil, fmt.Errorf("unmarshalling node response: %q, error: %w", result, err)
} }
return node, nil return node, nil
@@ -1526,7 +1526,7 @@ func (t *HeadscaleInContainer) SetNodeTags(nodeID uint64, tags []string) error {
[]string{}, []string{},
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to execute set tags command (node %d, tags %v): %w", nodeID, tags, err) return fmt.Errorf("executing set tags command (node %d, tags %v): %w", nodeID, tags, err)
} }
return nil return nil

View File

@@ -59,17 +59,17 @@ func WriteFileToContainer(
err := tarWriter.WriteHeader(header) err := tarWriter.WriteHeader(header)
if err != nil { if err != nil {
return fmt.Errorf("failed write file header to tar: %w", err) return fmt.Errorf("writing file header to tar: %w", err)
} }
_, err = io.Copy(tarWriter, file) _, err = io.Copy(tarWriter, file)
if err != nil { if err != nil {
return fmt.Errorf("failed to copy file to tar: %w", err) return fmt.Errorf("copying file to tar: %w", err)
} }
err = tarWriter.Close() err = tarWriter.Close()
if err != nil { if err != nil {
return fmt.Errorf("failed to close tar: %w", err) return fmt.Errorf("closing tar: %w", err)
} }
// Ensure the directory is present inside the container // Ensure the directory is present inside the container
@@ -79,7 +79,7 @@ func WriteFileToContainer(
[]string{}, []string{},
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to ensure directory: %w", err) return fmt.Errorf("ensuring directory: %w", err)
} }
err = pool.Client.UploadToContainer( err = pool.Client.UploadToContainer(

View File

@@ -163,7 +163,7 @@ func (s *Scenario) prefixedNetworkName(name string) string {
func NewScenario(spec ScenarioSpec) (*Scenario, error) { func NewScenario(spec ScenarioSpec) (*Scenario, error) {
pool, err := dockertest.NewPool("") pool, err := dockertest.NewPool("")
if err != nil { if err != nil {
return nil, fmt.Errorf("could not connect to docker: %w", err) return nil, fmt.Errorf("connecting to docker: %w", err)
} }
// Opportunity to clean up unreferenced networks. // Opportunity to clean up unreferenced networks.
@@ -242,7 +242,7 @@ func NewScenario(spec ScenarioSpec) (*Scenario, error) {
func (s *Scenario) AddNetwork(name string) (*dockertest.Network, error) { func (s *Scenario) AddNetwork(name string) (*dockertest.Network, error) {
network, err := dockertestutil.GetFirstOrCreateNetwork(s.pool, name) network, err := dockertestutil.GetFirstOrCreateNetwork(s.pool, name)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create or get network: %w", err) return nil, fmt.Errorf("creating or getting network: %w", err)
} }
// We run the test suite in a docker container that calls a couple of endpoints for // We run the test suite in a docker container that calls a couple of endpoints for
@@ -256,7 +256,7 @@ func (s *Scenario) AddNetwork(name string) (*dockertest.Network, error) {
err = dockertestutil.AddContainerToNetwork(s.pool, network, testSuiteName) err = dockertestutil.AddContainerToNetwork(s.pool, network, testSuiteName)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to add test suite container to network: %w", err) return nil, fmt.Errorf("adding test suite container to network: %w", err)
} }
mak.Set(&s.networks, name, network) mak.Set(&s.networks, name, network)
@@ -315,8 +315,8 @@ func (s *Scenario) ShutdownAssertNoPanics(t *testing.T) {
stdoutPath, stderrPath, err := control.Shutdown() stdoutPath, stderrPath, err := control.Shutdown()
if err != nil { if err != nil {
log.Printf( log.Printf(
"Failed to shut down control: %s", "shutting down control: %s",
fmt.Errorf("failed to tear down control: %w", err), fmt.Errorf("tearing down control: %w", err),
) )
} }
@@ -339,7 +339,7 @@ func (s *Scenario) ShutdownAssertNoPanics(t *testing.T) {
log.Printf("removing client %s in user %s", client.Hostname(), userName) log.Printf("removing client %s in user %s", client.Hostname(), userName)
stdoutPath, stderrPath, err := client.Shutdown() stdoutPath, stderrPath, err := client.Shutdown()
if err != nil { if err != nil {
log.Printf("failed to tear down client: %s", err) log.Printf("tearing down client: %s", err)
} }
if t != nil { if t != nil {
@@ -358,7 +358,7 @@ func (s *Scenario) ShutdownAssertNoPanics(t *testing.T) {
for _, derp := range s.derpServers { for _, derp := range s.derpServers {
err := derp.Shutdown() err := derp.Shutdown()
if err != nil { if err != nil {
log.Printf("failed to tear down derp server: %s", err) log.Printf("tearing down derp server: %s", err)
} }
} }
@@ -366,7 +366,7 @@ func (s *Scenario) ShutdownAssertNoPanics(t *testing.T) {
for _, svc := range svcs { for _, svc := range svcs {
err := svc.Close() err := svc.Close()
if err != nil { if err != nil {
log.Printf("failed to tear down service %q: %s", svc.Container.Name, err) log.Printf("tearing down service %q: %s", svc.Container.Name, err)
} }
} }
} }
@@ -374,13 +374,13 @@ func (s *Scenario) ShutdownAssertNoPanics(t *testing.T) {
if s.mockOIDC.r != nil { if s.mockOIDC.r != nil {
s.mockOIDC.r.Close() s.mockOIDC.r.Close()
if err := s.mockOIDC.r.Close(); err != nil { if err := s.mockOIDC.r.Close(); err != nil {
log.Printf("failed to tear down oidc server: %s", err) log.Printf("tearing down oidc server: %s", err)
} }
} }
for _, network := range s.networks { for _, network := range s.networks {
if err := network.Close(); err != nil { if err := network.Close(); err != nil {
log.Printf("failed to tear down network: %s", err) log.Printf("tearing down network: %s", err)
} }
} }
} }
@@ -424,12 +424,12 @@ func (s *Scenario) Headscale(opts ...hsic.Option) (ControlServer, error) {
headscale, err := hsic.New(s.pool, s.Networks(), opts...) headscale, err := hsic.New(s.pool, s.Networks(), opts...)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create headscale container: %w", err) return nil, fmt.Errorf("creating headscale container: %w", err)
} }
err = headscale.WaitForRunning() err = headscale.WaitForRunning()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed reach headscale container: %w", err) return nil, fmt.Errorf("reaching headscale container: %w", err)
} }
s.controlServers.Store("headscale", headscale) s.controlServers.Store("headscale", headscale)
@@ -469,13 +469,13 @@ func (s *Scenario) CreatePreAuthKey(
if headscale, err := s.Headscale(); err == nil { if headscale, err := s.Headscale(); err == nil {
key, err := headscale.CreateAuthKey(user, reusable, ephemeral) key, err := headscale.CreateAuthKey(user, reusable, ephemeral)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create user: %w", err) return nil, fmt.Errorf("creating user: %w", err)
} }
return key, nil return key, nil
} }
return nil, fmt.Errorf("failed to create user: %w", errNoHeadscaleAvailable) return nil, fmt.Errorf("creating user: %w", errNoHeadscaleAvailable)
} }
// CreatePreAuthKeyWithOptions creates a "pre authorised key" with the specified options // CreatePreAuthKeyWithOptions creates a "pre authorised key" with the specified options
@@ -483,12 +483,12 @@ func (s *Scenario) CreatePreAuthKey(
func (s *Scenario) CreatePreAuthKeyWithOptions(opts hsic.AuthKeyOptions) (*v1.PreAuthKey, error) { func (s *Scenario) CreatePreAuthKeyWithOptions(opts hsic.AuthKeyOptions) (*v1.PreAuthKey, error) {
headscale, err := s.Headscale() headscale, err := s.Headscale()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create preauth key with options: %w", errNoHeadscaleAvailable) return nil, fmt.Errorf("creating preauth key with options: %w", errNoHeadscaleAvailable)
} }
key, err := headscale.CreateAuthKeyWithOptions(opts) key, err := headscale.CreateAuthKeyWithOptions(opts)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create preauth key with options: %w", err) return nil, fmt.Errorf("creating preauth key with options: %w", err)
} }
return key, nil return key, nil
@@ -504,12 +504,12 @@ func (s *Scenario) CreatePreAuthKeyWithTags(
) (*v1.PreAuthKey, error) { ) (*v1.PreAuthKey, error) {
headscale, err := s.Headscale() headscale, err := s.Headscale()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create preauth key with tags: %w", errNoHeadscaleAvailable) return nil, fmt.Errorf("creating preauth key with tags: %w", errNoHeadscaleAvailable)
} }
key, err := headscale.CreateAuthKeyWithTags(user, reusable, ephemeral, tags) key, err := headscale.CreateAuthKeyWithTags(user, reusable, ephemeral, tags)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create preauth key with tags: %w", err) return nil, fmt.Errorf("creating preauth key with tags: %w", err)
} }
return key, nil return key, nil
@@ -521,7 +521,7 @@ func (s *Scenario) CreateUser(user string) (*v1.User, error) {
if headscale, err := s.Headscale(); err == nil { if headscale, err := s.Headscale(); err == nil {
u, err := headscale.CreateUser(user) u, err := headscale.CreateUser(user)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create user: %w", err) return nil, fmt.Errorf("creating user: %w", err)
} }
s.mu.Lock() s.mu.Lock()
@@ -533,7 +533,7 @@ func (s *Scenario) CreateUser(user string) (*v1.User, error) {
return u, nil return u, nil
} }
return nil, fmt.Errorf("failed to create user: %w", errNoHeadscaleAvailable) return nil, fmt.Errorf("creating user: %w", errNoHeadscaleAvailable)
} }
/// Client related stuff /// Client related stuff
@@ -544,7 +544,7 @@ func (s *Scenario) CreateTailscaleNode(
) (TailscaleClient, error) { ) (TailscaleClient, error) {
headscale, err := s.Headscale() headscale, err := s.Headscale()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create tailscale node (version: %s): %w", version, err) return nil, fmt.Errorf("creating tailscale node (version: %s): %w", version, err)
} }
cert := headscale.GetCert() cert := headscale.GetCert()
@@ -564,7 +564,7 @@ func (s *Scenario) CreateTailscaleNode(
) )
if err != nil { if err != nil {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"failed to create tailscale node: %w", "creating tailscale node: %w",
err, err,
) )
} }
@@ -572,7 +572,7 @@ func (s *Scenario) CreateTailscaleNode(
err = tsClient.WaitForNeedsLogin(integrationutil.PeerSyncTimeout()) err = tsClient.WaitForNeedsLogin(integrationutil.PeerSyncTimeout())
if err != nil { if err != nil {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"failed to wait for tailscaled (%s) to need login: %w", "waiting for tailscaled (%s) to need login: %w",
tsClient.Hostname(), tsClient.Hostname(),
err, err,
) )
@@ -604,7 +604,7 @@ func (s *Scenario) CreateTailscaleNodesInUser(
headscale, err := s.Headscale() headscale, err := s.Headscale()
if err != nil { if err != nil {
return fmt.Errorf("failed to create tailscale node (version: %s): %w", version, err) return fmt.Errorf("creating tailscale node (version: %s): %w", version, err)
} }
cert := headscale.GetCert() cert := headscale.GetCert()
@@ -641,7 +641,7 @@ func (s *Scenario) CreateTailscaleNodesInUser(
s.mu.Unlock() s.mu.Unlock()
if err != nil { if err != nil {
return fmt.Errorf( return fmt.Errorf(
"failed to create tailscale node: %w", "creating tailscale node: %w",
err, err,
) )
} }
@@ -649,7 +649,7 @@ func (s *Scenario) CreateTailscaleNodesInUser(
err = tsClient.WaitForNeedsLogin(integrationutil.PeerSyncTimeout()) err = tsClient.WaitForNeedsLogin(integrationutil.PeerSyncTimeout())
if err != nil { if err != nil {
return fmt.Errorf( return fmt.Errorf(
"failed to wait for tailscaled (%s) to need login: %w", "waiting for tailscaled (%s) to need login: %w",
tsClient.Hostname(), tsClient.Hostname(),
err, err,
) )
@@ -671,7 +671,7 @@ func (s *Scenario) CreateTailscaleNodesInUser(
return nil return nil
} }
return fmt.Errorf("failed to add tailscale node: %w", errNoUserAvailable) return fmt.Errorf("adding tailscale node: %w", errNoUserAvailable)
} }
// RunTailscaleUp will log in all of the TailscaleClients associated with a // RunTailscaleUp will log in all of the TailscaleClients associated with a
@@ -694,14 +694,14 @@ func (s *Scenario) RunTailscaleUp(
for _, client := range user.Clients { for _, client := range user.Clients {
err := client.WaitForRunning(integrationutil.PeerSyncTimeout()) err := client.WaitForRunning(integrationutil.PeerSyncTimeout())
if err != nil { if err != nil {
return fmt.Errorf("%s failed to up tailscale node: %w", client.Hostname(), err) return fmt.Errorf("%s bringing up tailscale node: %w", client.Hostname(), err)
} }
} }
return nil return nil
} }
return fmt.Errorf("failed to up tailscale node: %w", errNoUserAvailable) return fmt.Errorf("bringing up tailscale node: %w", errNoUserAvailable)
} }
// CountTailscale returns the total number of TailscaleClients in a Scenario. // CountTailscale returns the total number of TailscaleClients in a Scenario.
@@ -893,7 +893,7 @@ func (s *Scenario) RunTailscaleUpWithURL(userStr, loginServer string) error {
user.joinWaitGroup.Go(func() error { user.joinWaitGroup.Go(func() error {
loginURL, err := tsc.LoginWithURL(loginServer) loginURL, err := tsc.LoginWithURL(loginServer)
if err != nil { if err != nil {
log.Printf("%s failed to run tailscale up: %s", tsc.Hostname(), err) log.Printf("%s running tailscale up: %s", tsc.Hostname(), err)
} }
body, err := doLoginURL(tsc.Hostname(), loginURL) body, err := doLoginURL(tsc.Hostname(), loginURL)
@@ -931,7 +931,7 @@ func (s *Scenario) RunTailscaleUpWithURL(userStr, loginServer string) error {
return nil return nil
} }
return fmt.Errorf("failed to up tailscale node: %w", errNoUserAvailable) return fmt.Errorf("bringing up tailscale node: %w", errNoUserAvailable)
} }
type debugJar struct { type debugJar struct {
@@ -1013,7 +1013,7 @@ func newLoginHTTPClient(hostname string) (*http.Client, error) {
jar, err := newDebugJar() jar, err := newDebugJar()
if err != nil { if err != nil {
return nil, fmt.Errorf("%s failed to create cookiejar: %w", hostname, err) return nil, fmt.Errorf("%s creating cookiejar: %w", hostname, err)
} }
hc.Jar = jar hc.Jar = jar
@@ -1057,7 +1057,7 @@ func doLoginURLWithClient(hostname string, loginURL *url.URL, hc *http.Client, f
ctx := context.Background() ctx := context.Background()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, loginURL.String(), nil) req, err := http.NewRequestWithContext(ctx, http.MethodGet, loginURL.String(), nil)
if err != nil { if err != nil {
return "", nil, fmt.Errorf("%s failed to create http request: %w", hostname, err) return "", nil, fmt.Errorf("%s creating http request: %w", hostname, err)
} }
originalRedirect := hc.CheckRedirect originalRedirect := hc.CheckRedirect
@@ -1072,13 +1072,13 @@ func doLoginURLWithClient(hostname string, loginURL *url.URL, hc *http.Client, f
resp, err := hc.Do(req) resp, err := hc.Do(req)
if err != nil { if err != nil {
return "", nil, fmt.Errorf("%s failed to send http request: %w", hostname, err) return "", nil, fmt.Errorf("%s sending http request: %w", hostname, err)
} }
defer resp.Body.Close() defer resp.Body.Close()
bodyBytes, err := io.ReadAll(resp.Body) bodyBytes, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
return "", nil, fmt.Errorf("%s failed to read response body: %w", hostname, err) return "", nil, fmt.Errorf("%s reading response body: %w", hostname, err)
} }
body := string(bodyBytes) body := string(bodyBytes)
@@ -1086,7 +1086,7 @@ func doLoginURLWithClient(hostname string, loginURL *url.URL, hc *http.Client, f
if resp.StatusCode >= http.StatusMultipleChoices && resp.StatusCode < http.StatusBadRequest { if resp.StatusCode >= http.StatusMultipleChoices && resp.StatusCode < http.StatusBadRequest {
redirectURL, err = resp.Location() redirectURL, err = resp.Location()
if err != nil { if err != nil {
return body, nil, fmt.Errorf("%s failed to resolve redirect location: %w", hostname, err) return body, nil, fmt.Errorf("%s resolving redirect location: %w", hostname, err)
} }
} }
@@ -1113,7 +1113,7 @@ func doLoginURLWithClient(hostname string, loginURL *url.URL, hc *http.Client, f
return body, redirectURL, nil return body, redirectURL, nil
} }
var errParseAuthPage = errors.New("failed to parse auth page") var errParseAuthPage = errors.New("parsing auth page")
func (s *Scenario) runHeadscaleRegister(userStr string, body string) error { func (s *Scenario) runHeadscaleRegister(userStr string, body string) error {
// see api.go HTML template // see api.go HTML template
@@ -1135,7 +1135,7 @@ func (s *Scenario) runHeadscaleRegister(userStr string, body string) error {
[]string{"headscale", "nodes", "register", "--user", userStr, "--key", key}, []string{"headscale", "nodes", "register", "--user", userStr, "--key", key},
) )
if err != nil { if err != nil {
log.Printf("failed to register node: %s", err) log.Printf("registering node: %s", err)
return err return err
} }
@@ -1143,7 +1143,7 @@ func (s *Scenario) runHeadscaleRegister(userStr string, body string) error {
return nil return nil
} }
return fmt.Errorf("failed to find headscale: %w", errNoHeadscaleAvailable) return fmt.Errorf("finding headscale: %w", errNoHeadscaleAvailable)
} }
type LoggingRoundTripper struct { type LoggingRoundTripper struct {
@@ -1177,7 +1177,7 @@ func (s *Scenario) GetIPs(user string) ([]netip.Addr, error) {
for _, client := range ns.Clients { for _, client := range ns.Clients {
clientIps, err := client.IPs() clientIps, err := client.IPs()
if err != nil { if err != nil {
return ips, fmt.Errorf("failed to get ips: %w", err) return ips, fmt.Errorf("getting IPs: %w", err)
} }
ips = append(ips, clientIps...) ips = append(ips, clientIps...)
} }
@@ -1185,7 +1185,7 @@ func (s *Scenario) GetIPs(user string) ([]netip.Addr, error) {
return ips, nil return ips, nil
} }
return ips, fmt.Errorf("failed to get ips: %w", errNoUserAvailable) return ips, fmt.Errorf("getting IPs: %w", errNoUserAvailable)
} }
// GetClients returns all TailscaleClients associated with a User in a Scenario. // GetClients returns all TailscaleClients associated with a User in a Scenario.
@@ -1199,7 +1199,7 @@ func (s *Scenario) GetClients(user string) ([]TailscaleClient, error) {
return clients, nil return clients, nil
} }
return clients, fmt.Errorf("failed to get clients: %w", errNoUserAvailable) return clients, fmt.Errorf("getting clients: %w", errNoUserAvailable)
} }
// ListTailscaleClients returns a list of TailscaleClients given the Users // ListTailscaleClients returns a list of TailscaleClients given the Users
@@ -1306,12 +1306,12 @@ func (s *Scenario) WaitForTailscaleLogout() error {
func (s *Scenario) CreateDERPServer(version string, opts ...dsic.Option) (*dsic.DERPServerInContainer, error) { func (s *Scenario) CreateDERPServer(version string, opts ...dsic.Option) (*dsic.DERPServerInContainer, error) {
derp, err := dsic.New(s.pool, version, s.Networks(), opts...) derp, err := dsic.New(s.pool, version, s.Networks(), opts...)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create DERP server: %w", err) return nil, fmt.Errorf("creating DERP server: %w", err)
} }
err = derp.WaitForRunning() err = derp.WaitForRunning()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to reach DERP server: %w", err) return nil, fmt.Errorf("reaching DERP server: %w", err)
} }
s.derpServers = append(s.derpServers, derp) s.derpServers = append(s.derpServers, derp)
@@ -1359,7 +1359,7 @@ var errStatusCodeNotOK = errors.New("status code not OK")
func (s *Scenario) runMockOIDC(accessTTL time.Duration, users []mockoidc.MockUser) error { func (s *Scenario) runMockOIDC(accessTTL time.Duration, users []mockoidc.MockUser) error {
port, err := dockertestutil.RandomFreeHostPort() port, err := dockertestutil.RandomFreeHostPort()
if err != nil { if err != nil {
log.Fatalf("could not find an open port: %s", err) log.Fatalf("finding open port: %s", err)
} }
portNotation := fmt.Sprintf("%d/tcp", port) portNotation := fmt.Sprintf("%d/tcp", port)
@@ -1465,7 +1465,7 @@ type extraServiceFunc func(*Scenario, string) (*dockertest.Resource, error)
func Webservice(s *Scenario, networkName string) (*dockertest.Resource, error) { func Webservice(s *Scenario, networkName string) (*dockertest.Resource, error) {
// port, err := dockertestutil.RandomFreeHostPort() // port, err := dockertestutil.RandomFreeHostPort()
// if err != nil { // if err != nil {
// log.Fatalf("could not find an open port: %s", err) // log.Fatalf("finding open port: %s", err)
// } // }
// portNotation := fmt.Sprintf("%d/tcp", port) // portNotation := fmt.Sprintf("%d/tcp", port)

View File

@@ -427,7 +427,7 @@ func New(
dockertestutil.DockerMemoryLimit, dockertestutil.DockerMemoryLimit,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("could not run pre-built tailscale container %q: %w", prebuiltImage, err) return nil, fmt.Errorf("running pre-built tailscale container %q: %w", prebuiltImage, err)
} }
} else if util.IsCI() && !hasBuildTags { } else if util.IsCI() && !hasBuildTags {
// In CI, we require a pre-built image unless custom build tags are needed // In CI, we require a pre-built image unless custom build tags are needed
@@ -555,7 +555,7 @@ func New(
for i, cert := range tsic.caCerts { for i, cert := range tsic.caCerts {
err = tsic.WriteFile(fmt.Sprintf("%s/user-%d.crt", caCertRoot, i), cert) err = tsic.WriteFile(fmt.Sprintf("%s/user-%d.crt", caCertRoot, i), cert)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to write TLS certificate to container: %w", err) return nil, fmt.Errorf("writing TLS certificate to container: %w", err)
} }
} }
@@ -567,9 +567,9 @@ func (t *TailscaleInContainer) Shutdown() (string, string, error) {
stdoutPath, stderrPath, err := t.SaveLog("/tmp/control") stdoutPath, stderrPath, err := t.SaveLog("/tmp/control")
if err != nil { if err != nil {
log.Printf( log.Printf(
"Failed to save log from %s: %s", "saving log from %s: %s",
t.hostname, t.hostname,
fmt.Errorf("failed to save log: %w", err), fmt.Errorf("saving log: %w", err),
) )
} }
@@ -720,7 +720,7 @@ func (t *TailscaleInContainer) Logout() error {
stdout, stderr, _ = t.Execute([]string{"tailscale", "status"}) stdout, stderr, _ = t.Execute([]string{"tailscale", "status"})
if !strings.Contains(stdout+stderr, "Logged out.") { if !strings.Contains(stdout+stderr, "Logged out.") {
return fmt.Errorf("failed to logout, stdout: %s, stderr: %s", stdout, stderr) return fmt.Errorf("logging out, stdout: %s, stderr: %s", stdout, stderr)
} }
return t.waitForBackendState("NeedsLogin", integrationutil.PeerSyncTimeout()) return t.waitForBackendState("NeedsLogin", integrationutil.PeerSyncTimeout())
@@ -738,7 +738,7 @@ func (t *TailscaleInContainer) Restart() error {
// Use Docker API to restart the container // Use Docker API to restart the container
err := t.pool.Client.RestartContainer(t.container.Container.ID, 30) err := t.pool.Client.RestartContainer(t.container.Container.ID, 30)
if err != nil { if err != nil {
return fmt.Errorf("failed to restart container %s: %w", t.hostname, err) return fmt.Errorf("restarting container %s: %w", t.hostname, err)
} }
// Wait for the container to be back up and tailscaled to be ready // Wait for the container to be back up and tailscaled to be ready
@@ -825,7 +825,7 @@ func (t *TailscaleInContainer) IPs() ([]netip.Addr, error) {
ip, err := netip.ParseAddr(address) ip, err := netip.ParseAddr(address)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to parse IP %s: %w", address, err) return nil, fmt.Errorf("parsing IP %s: %w", address, err)
} }
ips = append(ips, ip) ips = append(ips, ip)
@@ -838,7 +838,7 @@ func (t *TailscaleInContainer) IPs() ([]netip.Addr, error) {
return ips, nil return ips, nil
}, backoff.WithBackOff(backoff.NewExponentialBackOff()), backoff.WithMaxElapsedTime(10*time.Second)) }, backoff.WithBackOff(backoff.NewExponentialBackOff()), backoff.WithMaxElapsedTime(10*time.Second))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get IPs for %s after retries: %w", t.hostname, err) return nil, fmt.Errorf("getting IPs for %s after retries: %w", t.hostname, err)
} }
return ips, nil return ips, nil
@@ -898,14 +898,14 @@ func (t *TailscaleInContainer) Status(save ...bool) (*ipnstate.Status, error) {
result, _, err := t.Execute(command) result, _, err := t.Execute(command)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to execute tailscale status command: %w", err) return nil, fmt.Errorf("executing tailscale status command: %w", err)
} }
var status ipnstate.Status var status ipnstate.Status
err = json.Unmarshal([]byte(result), &status) err = json.Unmarshal([]byte(result), &status)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to unmarshal tailscale status: %w", err) return nil, fmt.Errorf("unmarshalling tailscale status: %w", err)
} }
err = os.WriteFile(fmt.Sprintf("/tmp/control/%s_status.json", t.hostname), []byte(result), 0o755) err = os.WriteFile(fmt.Sprintf("/tmp/control/%s_status.json", t.hostname), []byte(result), 0o755)
@@ -935,7 +935,7 @@ func (t *TailscaleInContainer) MustID() types.NodeID {
id, err := strconv.ParseUint(string(status.Self.ID), 10, 64) id, err := strconv.ParseUint(string(status.Self.ID), 10, 64)
if err != nil { if err != nil {
panic(fmt.Sprintf("failed to parse ID: %s", err)) panic(fmt.Sprintf("parsing ID: %s", err))
} }
return types.NodeID(id) return types.NodeID(id)
@@ -958,14 +958,14 @@ func (t *TailscaleInContainer) Netmap() (*netmap.NetworkMap, error) {
result, stderr, err := t.Execute(command) result, stderr, err := t.Execute(command)
if err != nil { if err != nil {
fmt.Printf("stderr: %s\n", stderr) fmt.Printf("stderr: %s\n", stderr)
return nil, fmt.Errorf("failed to execute tailscale debug netmap command: %w", err) return nil, fmt.Errorf("executing tailscale debug netmap command: %w", err)
} }
var nm netmap.NetworkMap var nm netmap.NetworkMap
err = json.Unmarshal([]byte(result), &nm) err = json.Unmarshal([]byte(result), &nm)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to unmarshal tailscale netmap: %w", err) return nil, fmt.Errorf("unmarshalling tailscale netmap: %w", err)
} }
err = os.WriteFile(fmt.Sprintf("/tmp/control/%s_netmap.json", t.hostname), []byte(result), 0o755) err = os.WriteFile(fmt.Sprintf("/tmp/control/%s_netmap.json", t.hostname), []byte(result), 0o755)
@@ -1019,7 +1019,7 @@ func (t *TailscaleInContainer) watchIPN(ctx context.Context) (*ipn.Notify, error
"/bin/sh", "-c", `kill $(ps aux | grep "tailscale debug watch-ipn" | grep -v grep | awk '{print $1}') || true`, "/bin/sh", "-c", `kill $(ps aux | grep "tailscale debug watch-ipn" | grep -v grep | awk '{print $1}') || true`,
}) })
if err != nil { if err != nil {
log.Printf("failed to kill tailscale watcher, \nstdout: %s\nstderr: %s\nerr: %s", stdout, stderr, err) log.Printf("killing tailscale watcher, \nstdout: %s\nstderr: %s\nerr: %s", stdout, stderr, err)
} }
} }
@@ -1085,14 +1085,14 @@ func (t *TailscaleInContainer) DebugDERPRegion(region string) (*ipnstate.DebugDE
if err != nil { if err != nil {
fmt.Printf("stderr: %s\n", stderr) // nolint fmt.Printf("stderr: %s\n", stderr) // nolint
return nil, fmt.Errorf("failed to execute tailscale debug derp command: %w", err) return nil, fmt.Errorf("executing tailscale debug derp command: %w", err)
} }
var report ipnstate.DebugDERPRegionReport var report ipnstate.DebugDERPRegionReport
err = json.Unmarshal([]byte(result), &report) err = json.Unmarshal([]byte(result), &report)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to unmarshal tailscale derp region report: %w", err) return nil, fmt.Errorf("unmarshalling tailscale derp region report: %w", err)
} }
return &report, err return &report, err
@@ -1109,14 +1109,14 @@ func (t *TailscaleInContainer) Netcheck() (*netcheck.Report, error) {
result, stderr, err := t.Execute(command) result, stderr, err := t.Execute(command)
if err != nil { if err != nil {
fmt.Printf("stderr: %s\n", stderr) fmt.Printf("stderr: %s\n", stderr)
return nil, fmt.Errorf("failed to execute tailscale debug netcheck command: %w", err) return nil, fmt.Errorf("executing tailscale debug netcheck command: %w", err)
} }
var nm netcheck.Report var nm netcheck.Report
err = json.Unmarshal([]byte(result), &nm) err = json.Unmarshal([]byte(result), &nm)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to unmarshal tailscale netcheck: %w", err) return nil, fmt.Errorf("unmarshalling tailscale netcheck: %w", err)
} }
return &nm, err return &nm, err
@@ -1132,7 +1132,7 @@ func (t *TailscaleInContainer) FQDN() (string, error) {
fqdn, err := backoff.Retry(context.Background(), func() (string, error) { fqdn, err := backoff.Retry(context.Background(), func() (string, error) {
status, err := t.Status() status, err := t.Status()
if err != nil { if err != nil {
return "", fmt.Errorf("failed to get status: %w", err) return "", fmt.Errorf("getting status: %w", err)
} }
if status.Self.DNSName == "" { if status.Self.DNSName == "" {
@@ -1142,7 +1142,7 @@ func (t *TailscaleInContainer) FQDN() (string, error) {
return status.Self.DNSName, nil return status.Self.DNSName, nil
}, backoff.WithBackOff(backoff.NewExponentialBackOff()), backoff.WithMaxElapsedTime(10*time.Second)) }, backoff.WithBackOff(backoff.NewExponentialBackOff()), backoff.WithMaxElapsedTime(10*time.Second))
if err != nil { if err != nil {
return "", fmt.Errorf("failed to get FQDN for %s after retries: %w", t.hostname, err) return "", fmt.Errorf("getting FQDN for %s after retries: %w", t.hostname, err)
} }
return fqdn, nil return fqdn, nil
@@ -1163,7 +1163,7 @@ func (t *TailscaleInContainer) MustFQDN() string {
func (t *TailscaleInContainer) FailingPeersAsString() (string, bool, error) { func (t *TailscaleInContainer) FailingPeersAsString() (string, bool, error) {
status, err := t.Status() status, err := t.Status()
if err != nil { if err != nil {
return "", false, fmt.Errorf("failed to get FQDN: %w", err) return "", false, fmt.Errorf("getting FQDN: %w", err)
} }
var b strings.Builder var b strings.Builder
@@ -1373,7 +1373,7 @@ func (t *TailscaleInContainer) Ping(hostnameOrIP string, opts ...PingOption) err
if err != nil { if err != nil {
log.Printf("command: %v", command) log.Printf("command: %v", command)
log.Printf( log.Printf(
"failed to run ping command from %s to %s, err: %s", "running ping command from %s to %s, err: %s",
t.Hostname(), t.Hostname(),
hostnameOrIP, hostnameOrIP,
err, err,
@@ -1477,7 +1477,7 @@ func (t *TailscaleInContainer) Curl(url string, opts ...CurlOption) (string, err
result, _, err := t.Execute(command) result, _, err := t.Execute(command)
if err != nil { if err != nil {
log.Printf( log.Printf(
"failed to run curl command from %s to %s, err: %s", "running curl command from %s to %s, err: %s",
t.Hostname(), t.Hostname(),
url, url,
err, err,
@@ -1587,27 +1587,27 @@ func (t *TailscaleInContainer) ReadFile(path string) ([]byte, error) {
func (t *TailscaleInContainer) GetNodePrivateKey() (*key.NodePrivate, error) { func (t *TailscaleInContainer) GetNodePrivateKey() (*key.NodePrivate, error) {
state, err := t.ReadFile(paths.DefaultTailscaledStateFile()) state, err := t.ReadFile(paths.DefaultTailscaledStateFile())
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read state file: %w", err) return nil, fmt.Errorf("reading state file: %w", err)
} }
store := &mem.Store{} store := &mem.Store{}
if err = store.LoadFromJSON(state); err != nil { if err = store.LoadFromJSON(state); err != nil {
return nil, fmt.Errorf("failed to unmarshal state file: %w", err) return nil, fmt.Errorf("unmarshalling state file: %w", err)
} }
currentProfileKey, err := store.ReadState(ipn.CurrentProfileStateKey) currentProfileKey, err := store.ReadState(ipn.CurrentProfileStateKey)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read current profile state key: %w", err) return nil, fmt.Errorf("reading current profile state key: %w", err)
} }
currentProfile, err := store.ReadState(ipn.StateKey(currentProfileKey)) currentProfile, err := store.ReadState(ipn.StateKey(currentProfileKey))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read current profile state: %w", err) return nil, fmt.Errorf("reading current profile state: %w", err)
} }
p := &ipn.Prefs{} p := &ipn.Prefs{}
if err = json.Unmarshal(currentProfile, &p); err != nil { if err = json.Unmarshal(currentProfile, &p); err != nil {
return nil, fmt.Errorf("failed to unmarshal current profile state: %w", err) return nil, fmt.Errorf("unmarshalling current profile state: %w", err)
} }
return &p.Persist.PrivateNodeKey, nil return &p.Persist.PrivateNodeKey, nil
@@ -1622,7 +1622,7 @@ func (t *TailscaleInContainer) PacketFilter() ([]filter.Match, error) {
nm, err := t.Netmap() nm, err := t.Netmap()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get netmap: %w", err) return nil, fmt.Errorf("getting netmap: %w", err)
} }
return nm.PacketFilter, nil return nm.PacketFilter, nil