Skip to content

Commit

Permalink
feat: unstructured cluster patch helper (#48)
Browse files Browse the repository at this point in the history
* refactor: using capi helper for unstructured patch

Signed-off-by: Dario Tranchitella <[email protected]>

* feat: caching cluster unstructured data

Signed-off-by: Dario Tranchitella <[email protected]>

* chore(rbac): caching cluster unstructured data

Signed-off-by: Dario Tranchitella <[email protected]>

---------

Signed-off-by: Dario Tranchitella <[email protected]>
  • Loading branch information
prometherion authored Oct 24, 2024
1 parent fa48db6 commit dc1962a
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 43 deletions.
12 changes: 10 additions & 2 deletions config/control-plane-components.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13341,11 +13341,19 @@ rules:
- hetznerclusters
- ionoscloudclusters
- kubevirtclusters
- kubevirtclusters/status
- nutanixclusters
- nutanixclusters/status
- openstackclusters
- packetclusters
verbs:
- get
- list
- patch
- watch
- apiGroups:
- infrastructure.cluster.x-k8s.io
resources:
- kubevirtclusters/status
- nutanixclusters/status
- packetclusters/status
verbs:
- patch
Expand Down
12 changes: 10 additions & 2 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,19 @@ rules:
- hetznerclusters
- ionoscloudclusters
- kubevirtclusters
- kubevirtclusters/status
- nutanixclusters
- nutanixclusters/status
- openstackclusters
- packetclusters
verbs:
- get
- list
- patch
- watch
- apiGroups:
- infrastructure.cluster.x-k8s.io
resources:
- kubevirtclusters/status
- nutanixclusters/status
- packetclusters/status
verbs:
- patch
Expand Down
82 changes: 43 additions & 39 deletions controllers/kamajicontrolplane_controller_cluster_patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package controllers

import (
"context"
"encoding/json"
"fmt"
"net"
"strconv"
Expand All @@ -16,6 +15,7 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/retry"
capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/cluster-api/util/patch"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/clastix/cluster-api-control-plane-provider-kamaji/api/v1alpha1"
Expand Down Expand Up @@ -125,7 +125,7 @@ func (r *KamajiControlPlaneReconciler) checkOrPatchGenericCluster(ctx context.Co
return nil
}

//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsclusters;hetznerclusters;kubevirtclusters;nutanixclusters;packetclusters;ionoscloudclusters,verbs=patch
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsclusters;hetznerclusters;kubevirtclusters;nutanixclusters;packetclusters;ionoscloudclusters,verbs=patch;get;list;watch
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=kubevirtclusters/status;nutanixclusters/status;packetclusters/status,verbs=patch

func (r *KamajiControlPlaneReconciler) patchGenericCluster(ctx context.Context, cluster capiv1beta1.Cluster, endpoint string, port int64, patchStatus bool) error {
Expand All @@ -135,37 +135,30 @@ func (r *KamajiControlPlaneReconciler) patchGenericCluster(ctx context.Context,
infraCluster.SetName(cluster.Spec.InfrastructureRef.Name)
infraCluster.SetNamespace(cluster.Spec.InfrastructureRef.Namespace)

specPatch, err := json.Marshal(map[string]interface{}{
"spec": map[string]interface{}{
"controlPlaneEndpoint": map[string]interface{}{
"host": endpoint,
"port": port,
},
},
})
if err != nil {
return errors.Wrap(err, fmt.Sprintf("unable to marshal %s spec patch", infraCluster.GetKind()))
if err := r.client.Get(ctx, types.NamespacedName{Name: infraCluster.GetName(), Namespace: infraCluster.GetNamespace()}, &infraCluster); err != nil {
return errors.Wrap(err, fmt.Sprintf("cannot retrieve the %s resource", infraCluster.GetKind()))
}

if err = r.client.Patch(ctx, &infraCluster, client.RawPatch(types.MergePatchType, specPatch)); err != nil {
return errors.Wrap(err, fmt.Sprintf("cannot perform PATCH update for the %s resource", infraCluster.GetKind()))
patchHelper, err := patch.NewHelper(&infraCluster, r.client)
if err != nil {
return errors.Wrap(err, "unable to create patch helper")
}

if !patchStatus {
return nil
if err = unstructured.SetNestedMap(infraCluster.Object, map[string]interface{}{
"host": endpoint,
"port": port,
}, "spec", "controlPlaneEndpoint"); err != nil {
return errors.Wrap(err, fmt.Sprintf("unable to set unstructured %s spec patch", infraCluster.GetKind()))
}

statusPatch, err := json.Marshal(map[string]interface{}{
"status": map[string]interface{}{
"ready": true,
},
})
if err != nil {
return errors.Wrap(err, fmt.Sprintf("unable to marshal %s status patch", infraCluster.GetKind()))
if patchStatus {
if err = unstructured.SetNestedField(infraCluster.Object, true, "status", "ready"); err != nil {
return errors.Wrap(err, fmt.Sprintf("unable to set unstructured %s status patch", infraCluster.GetKind()))
}
}

if err = r.client.Status().Patch(ctx, &infraCluster, client.RawPatch(types.MergePatchType, statusPatch)); err != nil {
return errors.Wrap(err, fmt.Sprintf("cannot perform PATCH update for the %s status", infraCluster.GetKind()))
if err = patchHelper.Patch(ctx, &infraCluster); err != nil {
return errors.Wrap(err, fmt.Sprintf("cannot perform PATCH update for the %s resource", infraCluster.GetKind()))
}

return nil
Expand All @@ -184,14 +177,19 @@ func (r *KamajiControlPlaneReconciler) checkGenericCluster(ctx context.Context,
return errors.Wrap(err, fmt.Sprintf("cannot retrieve the %s resource", gkc.GetKind()))
}

controlPlaneEndpointUn := gkc.Object["spec"].(map[string]interface{})["controlPlaneEndpoint"] //nolint:forcetypeassert
if controlPlaneEndpointUn == nil {
return *NewUnmanagedControlPlaneAddressError(gkc.GetKind())
cpHost, _, err := unstructured.NestedString(gkc.Object, "spec", "controlPlaneEndpoint", "host")
if err != nil {
return errors.Wrap(err, "cannot extract control plane endpoint host")
}

controlPlaneEndpoint := controlPlaneEndpointUn.(map[string]interface{}) //nolint:forcetypeassert
if cpHost == "" {
return *NewUnmanagedControlPlaneAddressError(gkc.GetKind())
}

cpHost, cpPort := controlPlaneEndpoint["host"].(string), controlPlaneEndpoint["port"].(int64) //nolint:forcetypeassert
cpPort, _, err := unstructured.NestedInt64(gkc.Object, "spec", "controlPlaneEndpoint", "port")
if err != nil {
return errors.Wrap(err, "cannot extract control plane endpoint host")
}

if len(cpHost) == 0 && cpPort == 0 {
return *NewUnmanagedControlPlaneAddressError(gkc.GetKind())
Expand All @@ -208,7 +206,7 @@ func (r *KamajiControlPlaneReconciler) checkGenericCluster(ctx context.Context,
return nil
}

//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=openstackclusters,verbs=patch
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=openstackclusters,verbs=patch;get;list;watch

func (r *KamajiControlPlaneReconciler) patchOpenStackCluster(ctx context.Context, cluster capiv1beta1.Cluster, endpoint string, port int64) error {
osc := unstructured.Unstructured{}
Expand All @@ -217,17 +215,23 @@ func (r *KamajiControlPlaneReconciler) patchOpenStackCluster(ctx context.Context
osc.SetName(cluster.Spec.InfrastructureRef.Name)
osc.SetNamespace(cluster.Spec.InfrastructureRef.Namespace)

mergePatch, err := json.Marshal(map[string]interface{}{
"spec": map[string]interface{}{
"apiServerFixedIP": endpoint,
"apiServerPort": port,
},
})
if err := r.client.Get(ctx, types.NamespacedName{Name: osc.GetName(), Namespace: osc.GetNamespace()}, &osc); err != nil {
return errors.Wrap(err, fmt.Sprintf("cannot retrieve the %s resource", osc.GetKind()))
}

patchHelper, err := patch.NewHelper(&osc, r.client)
if err != nil {
return errors.Wrap(err, "unable to marshal OpenStackCluster patch")
return errors.Wrap(err, "unable to create patch helper")
}

if err = unstructured.SetNestedMap(osc.Object, map[string]interface{}{
"apiServerFixedIP": endpoint,
"apiServerPort": port,
}, "spec"); err != nil {
return errors.Wrap(err, fmt.Sprintf("unable to set unstructured %s spec patch", osc.GetKind()))
}

if err = r.client.Patch(ctx, &osc, client.RawPatch(types.MergePatchType, mergePatch)); err != nil {
if err = patchHelper.Patch(ctx, &osc); err != nil {
return errors.Wrap(err, "cannot perform PATCH update for the OpenStackCluster resource")
}

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ require (
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/gobuffalo/flect v1.0.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
Expand Down
Loading

0 comments on commit dc1962a

Please sign in to comment.