Skip to content

Commit

Permalink
Merge pull request #720 from fluxcd/ssa-class-stage
Browse files Browse the repository at this point in the history
Reconcile Kubernetes class type objects in a dedicated stage
  • Loading branch information
stefanprodan authored Sep 2, 2022
2 parents dca8c48 + 928f22d commit 3d17bc9
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 17 deletions.
61 changes: 47 additions & 14 deletions controllers/kustomization_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -715,10 +715,14 @@ func (r *KustomizationReconciler) apply(ctx context.Context, manager *ssa.Resour
}

// contains only CRDs and Namespaces
var stageOne []*unstructured.Unstructured
var defStage []*unstructured.Unstructured

// contains all objects except for CRDs and Namespaces
var stageTwo []*unstructured.Unstructured
// contains only Kubernetes Class types e.g.: RuntimeClass, PriorityClass,
// StorageClas, VolumeSnapshotClass, IngressClass, GatewayClass, ClusterClass, etc
var classStage []*unstructured.Unstructured

// contains all objects except for CRDs, Namespaces and Class type objects
var resStage []*unstructured.Unstructured

// contains the objects' metadata after apply
resultSet := ssa.NewChangeSet()
Expand All @@ -730,33 +734,62 @@ func (r *KustomizationReconciler) apply(ctx context.Context, manager *ssa.Resour
ssa.FmtUnstructured(u))
}

if ssa.IsClusterDefinition(u) {
stageOne = append(stageOne, u)
} else {
stageTwo = append(stageTwo, u)
switch {
case ssa.IsClusterDefinition(u):
defStage = append(defStage, u)
case strings.HasSuffix(u.GetKind(), "Class"):
classStage = append(classStage, u)
default:
resStage = append(resStage, u)
}

}

var changeSetLog strings.Builder

// validate, apply and wait for CRDs and Namespaces to register
if len(stageOne) > 0 {
changeSet, err := manager.ApplyAll(ctx, stageOne, applyOpts)
if len(defStage) > 0 {
changeSet, err := manager.ApplyAll(ctx, defStage, applyOpts)
if err != nil {
return false, nil, err
}
resultSet.Append(changeSet.Entries)

if changeSet != nil && len(changeSet.Entries) > 0 {
log.Info("server-side apply completed", "output", changeSet.ToMap())
log.Info("server-side apply for cluster definitions completed", "output", changeSet.ToMap())
for _, change := range changeSet.Entries {
if change.Action != string(ssa.UnchangedAction) {
changeSetLog.WriteString(change.String() + "\n")
}
}
}

if err := manager.Wait(defStage, ssa.WaitOptions{
Interval: 2 * time.Second,
Timeout: kustomization.GetTimeout(),
}); err != nil {
return false, nil, err
}
}

// validate, apply and wait for Class type objects to register
if len(classStage) > 0 {
changeSet, err := manager.ApplyAll(ctx, classStage, applyOpts)
if err != nil {
return false, nil, err
}
resultSet.Append(changeSet.Entries)

if changeSet != nil && len(changeSet.Entries) > 0 {
log.Info("server-side apply for cluster class types completed", "output", changeSet.ToMap())
for _, change := range changeSet.Entries {
if change.Action != string(ssa.UnchangedAction) {
changeSetLog.WriteString(change.String() + "\n")
}
}
}

if err := manager.Wait(stageOne, ssa.WaitOptions{
if err := manager.Wait(classStage, ssa.WaitOptions{
Interval: 2 * time.Second,
Timeout: kustomization.GetTimeout(),
}); err != nil {
Expand All @@ -765,9 +798,9 @@ func (r *KustomizationReconciler) apply(ctx context.Context, manager *ssa.Resour
}

// sort by kind, validate and apply all the others objects
sort.Sort(ssa.SortableUnstructureds(stageTwo))
if len(stageTwo) > 0 {
changeSet, err := manager.ApplyAll(ctx, stageTwo, applyOpts)
sort.Sort(ssa.SortableUnstructureds(resStage))
if len(resStage) > 0 {
changeSet, err := manager.ApplyAll(ctx, resStage, applyOpts)
if err != nil {
return false, nil, fmt.Errorf("%w\n%s", err, changeSetLog.String())
}
Expand Down
5 changes: 2 additions & 3 deletions controllers/kustomization_fetcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package controllers
import (
"context"
"fmt"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -135,10 +136,8 @@ stringData:
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
ready := apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition)
return ready.Reason == meta.ProgressingReason
return strings.Contains(ready.Message, "artifact not found")
}, timeout, time.Second).Should(BeTrue())

g.Expect(apimeta.FindStatusCondition(resultK.Status.Conditions, meta.ReadyCondition).Message).To(ContainSubstring("artifact not found"))
})

t.Run("recovers after not found errors", func(t *testing.T) {
Expand Down

0 comments on commit 3d17bc9

Please # to comment.