From f0d56eddc65fe6d76d3b81c74843ac48db4193ec Mon Sep 17 00:00:00 2001 From: Markus Rudy Date: Thu, 29 Feb 2024 10:43:23 +0100 Subject: [PATCH] e2e: deploy unstructured yaml --- e2e/internal/kubeclient/deploy.go | 42 +++++++++++++++++++++++++++ e2e/internal/kubeclient/kubeclient.go | 17 +++++++++-- 2 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 e2e/internal/kubeclient/deploy.go diff --git a/e2e/internal/kubeclient/deploy.go b/e2e/internal/kubeclient/deploy.go new file mode 100644 index 0000000000..ab012463da --- /dev/null +++ b/e2e/internal/kubeclient/deploy.go @@ -0,0 +1,42 @@ +package kubeclient + +import ( + "context" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/client-go/dynamic" +) + +func (c *Kubeclient) resourceInterfaceFor(obj *unstructured.Unstructured) (dynamic.ResourceInterface, error) { + dyn := dynamic.New(c.client.RESTClient()) + gvk := obj.GroupVersionKind() + + mapping, err := c.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + return nil, fmt.Errorf("could not get resource for %#v: %w", gvk, err) + } + c.log.Info("found mapping", "resource", mapping.Resource) + ri := dyn.Resource(mapping.Resource) + if namespace := obj.GetNamespace(); namespace != "" { + return ri.Namespace(namespace), nil + } + return ri, nil +} + +// Deploy a set of namespaced manifests to a namespace. +func (c *Kubeclient) Deploy(ctx context.Context, manifests ...*unstructured.Unstructured) error { + for _, obj := range manifests { + ri, err := c.resourceInterfaceFor(obj) + if err != nil { + return err + } + applied, err := ri.Apply(ctx, obj.GetName(), obj, metav1.ApplyOptions{Force: true, FieldManager: "e2e-test"}) + if err != nil { + return fmt.Errorf("could not apply %s %s in namespace %s: %w", obj.GetKind(), obj.GetName(), obj.GetNamespace(), err) + } + c.log.Info("object applied", "namespace", applied.GetNamespace(), "kind", applied.GetKind(), "name", applied.GetName()) + } + return nil +} diff --git a/e2e/internal/kubeclient/kubeclient.go b/e2e/internal/kubeclient/kubeclient.go index 8eeedd5cdb..36ff61852a 100644 --- a/e2e/internal/kubeclient/kubeclient.go +++ b/e2e/internal/kubeclient/kubeclient.go @@ -14,10 +14,12 @@ import ( "testing" v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/remotecommand" ) @@ -30,6 +32,9 @@ type Kubeclient struct { client *kubernetes.Clientset // config is the "Kubeconfig" for the client config *rest.Config + + // restMapper maps objects to REST endpoints + restMapper meta.RESTMapper } // New creates a new Kubeclient from a given Kubeconfig. @@ -39,10 +44,16 @@ func New(config *rest.Config, log *slog.Logger) (*Kubeclient, error) { return nil, fmt.Errorf("creating kubernetes client: %w", err) } + resources, err := restmapper.GetAPIGroupResources(client.Discovery()) + if err != nil { + return nil, fmt.Errorf("fetching resource groups: %w", err) + } + return &Kubeclient{ - log: log, - client: client, - config: config, + log: log, + client: client, + config: config, + restMapper: restmapper.NewDiscoveryRESTMapper(resources), }, nil }