Major refactoring to hexagonal (ports & adapters) architecture: - Add service layer (apikey_service, project_service) for business logic - Add webhook system with dispatcher and delivery tracking - Add command queue with priority-based processing - Add rate limiting with sliding window algorithm - Add audit logging for command execution - Add OpenTelemetry integration (traces, metrics, spans) - Add circuit breaker for fault tolerance - Add cached repository wrapper for performance - Add comprehensive validation package - Add Kubernetes client integration for pod management - Add database migrations (allowed_ips, audit_log, rate_limiting, queue, webhooks) - Add network policy and PodDisruptionBudget for k8s - Remove legacy executor and projects/registry packages - Untrack secrets.yaml (now managed via envault) - Add coverage.out to .gitignore - Add e2e test infrastructure with docker-compose - Add comprehensive documentation (API, architecture, operations, plans) - Add golangci-lint config and pre-commit hook Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
73 lines
1.9 KiB
Go
73 lines
1.9 KiB
Go
// Package kubernetes provides Kubernetes-based implementations of port interfaces.
|
|
package kubernetes
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"k8s.io/client-go/kubernetes"
|
|
"k8s.io/client-go/rest"
|
|
"k8s.io/client-go/tools/clientcmd"
|
|
)
|
|
|
|
// ClientConfig holds configuration for the Kubernetes client.
|
|
type ClientConfig struct {
|
|
// Namespace is the K8s namespace to operate in.
|
|
Namespace string
|
|
// Kubeconfig is the path to the kubeconfig file (optional, for local dev).
|
|
Kubeconfig string
|
|
}
|
|
|
|
// NewClient creates a new Kubernetes clientset.
|
|
// When running in-cluster, it uses the service account token.
|
|
// When running locally, it uses the kubeconfig file.
|
|
func NewClient(cfg ClientConfig) (*kubernetes.Clientset, error) {
|
|
var config *rest.Config
|
|
var err error
|
|
|
|
// Try in-cluster config first (when running in K8s)
|
|
config, err = rest.InClusterConfig()
|
|
if err != nil {
|
|
// Fall back to kubeconfig for local development
|
|
kubeconfigPath := cfg.Kubeconfig
|
|
if kubeconfigPath == "" {
|
|
kubeconfigPath = defaultKubeconfigPath()
|
|
}
|
|
|
|
config, err = clientcmd.BuildConfigFromFlags("", kubeconfigPath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create k8s config: %w", err)
|
|
}
|
|
}
|
|
|
|
clientset, err := kubernetes.NewForConfig(config)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create k8s clientset: %w", err)
|
|
}
|
|
|
|
return clientset, nil
|
|
}
|
|
|
|
// NewClientOrNil creates a K8s client, returning nil if it fails.
|
|
// This is useful for graceful fallback to hardcoded projects.
|
|
func NewClientOrNil(cfg ClientConfig) *kubernetes.Clientset {
|
|
client, err := NewClient(cfg)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return client
|
|
}
|
|
|
|
// defaultKubeconfigPath returns the default kubeconfig path.
|
|
func defaultKubeconfigPath() string {
|
|
if kubeconfig := os.Getenv("KUBECONFIG"); kubeconfig != "" {
|
|
return kubeconfig
|
|
}
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return filepath.Join(home, ".kube", "config")
|
|
}
|