// Package cluster reads live k3s state from inside a pod via the Kubernetes // API, using the mounted ServiceAccount credentials. No client-go: the queries // are read-only and few, so stdlib net/http keeps the dependency surface small. package cluster import ( "crypto/tls" "crypto/x509" "fmt" "io" "net/http" "os" "time" ) const ( tokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token" //nolint:gosec // well-known in-cluster path, not a secret literal caPath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" ) // Nodes returns the raw /api/v1/nodes JSON from the in-cluster API server. func Nodes() ([]byte, error) { return get("/api/v1/nodes") } // Namespaces returns the raw /api/v1/namespaces JSON from the in-cluster API server. func Namespaces() ([]byte, error) { return get("/api/v1/namespaces") } // Deployment returns the raw JSON for the cad-atlas Deployment (its own live state). func Deployment() ([]byte, error) { return get("/apis/apps/v1/namespaces/cad-atlas/deployments/cad-atlas") } func get(path string) ([]byte, error) { host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT") if host == "" || port == "" { return nil, fmt.Errorf("not in-cluster: KUBERNETES_SERVICE_HOST unset") } token, err := os.ReadFile(tokenPath) if err != nil { return nil, fmt.Errorf("read sa token: %w", err) } ca, err := os.ReadFile(caPath) if err != nil { return nil, fmt.Errorf("read ca: %w", err) } pool := x509.NewCertPool() if !pool.AppendCertsFromPEM(ca) { return nil, fmt.Errorf("invalid cluster CA cert") } client := &http.Client{ Timeout: 5 * time.Second, Transport: &http.Transport{ TLSClientConfig: &tls.Config{RootCAs: pool, MinVersion: tls.VersionTLS12}, }, } req, err := http.NewRequest(http.MethodGet, "https://"+host+":"+port+path, nil) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+string(token)) resp, err := client.Do(req) if err != nil { return nil, err } defer func() { _ = resp.Body.Close() }() body, err := io.ReadAll(io.LimitReader(resp.Body, 8<<20)) if err != nil { return nil, err } if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("k8s API GET %s: %s", path, resp.Status) } return body, nil }