Add complete TUI application for monitoring Kubernetes clusters and host systems. Features include: Core features: - Collector framework with concurrent scheduling - Host collectors: disk, memory, load, network - Kubernetes collectors: pods, nodes, workloads, events with informers - Issue deduplication, state management, and resolve-after logic - Bubble Tea TUI with table view, details pane, and filtering - JSON export functionality UX improvements: - Help overlay with keybindings - Priority/category filters with visual indicators - Direct priority jump (0/1/2/3) - Bulk acknowledge (Shift+A) - Clipboard copy (y) - Theme toggle (T) - Age format toggle (d) - Wide title toggle (t) - Vi-style navigation (j/k) - Home/End jump (g/G) - Rollup drill-down in details Robustness: - Grace period for unreachable clusters - Rollups for high-volume issues - Flap suppression - RBAC error handling Files: All core application code with tests for host collectors, engine, store, model, and export packages.
89 lines
2.4 KiB
Go
89 lines
2.4 KiB
Go
package k8s
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
"k8s.io/client-go/kubernetes"
|
|
"k8s.io/client-go/rest"
|
|
"k8s.io/client-go/tools/clientcmd"
|
|
)
|
|
|
|
// ClientFromCurrentContext creates a Kubernetes client-go Clientset using the
|
|
// user's kubeconfig current context.
|
|
//
|
|
// It is a pure helper (no global state) so it can be used by collectors and
|
|
// unit tests (with temporary kubeconfig files).
|
|
func ClientFromCurrentContext() (*kubernetes.Clientset, *rest.Config, error) {
|
|
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
|
|
|
// Respect KUBECONFIG semantics (it may be a path list).
|
|
if p := os.Getenv("KUBECONFIG"); p != "" {
|
|
if list := filepath.SplitList(p); len(list) > 1 {
|
|
loadingRules.ExplicitPath = ""
|
|
loadingRules.Precedence = list
|
|
} else {
|
|
loadingRules.ExplicitPath = p
|
|
}
|
|
}
|
|
|
|
cfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
|
|
restCfg, err := cfg.ClientConfig()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Ensure HTTP client timeouts are bounded. LIST fallback uses its own context
|
|
// timeouts, but this provides a safety net.
|
|
if restCfg.Timeout <= 0 {
|
|
restCfg.Timeout = 30 * time.Second
|
|
}
|
|
|
|
cs, err := kubernetes.NewForConfig(restCfg)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return cs, restCfg, nil
|
|
}
|
|
|
|
func defaultKubeconfigPath() string {
|
|
// This helper is used only for existence checks / UI messages. Client loading
|
|
// should use client-go's default loading rules.
|
|
if p := os.Getenv("KUBECONFIG"); p != "" {
|
|
// If KUBECONFIG is a list, return the first entry for display.
|
|
if list := filepath.SplitList(p); len(list) > 0 {
|
|
return list[0]
|
|
}
|
|
return p
|
|
}
|
|
|
|
h, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return filepath.Join(h, ".kube", "config")
|
|
}
|
|
|
|
// Ping performs a lightweight API call to determine if the cluster is reachable
|
|
// and authentication works.
|
|
func Ping(ctx context.Context, cs kubernetes.Interface) error {
|
|
if cs == nil {
|
|
return errors.New("nil kubernetes client")
|
|
}
|
|
_, err := cs.Discovery().ServerVersion()
|
|
if err != nil {
|
|
// Treat authn/authz errors separately so callers can decide whether to
|
|
// surface "unreachable" vs "insufficient credentials".
|
|
if apierrors.IsForbidden(err) || apierrors.IsUnauthorized(err) {
|
|
return fmt.Errorf("discovery auth: %w", err)
|
|
}
|
|
return fmt.Errorf("discovery server version: %w", err)
|
|
}
|
|
return nil
|
|
}
|