mirror of
https://github.com/juanfont/headscale.git
synced 2025-06-26 10:08:32 +00:00

* cmd/hi: add integration test runner CLI tool Add a new CLI tool 'hi' for running headscale integration tests with Docker automation. The tool replaces manual Docker command composition with an automated solution. Features: - Run integration tests in golang:1.24 containers - Docker context detection (supports colima and other contexts) - Test isolation with unique run IDs and isolated control_logs - Automatic Docker image pulling and container management - Comprehensive cleanup operations for containers, networks, images - Docker volume caching for Go modules - Verbose logging and detailed test artifact reporting - Support for PostgreSQL/SQLite selection and various test flags Usage: go run ./cmd/hi run TestPingAllByIP --verbose The tool uses creachadair/command and flax for CLI parsing and provides cleanup subcommands for Docker resource management. Updates flake.nix vendorHash for new Go dependencies. * ci: update integration tests to use hi CLI tool Replace manual Docker command composition in GitHub Actions workflow with the new hi CLI tool for running integration tests. Changes: - Replace complex docker run command with simple 'go run ./cmd/hi run' - Remove manual environment variable setup (handled by hi tool) - Update artifact paths for new timestamped log directory structure - Simplify command from 15+ lines to 3 lines - Maintain all existing functionality (postgres/sqlite, timeout, test patterns) The hi tool automatically handles Docker context detection, container management, volume mounting, and environment variable setup that was previously done manually in the workflow. * makefile: remove test integration Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> --------- Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
145 lines
3.3 KiB
Go
145 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/api/types/filters"
|
|
"github.com/docker/docker/api/types/image"
|
|
"github.com/docker/docker/client"
|
|
)
|
|
|
|
// cleanupBeforeTest performs cleanup operations before running tests.
|
|
func cleanupBeforeTest(ctx context.Context) error {
|
|
if err := killTestContainers(ctx); err != nil {
|
|
return fmt.Errorf("failed to kill test containers: %w", err)
|
|
}
|
|
|
|
if err := pruneDockerNetworks(ctx); err != nil {
|
|
return fmt.Errorf("failed to prune networks: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// cleanupAfterTest removes the test container after completion.
|
|
func cleanupAfterTest(ctx context.Context, cli *client.Client, containerID string) error {
|
|
return cli.ContainerRemove(ctx, containerID, container.RemoveOptions{
|
|
Force: true,
|
|
})
|
|
}
|
|
|
|
// killTestContainers terminates all running test containers.
|
|
func killTestContainers(ctx context.Context) error {
|
|
cli, err := createDockerClient()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create Docker client: %w", err)
|
|
}
|
|
defer cli.Close()
|
|
|
|
containers, err := cli.ContainerList(ctx, container.ListOptions{
|
|
All: true,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to list containers: %w", err)
|
|
}
|
|
|
|
killed := 0
|
|
for _, cont := range containers {
|
|
shouldKill := false
|
|
for _, name := range cont.Names {
|
|
if strings.Contains(name, "headscale-test-suite") ||
|
|
strings.Contains(name, "hs-") ||
|
|
strings.Contains(name, "ts-") {
|
|
shouldKill = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if shouldKill {
|
|
if err := cli.ContainerKill(ctx, cont.ID, "KILL"); err == nil {
|
|
killed++
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// pruneDockerNetworks removes unused Docker networks.
|
|
func pruneDockerNetworks(ctx context.Context) error {
|
|
cli, err := createDockerClient()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create Docker client: %w", err)
|
|
}
|
|
defer cli.Close()
|
|
|
|
_, err = cli.NetworksPrune(ctx, filters.Args{})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to prune networks: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// cleanOldImages removes test-related and old dangling Docker images.
|
|
func cleanOldImages(ctx context.Context) error {
|
|
cli, err := createDockerClient()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create Docker client: %w", err)
|
|
}
|
|
defer cli.Close()
|
|
|
|
images, err := cli.ImageList(ctx, image.ListOptions{
|
|
All: true,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to list images: %w", err)
|
|
}
|
|
|
|
removed := 0
|
|
for _, img := range images {
|
|
shouldRemove := false
|
|
for _, tag := range img.RepoTags {
|
|
if strings.Contains(tag, "hs-") ||
|
|
strings.Contains(tag, "headscale-integration") ||
|
|
strings.Contains(tag, "tailscale") {
|
|
shouldRemove = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if len(img.RepoTags) == 0 && time.Unix(img.Created, 0).Before(time.Now().Add(-7*24*time.Hour)) {
|
|
shouldRemove = true
|
|
}
|
|
|
|
if shouldRemove {
|
|
_, err := cli.ImageRemove(ctx, img.ID, image.RemoveOptions{
|
|
Force: true,
|
|
})
|
|
if err == nil {
|
|
removed++
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// cleanCacheVolume removes the Docker volume used for Go module cache.
|
|
func cleanCacheVolume(ctx context.Context) error {
|
|
cli, err := createDockerClient()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create Docker client: %w", err)
|
|
}
|
|
defer cli.Close()
|
|
|
|
volumeName := "hs-integration-go-cache"
|
|
_ = cli.VolumeRemove(ctx, volumeName, true)
|
|
|
|
return nil
|
|
}
|