all: fix golangci-lint issues (#3064)

This commit is contained in:
Kristoffer Dalby
2026-02-06 21:45:32 +01:00
committed by GitHub
parent bfb6fd80df
commit ce580f8245
131 changed files with 3131 additions and 1560 deletions

View File

@@ -22,15 +22,20 @@ import (
"github.com/juanfont/headscale/integration/dockertestutil"
)
const defaultDirPerm = 0o755
var (
ErrTestFailed = errors.New("test failed")
ErrUnexpectedContainerWait = errors.New("unexpected end of container wait")
ErrNoDockerContext = errors.New("no docker context found")
ErrMemoryLimitViolations = errors.New("container(s) exceeded memory limits")
)
// runTestContainer executes integration tests in a Docker container.
//
//nolint:gocyclo // complex test orchestration function
func runTestContainer(ctx context.Context, config *RunConfig) error {
cli, err := createDockerClient()
cli, err := createDockerClient(ctx)
if err != nil {
return fmt.Errorf("creating Docker client: %w", err)
}
@@ -52,7 +57,7 @@ func runTestContainer(ctx context.Context, config *RunConfig) error {
}
const dirPerm = 0o755
if err := os.MkdirAll(absLogsDir, dirPerm); err != nil {
if err := os.MkdirAll(absLogsDir, dirPerm); err != nil { //nolint:noinlineerr
return fmt.Errorf("creating logs directory: %w", err)
}
@@ -60,7 +65,9 @@ func runTestContainer(ctx context.Context, config *RunConfig) error {
if config.Verbose {
log.Printf("Running pre-test cleanup...")
}
if err := cleanupBeforeTest(ctx); err != nil && config.Verbose {
err := cleanupBeforeTest(ctx)
if err != nil && config.Verbose {
log.Printf("Warning: pre-test cleanup failed: %v", err)
}
}
@@ -71,7 +78,7 @@ func runTestContainer(ctx context.Context, config *RunConfig) error {
}
imageName := "golang:" + config.GoVersion
if err := ensureImageAvailable(ctx, cli, imageName, config.Verbose); err != nil {
if err := ensureImageAvailable(ctx, cli, imageName, config.Verbose); err != nil { //nolint:noinlineerr
return fmt.Errorf("ensuring image availability: %w", err)
}
@@ -84,7 +91,7 @@ func runTestContainer(ctx context.Context, config *RunConfig) error {
log.Printf("Created container: %s", resp.ID)
}
if err := cli.ContainerStart(ctx, resp.ID, container.StartOptions{}); err != nil {
if err := cli.ContainerStart(ctx, resp.ID, container.StartOptions{}); err != nil { //nolint:noinlineerr
return fmt.Errorf("starting container: %w", err)
}
@@ -95,13 +102,16 @@ func runTestContainer(ctx context.Context, config *RunConfig) error {
// Start stats collection for container resource monitoring (if enabled)
var statsCollector *StatsCollector
if config.Stats {
var err error
statsCollector, err = NewStatsCollector()
statsCollector, err = NewStatsCollector(ctx)
if err != nil {
if config.Verbose {
log.Printf("Warning: failed to create stats collector: %v", err)
}
statsCollector = nil
}
@@ -110,7 +120,8 @@ func runTestContainer(ctx context.Context, config *RunConfig) error {
// Start stats collection immediately - no need for complex retry logic
// The new implementation monitors Docker events and will catch containers as they start
if err := statsCollector.StartCollection(ctx, runID, config.Verbose); err != nil {
err := statsCollector.StartCollection(ctx, runID, config.Verbose)
if err != nil {
if config.Verbose {
log.Printf("Warning: failed to start stats collection: %v", err)
}
@@ -122,12 +133,13 @@ func runTestContainer(ctx context.Context, config *RunConfig) error {
exitCode, err := streamAndWait(ctx, cli, resp.ID)
// Ensure all containers have finished and logs are flushed before extracting artifacts
if waitErr := waitForContainerFinalization(ctx, cli, resp.ID, config.Verbose); waitErr != nil && config.Verbose {
waitErr := waitForContainerFinalization(ctx, cli, resp.ID, config.Verbose)
if waitErr != nil && config.Verbose {
log.Printf("Warning: failed to wait for container finalization: %v", waitErr)
}
// Extract artifacts from test containers before cleanup
if err := extractArtifactsFromContainers(ctx, resp.ID, logsDir, config.Verbose); err != nil && config.Verbose {
if err := extractArtifactsFromContainers(ctx, resp.ID, logsDir, config.Verbose); err != nil && config.Verbose { //nolint:noinlineerr
log.Printf("Warning: failed to extract artifacts from containers: %v", err)
}
@@ -140,12 +152,13 @@ func runTestContainer(ctx context.Context, config *RunConfig) error {
if len(violations) > 0 {
log.Printf("MEMORY LIMIT VIOLATIONS DETECTED:")
log.Printf("=================================")
for _, violation := range violations {
log.Printf("Container %s exceeded memory limit: %.1f MB > %.1f MB",
violation.ContainerName, violation.MaxMemoryMB, violation.LimitMB)
}
return fmt.Errorf("test failed: %d container(s) exceeded memory limits", len(violations))
return fmt.Errorf("test failed: %d %w", len(violations), ErrMemoryLimitViolations)
}
}
@@ -347,6 +360,7 @@ func waitForContainerFinalization(ctx context.Context, cli *client.Client, testC
maxWaitTime := 10 * time.Second
checkInterval := 500 * time.Millisecond
timeout := time.After(maxWaitTime)
ticker := time.NewTicker(checkInterval)
defer ticker.Stop()
@@ -356,6 +370,7 @@ func waitForContainerFinalization(ctx context.Context, cli *client.Client, testC
if verbose {
log.Printf("Timeout waiting for container finalization, proceeding with artifact extraction")
}
return nil
case <-ticker.C:
allFinalized := true
@@ -366,12 +381,14 @@ func waitForContainerFinalization(ctx context.Context, cli *client.Client, testC
if verbose {
log.Printf("Warning: failed to inspect container %s: %v", testCont.name, err)
}
continue
}
// Check if container is in a final state
if !isContainerFinalized(inspect.State) {
allFinalized = false
if verbose {
log.Printf("Container %s still finalizing (state: %s)", testCont.name, inspect.State.Status)
}
@@ -384,6 +401,7 @@ func waitForContainerFinalization(ctx context.Context, cli *client.Client, testC
if verbose {
log.Printf("All test containers finalized, ready for artifact extraction")
}
return nil
}
}
@@ -400,13 +418,15 @@ func isContainerFinalized(state *container.State) bool {
func findProjectRoot(startPath string) string {
current := startPath
for {
if _, err := os.Stat(filepath.Join(current, "go.mod")); err == nil {
if _, err := os.Stat(filepath.Join(current, "go.mod")); err == nil { //nolint:noinlineerr
return current
}
parent := filepath.Dir(current)
if parent == current {
return startPath
}
current = parent
}
}
@@ -416,6 +436,7 @@ func boolToInt(b bool) int {
if b {
return 1
}
return 0
}
@@ -428,13 +449,14 @@ type DockerContext struct {
}
// createDockerClient creates a Docker client with context detection.
func createDockerClient() (*client.Client, error) {
contextInfo, err := getCurrentDockerContext()
func createDockerClient(ctx context.Context) (*client.Client, error) {
contextInfo, err := getCurrentDockerContext(ctx)
if err != nil {
return client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
}
var clientOpts []client.Opt
clientOpts = append(clientOpts, client.WithAPIVersionNegotiation())
if contextInfo != nil {
@@ -444,6 +466,7 @@ func createDockerClient() (*client.Client, error) {
if runConfig.Verbose {
log.Printf("Using Docker host from context '%s': %s", contextInfo.Name, host)
}
clientOpts = append(clientOpts, client.WithHost(host))
}
}
@@ -458,15 +481,16 @@ func createDockerClient() (*client.Client, error) {
}
// getCurrentDockerContext retrieves the current Docker context information.
func getCurrentDockerContext() (*DockerContext, error) {
cmd := exec.Command("docker", "context", "inspect")
func getCurrentDockerContext(ctx context.Context) (*DockerContext, error) {
cmd := exec.CommandContext(ctx, "docker", "context", "inspect")
output, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("getting docker context: %w", err)
}
var contexts []DockerContext
if err := json.Unmarshal(output, &contexts); err != nil {
if err := json.Unmarshal(output, &contexts); err != nil { //nolint:noinlineerr
return nil, fmt.Errorf("parsing docker context: %w", err)
}
@@ -486,11 +510,12 @@ func getDockerSocketPath() string {
// checkImageAvailableLocally checks if the specified Docker image is available locally.
func checkImageAvailableLocally(ctx context.Context, cli *client.Client, imageName string) (bool, error) {
_, _, err := cli.ImageInspectWithRaw(ctx, imageName)
_, _, err := cli.ImageInspectWithRaw(ctx, imageName) //nolint:staticcheck // SA1019: deprecated but functional
if err != nil {
if client.IsErrNotFound(err) {
if client.IsErrNotFound(err) { //nolint:staticcheck // SA1019: deprecated but functional
return false, nil
}
return false, fmt.Errorf("inspecting image %s: %w", imageName, err)
}
@@ -509,6 +534,7 @@ func ensureImageAvailable(ctx context.Context, cli *client.Client, imageName str
if verbose {
log.Printf("Image %s is available locally", imageName)
}
return nil
}
@@ -533,6 +559,7 @@ func ensureImageAvailable(ctx context.Context, cli *client.Client, imageName str
if err != nil {
return fmt.Errorf("reading pull output: %w", err)
}
log.Printf("Image %s pulled successfully", imageName)
}
@@ -547,9 +574,11 @@ func listControlFiles(logsDir string) {
return
}
var logFiles []string
var dataFiles []string
var dataDirs []string
var (
logFiles []string
dataFiles []string
dataDirs []string
)
for _, entry := range entries {
name := entry.Name()
@@ -578,6 +607,7 @@ func listControlFiles(logsDir string) {
if len(logFiles) > 0 {
log.Printf("Headscale logs:")
for _, file := range logFiles {
log.Printf(" %s", file)
}
@@ -585,9 +615,11 @@ func listControlFiles(logsDir string) {
if len(dataFiles) > 0 || len(dataDirs) > 0 {
log.Printf("Headscale data:")
for _, file := range dataFiles {
log.Printf(" %s", file)
}
for _, dir := range dataDirs {
log.Printf(" %s/", dir)
}
@@ -596,7 +628,7 @@ func listControlFiles(logsDir string) {
// extractArtifactsFromContainers collects container logs and files from the specific test run.
func extractArtifactsFromContainers(ctx context.Context, testContainerID, logsDir string, verbose bool) error {
cli, err := createDockerClient()
cli, err := createDockerClient(ctx)
if err != nil {
return fmt.Errorf("creating Docker client: %w", err)
}
@@ -612,9 +644,11 @@ func extractArtifactsFromContainers(ctx context.Context, testContainerID, logsDi
currentTestContainers := getCurrentTestContainers(containers, testContainerID, verbose)
extractedCount := 0
for _, cont := range currentTestContainers {
// Extract container logs and tar files
if err := extractContainerArtifacts(ctx, cli, cont.ID, cont.name, logsDir, verbose); err != nil {
err := extractContainerArtifacts(ctx, cli, cont.ID, cont.name, logsDir, verbose)
if err != nil {
if verbose {
log.Printf("Warning: failed to extract artifacts from container %s (%s): %v", cont.name, cont.ID[:12], err)
}
@@ -622,6 +656,7 @@ func extractArtifactsFromContainers(ctx context.Context, testContainerID, logsDi
if verbose {
log.Printf("Extracted artifacts from container %s (%s)", cont.name, cont.ID[:12])
}
extractedCount++
}
}
@@ -645,11 +680,13 @@ func getCurrentTestContainers(containers []container.Summary, testContainerID st
// Find the test container to get its run ID label
var runID string
for _, cont := range containers {
if cont.ID == testContainerID {
if cont.Labels != nil {
runID = cont.Labels["hi.run-id"]
}
break
}
}
@@ -690,18 +727,21 @@ func getCurrentTestContainers(containers []container.Summary, testContainerID st
// extractContainerArtifacts saves logs and tar files from a container.
func extractContainerArtifacts(ctx context.Context, cli *client.Client, containerID, containerName, logsDir string, verbose bool) error {
// Ensure the logs directory exists
if err := os.MkdirAll(logsDir, 0o755); err != nil {
err := os.MkdirAll(logsDir, defaultDirPerm)
if err != nil {
return fmt.Errorf("creating logs directory: %w", err)
}
// Extract container logs
if err := extractContainerLogs(ctx, cli, containerID, containerName, logsDir, verbose); err != nil {
err = extractContainerLogs(ctx, cli, containerID, containerName, logsDir, verbose)
if err != nil {
return fmt.Errorf("extracting logs: %w", err)
}
// Extract tar files for headscale containers only
if strings.HasPrefix(containerName, "hs-") {
if err := extractContainerFiles(ctx, cli, containerID, containerName, logsDir, verbose); err != nil {
err := extractContainerFiles(ctx, cli, containerID, containerName, logsDir, verbose)
if err != nil {
if verbose {
log.Printf("Warning: failed to extract files from %s: %v", containerName, err)
}
@@ -741,12 +781,12 @@ func extractContainerLogs(ctx context.Context, cli *client.Client, containerID,
}
// Write stdout logs
if err := os.WriteFile(stdoutPath, stdoutBuf.Bytes(), 0o644); err != nil {
if err := os.WriteFile(stdoutPath, stdoutBuf.Bytes(), 0o644); err != nil { //nolint:gosec,noinlineerr // log files should be readable
return fmt.Errorf("writing stdout log: %w", err)
}
// Write stderr logs
if err := os.WriteFile(stderrPath, stderrBuf.Bytes(), 0o644); err != nil {
if err := os.WriteFile(stderrPath, stderrBuf.Bytes(), 0o644); err != nil { //nolint:gosec,noinlineerr // log files should be readable
return fmt.Errorf("writing stderr log: %w", err)
}