mirror of
https://github.com/juanfont/headscale.git
synced 2026-05-25 11:38:41 +09:00
all: apply godoc [Name] link conventions across comments
Every Go-identifier reference in // and /* */ comments now uses
godoc's [Name] linking syntax so pkg.go.dev and `go doc` render
them as clickable cross-references. No behaviour change.
Pattern applied across the tree:
In-package [Foo], [Foo.Bar]
Cross-package [pkg.Foo], [pkg.Foo.Bar]
Stdlib [netip.Prefix], [errors.Is], [context.Context]
Tailscale [tailcfg.MapResponse], [tailcfg.Node.CapMap],
[tailcfg.NodeAttrSuggestExitNode]
Skip rules:
- File:line refs left as plain text
- HuJSON wire keys inside backtick raw strings untouched
- ACL/policy syntax tokens (tag:foo, autogroup:self, ...) not Go
symbols, left as plain text
- JSON/OIDC wire keys, gorm tags, RFC IPv6 placeholders, markdown
link tags, decorative dividers — all left as-is
This commit is contained in:
@@ -830,7 +830,7 @@ func extractContainerLogs(ctx context.Context, cli *client.Client, containerID,
|
||||
|
||||
// extractContainerFiles extracts database file and directories from headscale containers.
|
||||
// Note: The actual file extraction is now handled by the integration tests themselves
|
||||
// via SaveProfile, SaveMapResponses, and SaveDatabase functions in hsic.go.
|
||||
// via [SaveProfile], [SaveMapResponses], and [SaveDatabase] functions in hsic.go.
|
||||
func extractContainerFiles(ctx context.Context, cli *client.Client, containerID, containerName, logsDir string, verbose bool) error {
|
||||
// Files are now extracted directly by the integration tests
|
||||
// This function is kept for potential future use or other file types
|
||||
|
||||
102
cmd/hi/doctor.go
102
cmd/hi/doctor.go
@@ -11,6 +11,18 @@ import (
|
||||
"github.com/juanfont/headscale/integration/dockertestutil"
|
||||
)
|
||||
|
||||
const (
|
||||
statusPass = "PASS"
|
||||
statusFail = "FAIL"
|
||||
statusWarn = "WARN"
|
||||
|
||||
nameDockerDaemon = "Docker Daemon"
|
||||
nameDockerContext = "Docker Context"
|
||||
nameDockerSocket = "Docker Socket"
|
||||
nameGolangImage = "Golang Image"
|
||||
nameGoInstall = "Go Installation"
|
||||
)
|
||||
|
||||
var ErrSystemChecksFailed = errors.New("system checks failed")
|
||||
|
||||
// DoctorResult represents the result of a single health check.
|
||||
@@ -33,7 +45,7 @@ func runDoctorCheck(ctx context.Context) error {
|
||||
results = append(results, dockerResult)
|
||||
|
||||
// If Docker is available, run additional checks
|
||||
if dockerResult.Status == "PASS" {
|
||||
if dockerResult.Status == statusPass {
|
||||
results = append(results, checkDockerContext(ctx))
|
||||
results = append(results, checkDockerSocket(ctx))
|
||||
results = append(results, checkDockerHubCredentials())
|
||||
@@ -54,7 +66,7 @@ func runDoctorCheck(ctx context.Context) error {
|
||||
|
||||
// Return error if any critical checks failed
|
||||
for _, result := range results {
|
||||
if result.Status == "FAIL" {
|
||||
if result.Status == statusFail {
|
||||
return fmt.Errorf("%w - see details above", ErrSystemChecksFailed)
|
||||
}
|
||||
}
|
||||
@@ -70,7 +82,7 @@ func checkDockerBinary() DoctorResult {
|
||||
if err != nil {
|
||||
return DoctorResult{
|
||||
Name: "Docker Binary",
|
||||
Status: "FAIL",
|
||||
Status: statusFail,
|
||||
Message: "Docker binary not found in PATH",
|
||||
Suggestions: []string{
|
||||
"Install Docker: https://docs.docker.com/get-docker/",
|
||||
@@ -82,7 +94,7 @@ func checkDockerBinary() DoctorResult {
|
||||
|
||||
return DoctorResult{
|
||||
Name: "Docker Binary",
|
||||
Status: "PASS",
|
||||
Status: statusPass,
|
||||
Message: "Docker binary found",
|
||||
}
|
||||
}
|
||||
@@ -92,8 +104,8 @@ func checkDockerDaemon(ctx context.Context) DoctorResult {
|
||||
cli, err := createDockerClient(ctx)
|
||||
if err != nil {
|
||||
return DoctorResult{
|
||||
Name: "Docker Daemon",
|
||||
Status: "FAIL",
|
||||
Name: nameDockerDaemon,
|
||||
Status: statusFail,
|
||||
Message: fmt.Sprintf("Cannot create Docker client: %v", err),
|
||||
Suggestions: []string{
|
||||
"Start Docker daemon/service",
|
||||
@@ -108,8 +120,8 @@ func checkDockerDaemon(ctx context.Context) DoctorResult {
|
||||
_, err = cli.Ping(ctx)
|
||||
if err != nil {
|
||||
return DoctorResult{
|
||||
Name: "Docker Daemon",
|
||||
Status: "FAIL",
|
||||
Name: nameDockerDaemon,
|
||||
Status: statusFail,
|
||||
Message: fmt.Sprintf("Cannot ping Docker daemon: %v", err),
|
||||
Suggestions: []string{
|
||||
"Ensure Docker daemon is running",
|
||||
@@ -120,8 +132,8 @@ func checkDockerDaemon(ctx context.Context) DoctorResult {
|
||||
}
|
||||
|
||||
return DoctorResult{
|
||||
Name: "Docker Daemon",
|
||||
Status: "PASS",
|
||||
Name: nameDockerDaemon,
|
||||
Status: statusPass,
|
||||
Message: "Docker daemon is running and accessible",
|
||||
}
|
||||
}
|
||||
@@ -131,8 +143,8 @@ func checkDockerContext(ctx context.Context) DoctorResult {
|
||||
contextInfo, err := getCurrentDockerContext(ctx)
|
||||
if err != nil {
|
||||
return DoctorResult{
|
||||
Name: "Docker Context",
|
||||
Status: "WARN",
|
||||
Name: nameDockerContext,
|
||||
Status: statusWarn,
|
||||
Message: "Could not detect Docker context, using default settings",
|
||||
Suggestions: []string{
|
||||
"Check: docker context ls",
|
||||
@@ -143,15 +155,15 @@ func checkDockerContext(ctx context.Context) DoctorResult {
|
||||
|
||||
if contextInfo == nil {
|
||||
return DoctorResult{
|
||||
Name: "Docker Context",
|
||||
Status: "PASS",
|
||||
Name: nameDockerContext,
|
||||
Status: statusPass,
|
||||
Message: "Using default Docker context",
|
||||
}
|
||||
}
|
||||
|
||||
return DoctorResult{
|
||||
Name: "Docker Context",
|
||||
Status: "PASS",
|
||||
Name: nameDockerContext,
|
||||
Status: statusPass,
|
||||
Message: "Using Docker context: " + contextInfo.Name,
|
||||
}
|
||||
}
|
||||
@@ -161,8 +173,8 @@ func checkDockerSocket(ctx context.Context) DoctorResult {
|
||||
cli, err := createDockerClient(ctx)
|
||||
if err != nil {
|
||||
return DoctorResult{
|
||||
Name: "Docker Socket",
|
||||
Status: "FAIL",
|
||||
Name: nameDockerSocket,
|
||||
Status: statusFail,
|
||||
Message: fmt.Sprintf("Cannot access Docker socket: %v", err),
|
||||
Suggestions: []string{
|
||||
"Check Docker socket permissions",
|
||||
@@ -176,8 +188,8 @@ func checkDockerSocket(ctx context.Context) DoctorResult {
|
||||
info, err := cli.Info(ctx)
|
||||
if err != nil {
|
||||
return DoctorResult{
|
||||
Name: "Docker Socket",
|
||||
Status: "FAIL",
|
||||
Name: nameDockerSocket,
|
||||
Status: statusFail,
|
||||
Message: fmt.Sprintf("Cannot get Docker info: %v", err),
|
||||
Suggestions: []string{
|
||||
"Check Docker daemon status",
|
||||
@@ -187,8 +199,8 @@ func checkDockerSocket(ctx context.Context) DoctorResult {
|
||||
}
|
||||
|
||||
return DoctorResult{
|
||||
Name: "Docker Socket",
|
||||
Status: "PASS",
|
||||
Name: nameDockerSocket,
|
||||
Status: statusPass,
|
||||
Message: fmt.Sprintf("Docker socket accessible (Server: %s)", info.ServerVersion),
|
||||
}
|
||||
}
|
||||
@@ -222,8 +234,8 @@ func checkGolangImage(ctx context.Context) DoctorResult {
|
||||
cli, err := createDockerClient(ctx)
|
||||
if err != nil {
|
||||
return DoctorResult{
|
||||
Name: "Golang Image",
|
||||
Status: "FAIL",
|
||||
Name: nameGolangImage,
|
||||
Status: statusFail,
|
||||
Message: "Cannot create Docker client for image check",
|
||||
}
|
||||
}
|
||||
@@ -236,8 +248,8 @@ func checkGolangImage(ctx context.Context) DoctorResult {
|
||||
available, err := checkImageAvailableLocally(ctx, cli, imageName)
|
||||
if err != nil {
|
||||
return DoctorResult{
|
||||
Name: "Golang Image",
|
||||
Status: "FAIL",
|
||||
Name: nameGolangImage,
|
||||
Status: statusFail,
|
||||
Message: fmt.Sprintf("Cannot check golang image %s: %v", imageName, err),
|
||||
Suggestions: []string{
|
||||
"Check Docker daemon status",
|
||||
@@ -248,8 +260,8 @@ func checkGolangImage(ctx context.Context) DoctorResult {
|
||||
|
||||
if available {
|
||||
return DoctorResult{
|
||||
Name: "Golang Image",
|
||||
Status: "PASS",
|
||||
Name: nameGolangImage,
|
||||
Status: statusPass,
|
||||
Message: fmt.Sprintf("Golang image %s is available locally", imageName),
|
||||
}
|
||||
}
|
||||
@@ -258,8 +270,8 @@ func checkGolangImage(ctx context.Context) DoctorResult {
|
||||
err = ensureImageAvailable(ctx, cli, imageName, false)
|
||||
if err != nil {
|
||||
return DoctorResult{
|
||||
Name: "Golang Image",
|
||||
Status: "FAIL",
|
||||
Name: nameGolangImage,
|
||||
Status: statusFail,
|
||||
Message: fmt.Sprintf("Golang image %s not available locally and cannot pull: %v", imageName, err),
|
||||
Suggestions: []string{
|
||||
"Check internet connectivity",
|
||||
@@ -271,8 +283,8 @@ func checkGolangImage(ctx context.Context) DoctorResult {
|
||||
}
|
||||
|
||||
return DoctorResult{
|
||||
Name: "Golang Image",
|
||||
Status: "PASS",
|
||||
Name: nameGolangImage,
|
||||
Status: statusPass,
|
||||
Message: fmt.Sprintf("Golang image %s is now available", imageName),
|
||||
}
|
||||
}
|
||||
@@ -282,8 +294,8 @@ func checkGoInstallation(ctx context.Context) DoctorResult {
|
||||
_, err := exec.LookPath("go")
|
||||
if err != nil {
|
||||
return DoctorResult{
|
||||
Name: "Go Installation",
|
||||
Status: "FAIL",
|
||||
Name: nameGoInstall,
|
||||
Status: statusFail,
|
||||
Message: "Go binary not found in PATH",
|
||||
Suggestions: []string{
|
||||
"Install Go: https://golang.org/dl/",
|
||||
@@ -297,8 +309,8 @@ func checkGoInstallation(ctx context.Context) DoctorResult {
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return DoctorResult{
|
||||
Name: "Go Installation",
|
||||
Status: "FAIL",
|
||||
Name: nameGoInstall,
|
||||
Status: statusFail,
|
||||
Message: fmt.Sprintf("Cannot get Go version: %v", err),
|
||||
}
|
||||
}
|
||||
@@ -306,8 +318,8 @@ func checkGoInstallation(ctx context.Context) DoctorResult {
|
||||
version := strings.TrimSpace(string(output))
|
||||
|
||||
return DoctorResult{
|
||||
Name: "Go Installation",
|
||||
Status: "PASS",
|
||||
Name: nameGoInstall,
|
||||
Status: statusPass,
|
||||
Message: version,
|
||||
}
|
||||
}
|
||||
@@ -320,7 +332,7 @@ func checkGitRepository(ctx context.Context) DoctorResult {
|
||||
if err != nil {
|
||||
return DoctorResult{
|
||||
Name: "Git Repository",
|
||||
Status: "FAIL",
|
||||
Status: statusFail,
|
||||
Message: "Not in a Git repository",
|
||||
Suggestions: []string{
|
||||
"Run from within the headscale git repository",
|
||||
@@ -331,7 +343,7 @@ func checkGitRepository(ctx context.Context) DoctorResult {
|
||||
|
||||
return DoctorResult{
|
||||
Name: "Git Repository",
|
||||
Status: "PASS",
|
||||
Status: statusPass,
|
||||
Message: "Running in Git repository",
|
||||
}
|
||||
}
|
||||
@@ -358,7 +370,7 @@ func checkRequiredFiles(ctx context.Context) DoctorResult {
|
||||
if len(missingFiles) > 0 {
|
||||
return DoctorResult{
|
||||
Name: "Required Files",
|
||||
Status: "FAIL",
|
||||
Status: statusFail,
|
||||
Message: "Missing required files: " + strings.Join(missingFiles, ", "),
|
||||
Suggestions: []string{
|
||||
"Ensure you're in the headscale project root directory",
|
||||
@@ -370,7 +382,7 @@ func checkRequiredFiles(ctx context.Context) DoctorResult {
|
||||
|
||||
return DoctorResult{
|
||||
Name: "Required Files",
|
||||
Status: "PASS",
|
||||
Status: statusPass,
|
||||
Message: "All required files found",
|
||||
}
|
||||
}
|
||||
@@ -384,11 +396,11 @@ func displayDoctorResults(results []DoctorResult) {
|
||||
var icon string
|
||||
|
||||
switch result.Status {
|
||||
case "PASS":
|
||||
case statusPass:
|
||||
icon = "✅"
|
||||
case "WARN":
|
||||
case statusWarn:
|
||||
icon = "⚠️"
|
||||
case "FAIL":
|
||||
case statusFail:
|
||||
icon = "❌"
|
||||
default:
|
||||
icon = "❓"
|
||||
|
||||
@@ -94,7 +94,7 @@ func detectGoVersion() string {
|
||||
return "1.26.1"
|
||||
}
|
||||
|
||||
// splitLines splits a string into lines without using strings.Split.
|
||||
// splitLines splits a string into lines without using [strings.Split].
|
||||
func splitLines(s string) []string {
|
||||
var (
|
||||
lines []string
|
||||
|
||||
@@ -160,7 +160,7 @@ func (sc *StatsCollector) monitorDockerEvents(ctx context.Context, runID string,
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert to types.Container format for consistency
|
||||
// Convert to [types.Container] format for consistency
|
||||
cont := types.Container{ //nolint:staticcheck // SA1019: use container.Summary
|
||||
ID: containerInfo.ID,
|
||||
Names: []string{containerInfo.Name},
|
||||
@@ -256,7 +256,7 @@ func (sc *StatsCollector) collectStatsForContainer(ctx context.Context, containe
|
||||
|
||||
err := decoder.Decode(&stats)
|
||||
if err != nil {
|
||||
// EOF is expected when container stops or stream ends
|
||||
// [io.EOF] is expected when container stops or stream ends
|
||||
if err.Error() != "EOF" && verbose {
|
||||
log.Printf("Failed to decode stats for container %s: %v", containerID[:12], err)
|
||||
}
|
||||
@@ -312,7 +312,7 @@ func calculateCPUPercent(prevStats, stats *container.Stats) float64 { //nolint:s
|
||||
// Calculate CPU percentage: (container CPU delta / system CPU delta) * number of CPUs * 100
|
||||
numCPUs := float64(len(stats.CPUStats.CPUUsage.PercpuUsage))
|
||||
if numCPUs == 0 {
|
||||
// Fallback: if PercpuUsage is not available, assume 1 CPU
|
||||
// Fallback: if [PercpuUsage] is not available, assume 1 CPU
|
||||
numCPUs = 1.0
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// vendorhash check exit non-zero if flakehashes.json is stale
|
||||
// vendorhash update recompute and rewrite flakehashes.json
|
||||
//
|
||||
// The JSON schema and goModFingerprint algorithm mirror upstream
|
||||
// The JSON schema and [goModFingerprint] algorithm mirror upstream
|
||||
// tailscale's tool/updateflakes so a future shared library extraction
|
||||
// is straightforward.
|
||||
package main
|
||||
@@ -82,8 +82,8 @@ func usage() {
|
||||
fmt.Fprintln(os.Stderr, "usage: vendorhash <check|update>")
|
||||
}
|
||||
|
||||
// errStale signals to main that the check found a mismatch; it has
|
||||
// already printed a remediation message, so main should exit 1
|
||||
// errStale signals to [main] that the check found a mismatch; it has
|
||||
// already printed a remediation message, so [main] should exit 1
|
||||
// silently.
|
||||
var errStale = errors.New("vendor hash stale")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user