agentikube/internal/kube/client.go
2026-02-07 13:49:11 -05:00

76 lines
2.1 KiB
Go

package kube
import (
"context"
"fmt"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
// Client wraps the Kubernetes dynamic client, typed clientset, and REST config.
type Client struct {
dynamic dynamic.Interface
clientset kubernetes.Interface
restConfig *rest.Config
}
func (c *Client) Dynamic() dynamic.Interface { return c.dynamic }
func (c *Client) Clientset() kubernetes.Interface { return c.clientset }
func (c *Client) RestConfig() *rest.Config { return c.restConfig }
// NewClient creates a Kubernetes client using the default kubeconfig loading
// rules (KUBECONFIG env var or ~/.kube/config).
func NewClient() (*Client, error) {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
configOverrides := &clientcmd.ConfigOverrides{}
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
restConfig, err := kubeConfig.ClientConfig()
if err != nil {
return nil, fmt.Errorf("loading kubeconfig: %w", err)
}
dynamicClient, err := dynamic.NewForConfig(restConfig)
if err != nil {
return nil, fmt.Errorf("creating dynamic client: %w", err)
}
clientset, err := kubernetes.NewForConfig(restConfig)
if err != nil {
return nil, fmt.Errorf("creating clientset: %w", err)
}
return &Client{
dynamic: dynamicClient,
clientset: clientset,
restConfig: restConfig,
}, nil
}
// EnsureNamespace creates the namespace if it does not already exist.
func (c *Client) EnsureNamespace(ctx context.Context, name string) error {
_, err := c.clientset.CoreV1().Namespaces().Get(ctx, name, metav1.GetOptions{})
if err == nil {
return nil
}
if !errors.IsNotFound(err) {
return fmt.Errorf("checking namespace %q: %w", name, err)
}
ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}
_, err = c.clientset.CoreV1().Namespaces().Create(ctx, ns, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("creating namespace %q: %w", name, err)
}
return nil
}