Skip to content

Commit

Permalink
Track the resource group revision in status
Browse files Browse the repository at this point in the history
Signed-off-by: Stefan Prodan <[email protected]>
  • Loading branch information
stefanprodan committed Jan 1, 2025
1 parent 8aa7814 commit d5683c5
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 11 deletions.
5 changes: 5 additions & 0 deletions api/v1/resourcegroup_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ type ResourceGroupStatus struct {
// last applied on the cluster.
// +optional
Inventory *ResourceInventory `json:"inventory,omitempty"`

// LastAppliedRevision is the digest of the
// generated resources that were last reconcile.
// +optional
LastAppliedRevision string `json:"lastAppliedRevision,omitempty"`
}

// GetConditions returns the status conditions of the object.
Expand Down
5 changes: 5 additions & 0 deletions config/crd/bases/fluxcd.controlplane.io_resourcegroups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ spec:
required:
- entries
type: object
lastAppliedRevision:
description: |-
LastAppliedRevision is the digest of the
generated resources that were last reconcile.
type: string
lastHandledReconcileAt:
description: |-
LastHandledReconcileAt holds the value of the most recent
Expand Down
34 changes: 23 additions & 11 deletions internal/controller/resourcegroup_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/ext"
"github.com/opencontainers/go-digest"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -157,7 +158,8 @@ func (r *ResourceGroupReconciler) reconcile(ctx context.Context,
}

// Apply the resources to the cluster.
if err := r.apply(ctx, obj, buildResult); err != nil {
applySetDigest, err := r.apply(ctx, obj, buildResult)
if err != nil {
msg := fmt.Sprintf("reconciliation failed: %s", err.Error())
conditions.MarkFalse(obj,
meta.ReadyCondition,
Expand All @@ -168,7 +170,8 @@ func (r *ResourceGroupReconciler) reconcile(ctx context.Context,
return ctrl.Result{}, err
}

// Mark the object as ready.
// Mark the object as ready and set the last applied revision.
obj.Status.LastAppliedRevision = applySetDigest
msg = fmt.Sprintf("Reconciliation finished in %s", fmtDuration(reconcileStart))
conditions.MarkTrue(obj,
meta.ReadyCondition,
Expand Down Expand Up @@ -262,9 +265,11 @@ func (r *ResourceGroupReconciler) checkDependencies(ctx context.Context,
// apply reconciles the resources in the cluster by performing
// a server-side apply, pruning of stale resources and waiting
// for the resources to become ready.
// It returns an error if the apply operation fails, otherwise
// it returns the sha256 digest of the applied resources.
func (r *ResourceGroupReconciler) apply(ctx context.Context,
obj *fluxcdv1.ResourceGroup,
objects []*unstructured.Unstructured) error {
objects []*unstructured.Unstructured) (string, error) {
log := ctrl.LoggerFrom(ctx)
var changeSetLog strings.Builder

Expand All @@ -289,7 +294,7 @@ func (r *ResourceGroupReconciler) apply(ctx context.Context,
// Create the Kubernetes client that runs under impersonation.
kubeClient, statusPoller, err := impersonation.GetClient(ctx)
if err != nil {
return fmt.Errorf("failed to build kube client: %w", err)
return "", fmt.Errorf("failed to build kube client: %w", err)
}

// Create a resource manager to reconcile the resources.
Expand All @@ -300,13 +305,20 @@ func (r *ResourceGroupReconciler) apply(ctx context.Context,
resourceManager.SetOwnerLabels(objects, obj.GetName(), obj.GetNamespace())

if err := normalize.UnstructuredList(objects); err != nil {
return err
return "", err
}

if cm := obj.Spec.CommonMetadata; cm != nil {
ssautil.SetCommonMetadata(objects, cm.Labels, cm.Annotations)
}

// Compute the sha256 digest of the resources.
data, err := ssautil.ObjectsToYAML(objects)
if err != nil {
return "", fmt.Errorf("failed to convert objects to YAML: %w", err)
}
applySetDigest := digest.FromString(data).String()

applyOpts := ssa.DefaultApplyOptions()
applyOpts.Cleanup = ssa.ApplyCleanupOptions{
// Remove the kubectl and helm annotations.
Expand Down Expand Up @@ -347,7 +359,7 @@ func (r *ResourceGroupReconciler) apply(ctx context.Context,
// Apply the resources to the cluster.
changeSet, err := resourceManager.ApplyAllStaged(ctx, objects, applyOpts)
if err != nil {
return err
return "", err
}

// Filter out the resources that have changed.
Expand All @@ -368,7 +380,7 @@ func (r *ResourceGroupReconciler) apply(ctx context.Context,
newInventory := inventory.New()
err = inventory.AddChangeSet(newInventory, changeSet)
if err != nil {
return err
return "", err
}

// Set last applied inventory in status.
Expand All @@ -377,7 +389,7 @@ func (r *ResourceGroupReconciler) apply(ctx context.Context,
// Detect stale resources which are subject to garbage collection.
staleObjects, err := inventory.Diff(oldInventory, newInventory)
if err != nil {
return err
return "", err
}

// Garbage collect stale resources.
Expand All @@ -392,7 +404,7 @@ func (r *ResourceGroupReconciler) apply(ctx context.Context,

deleteSet, err := r.deleteAllStaged(ctx, resourceManager, staleObjects, deleteOpts)
if err != nil {
return err
return "", err
}

if len(deleteSet.Entries) > 0 {
Expand Down Expand Up @@ -421,12 +433,12 @@ func (r *ResourceGroupReconciler) apply(ctx context.Context,
FailFast: true,
}); err != nil {
readyStatus := r.aggregateNotReadyStatus(ctx, kubeClient, objects)
return fmt.Errorf("%w\n%s", err, readyStatus)
return "", fmt.Errorf("%w\n%s", err, readyStatus)
}
log.Info("Health check completed")
}

return nil
return applySetDigest, nil
}

// aggregateNotReadyStatus returns the status of the Flux resources not ready.
Expand Down
8 changes: 8 additions & 0 deletions internal/controller/resourcegroup_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ spec:
},
))

// Check if the status last applied revision was set.
g.Expect(result.Status.LastAppliedRevision).ToNot(BeEmpty())
lastAppliedRevision := result.Status.LastAppliedRevision

// Check if the resources were created and labeled.
resultSA := &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -177,6 +181,10 @@ spec:
},
))

// Check if the status last applied revision was updated.
g.Expect(resultFinal.Status.LastAppliedRevision).ToNot(BeEmpty())
g.Expect(resultFinal.Status.LastAppliedRevision).ToNot(BeEquivalentTo(lastAppliedRevision))

// Check if the resources were deleted.
err = testClient.Get(ctx, client.ObjectKeyFromObject(resultSA), resultSA)
g.Expect(err).To(HaveOccurred())
Expand Down

0 comments on commit d5683c5

Please sign in to comment.