package main
import (
"context"
"fmt"
"os"
"strconv"
"strings"
)
// checkKubectl reports whether kubectl can currently reach the cluster —
// this is the exact failure observed live: a freshly root-owned
// /etc/rancher/k3s/k3s.yaml with no ~/.kube/config for root to fall back
// to, so every kubectl call prompts nothing and just fails.
func checkKubectl(ctx context.Context) bool {
_, err := runQuiet(ctx, "", "kubectl", "get", "ns", "gitfed", "--no-headers")
return err == nil
}
// k3sYAMLPath is where a fresh k3s install always writes its kubeconfig,
// root-owned — same path cmd/gitfed-install/actions.go's setupKubeconfig
// reads from for the non-root case.
const k3sYAMLPath = "/etc/rancher/k3s/k3s.yaml"
func k3sYAMLExists() bool {
_, err := os.Stat(k3sYAMLPath)
return err == nil
}
// fixKubeconfig is the root-side equivalent of cmd/gitfed-install's
// setupKubeconfig: gitfed-ctl already runs as root (see main.go), so there
// is no sudo subshell to invoke — just copy the file directly into root's
// own kube config location and point KUBECONFIG at it for the rest of this
// process's lifetime.
func fixKubeconfig() error {
data, err := os.ReadFile(k3sYAMLPath)
if err != nil {
return err
}
if err := os.MkdirAll("/root/.kube", 0700); err != nil {
return err
}
if err := os.WriteFile("/root/.kube/config", data, 0600); err != nil {
return err
}
os.Setenv("KUBECONFIG", "/root/.kube/config")
return nil
}
// podSummary is a one-line human-readable status of the gitfed pod for the
// dashboard — not a full stuck-pod diagnosis (that's cmd/gitfed-install's
// job during first install); here it's only "is it healthy right now".
func podSummary(ctx context.Context) (summary string, healthy bool, err error) {
out, err := runQuiet(ctx, "", "kubectl", "-n", "gitfed", "get", "pods", "--no-headers")
if err != nil {
return "", false, err
}
for _, line := range strings.Split(strings.TrimSpace(out), "\n") {
fields := strings.Fields(line)
if len(fields) < 3 || !strings.HasPrefix(fields[0], "gitfed-") {
continue
}
status := fields[2]
ready, total, ok := readyFraction(fields[1])
healthy = status == "Running" && ok && ready == total && total > 0
return fmt.Sprintf("%s — %s (%s)", fields[0], status, fields[1]), healthy, nil
}
return "aucun pod trouvé dans le namespace gitfed", false, nil
}
func readyFraction(s string) (ready, total int, ok bool) {
a, b, found := strings.Cut(s, "/")
if !found {
return 0, 0, false
}
ready, err1 := strconv.Atoi(a)
total, err2 := strconv.Atoi(b)
return ready, total, err1 == nil && err2 == nil
}