mirror of
https://github.com/harivansh-afk/agentikube.git
synced 2026-04-15 11:02:16 +00:00
92 lines
2.5 KiB
Go
92 lines
2.5 KiB
Go
package kube
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/types"
|
|
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
|
|
"k8s.io/client-go/discovery"
|
|
"k8s.io/client-go/discovery/cached/memory"
|
|
"k8s.io/client-go/restmapper"
|
|
yamlserializer "k8s.io/apimachinery/pkg/runtime/serializer/yaml"
|
|
)
|
|
|
|
// ServerSideApply splits a multi-document YAML into individual resources
|
|
// and applies each one using server-side apply with the "agentikube" field manager.
|
|
func (c *Client) ServerSideApply(ctx context.Context, manifests []byte) error {
|
|
decoder := k8syaml.NewYAMLOrJSONDecoder(bytes.NewReader(manifests), 4096)
|
|
|
|
discoveryClient, ok := c.Clientset().Discovery().(*discovery.DiscoveryClient)
|
|
if !ok {
|
|
return fmt.Errorf("failed to get discovery client")
|
|
}
|
|
cachedDiscovery := memory.NewMemCacheClient(discoveryClient)
|
|
mapper := restmapper.NewDeferredDiscoveryRESTMapper(cachedDiscovery)
|
|
|
|
deserializer := yamlserializer.NewDecodingSerializer(unstructured.UnstructuredJSONScheme)
|
|
|
|
for {
|
|
var rawObj unstructured.Unstructured
|
|
if err := decoder.Decode(&rawObj); err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
return fmt.Errorf("decoding YAML document: %w", err)
|
|
}
|
|
|
|
// Skip empty documents
|
|
if len(rawObj.Object) == 0 {
|
|
continue
|
|
}
|
|
|
|
// Re-encode to JSON for the patch body
|
|
rawJSON, err := rawObj.MarshalJSON()
|
|
if err != nil {
|
|
return fmt.Errorf("marshaling to JSON: %w", err)
|
|
}
|
|
|
|
// Decode to get the GVK
|
|
obj := &unstructured.Unstructured{}
|
|
_, gvk, err := deserializer.Decode(rawJSON, nil, obj)
|
|
if err != nil {
|
|
return fmt.Errorf("deserializing object: %w", err)
|
|
}
|
|
|
|
// Map GVK to GVR using the REST mapper
|
|
mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
|
if err != nil {
|
|
return fmt.Errorf("mapping GVK %s to GVR: %w", gvk.String(), err)
|
|
}
|
|
|
|
gvr := mapping.Resource
|
|
name := obj.GetName()
|
|
namespace := obj.GetNamespace()
|
|
|
|
applyOpts := metav1.ApplyOptions{
|
|
FieldManager: "agentikube",
|
|
}
|
|
|
|
// Apply using the dynamic client - handle namespaced vs cluster-scoped
|
|
if namespace != "" {
|
|
_, err = c.Dynamic().Resource(gvr).Namespace(namespace).Patch(
|
|
ctx, name, types.ApplyPatchType, rawJSON, applyOpts.ToPatchOptions(),
|
|
)
|
|
} else {
|
|
_, err = c.Dynamic().Resource(gvr).Patch(
|
|
ctx, name, types.ApplyPatchType, rawJSON, applyOpts.ToPatchOptions(),
|
|
)
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("applying %s/%s: %w", gvk.Kind, name, err)
|
|
}
|
|
|
|
fmt.Printf("applied %s/%s\n", gvk.Kind, name)
|
|
}
|
|
|
|
return nil
|
|
}
|