diff --git a/controllers/nstemplatetier/nstemplatetier_controller.go b/controllers/nstemplatetier/nstemplatetier_controller.go index 24673bc9d..f31e193c5 100644 --- a/controllers/nstemplatetier/nstemplatetier_controller.go +++ b/controllers/nstemplatetier/nstemplatetier_controller.go @@ -9,7 +9,10 @@ import ( toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/host-operator/controllers/toolchainconfig" "github.com/codeready-toolchain/host-operator/pkg/templates/nstemplatetiers" + "github.com/codeready-toolchain/toolchain-common/pkg/condition" "github.com/redhat-cop/operator-utils/pkg/util" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -71,14 +74,21 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl. // check if the `status.revisions` field is up-to-date and create a TTR for each TierTemplate if created, err := r.ensureRevision(ctx, tier); err != nil { - // todo add/update ready condition false in the NSTemplateTier when something fails + // set ready condition false in the NSTemplateTier + if err := r.setStatusFailed(ctx, tier, FailedCondition(toolchainv1alpha1.NSTemplateTierUnableToEnsureRevisionsReason, err.Error())); err != nil { + return reconcile.Result{}, err + } + return reconcile.Result{}, fmt.Errorf("unable to create new TierTemplateRevision after NSTemplateTier changed: %w", err) } else if created { logger.Info("Requeue after creating a new TTR") return reconcile.Result{RequeueAfter: time.Second}, nil } - return reconcile.Result{}, nil + // set ready condition on NSTemplateTier + err = r.updateStatus(ctx, tier, ReadyCondition()) + + return reconcile.Result{}, err } // ensureRevision ensures that there is a TierTemplateRevision CR for each of the TierTemplate. @@ -221,3 +231,43 @@ func NewTTR(tierTmpl *toolchainv1alpha1.TierTemplate, nsTmplTier *toolchainv1alp return ttr } + +func (r *Reconciler) setStatusFailed(ctx context.Context, tmplTier *toolchainv1alpha1.NSTemplateTier, failedCondition toolchainv1alpha1.Condition) error { + if err := r.updateStatus( + ctx, + tmplTier, + failedCondition, + ); err != nil { + logger := log.FromContext(ctx) + logger.Error(err, "unable to update NSTemplateTier condition") + return err + } + return nil +} + +func (r *Reconciler) updateStatus(ctx context.Context, tmplTier *toolchainv1alpha1.NSTemplateTier, conditions ...toolchainv1alpha1.Condition) error { + var updated bool + tmplTier.Status.Conditions, updated = condition.AddOrUpdateStatusConditions(tmplTier.Status.Conditions, conditions...) + if !updated { + // Nothing changed + return nil + } + return r.Client.Status().Update(ctx, tmplTier) +} + +func FailedCondition(reason string, cause string) toolchainv1alpha1.Condition { + return toolchainv1alpha1.Condition{ + Type: toolchainv1alpha1.ConditionReady, + Status: corev1.ConditionFalse, + Reason: reason, + Message: cause, + } +} + +func ReadyCondition() toolchainv1alpha1.Condition { + return toolchainv1alpha1.Condition{ + Type: toolchainv1alpha1.ConditionReady, + Status: corev1.ConditionTrue, + Reason: toolchainv1alpha1.NSTemplateTierProvisionedReason, + } +} diff --git a/controllers/nstemplatetier/nstemplatetier_controller_test.go b/controllers/nstemplatetier/nstemplatetier_controller_test.go index df82a22cd..23aa79499 100644 --- a/controllers/nstemplatetier/nstemplatetier_controller_test.go +++ b/controllers/nstemplatetier/nstemplatetier_controller_test.go @@ -115,6 +115,9 @@ func TestReconcile(t *testing.T) { require.Equal(t, reconcile.Result{Requeue: false}, res) // no reconcile // revisions are the same tiertest.AssertThatNSTemplateTier(t, "base1ns", cl). + HasConditions( + nstemplatetier.ReadyCondition(), + ). HasStatusTierTemplateRevisions(tierTemplatesRefs) // no TierTemplateRevision CRs were created tiertemplaterevision.AssertThatTTRs(t, cl, base1nsTier.GetNamespace()).DoNotExist() @@ -161,6 +164,9 @@ func TestReconcile(t *testing.T) { require.Equal(t, reconcile.Result{Requeue: false}, res) // no reconcile // revisions are the same tiertest.AssertThatNSTemplateTier(t, "base1ns", cl). + HasConditions( + nstemplatetier.ReadyCondition(), + ). HasStatusTierTemplateRevisions(tierTemplatesRefs) // expected TierTemplateRevision CRs are still there ttrs := toolchainv1alpha1.TierTemplateRevisionList{} @@ -268,9 +274,13 @@ func TestReconcile(t *testing.T) { _, err := r.Reconcile(context.TODO(), req) // then // we expect an error caused by the absence of the tiertemplate for the `code` namespace CR - require.ErrorContains(t, err, "tiertemplates.toolchain.dev.openshift.com \"base1ns-code-123456new\" not found") + errCause := "tiertemplates.toolchain.dev.openshift.com \"base1ns-code-123456new\" not found" + require.ErrorContains(t, err, errCause) // the revisions field also should remain empty tiertest.AssertThatNSTemplateTier(t, "base1ns", cl). + HasConditions( + nstemplatetier.FailedCondition(toolchainv1alpha1.NSTemplateTierUnableToEnsureRevisionsReason, errCause), + ). HasNoStatusTierTemplateRevisions() // and the TierTemplateRevision CRs are not created tiertemplaterevision.AssertThatTTRs(t, cl, base1nsTier.GetNamespace()).DoNotExist() diff --git a/go.mod b/go.mod index 0b170d4fe..f7915f917 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/codeready-toolchain/host-operator require ( cloud.google.com/go/recaptchaenterprise/v2 v2.13.0 - github.com/codeready-toolchain/api v0.0.0-20250227073728-5999971adb48 + github.com/codeready-toolchain/api v0.0.0-20250304130838-c9c2ff18f4de github.com/codeready-toolchain/toolchain-common v0.0.0-20250303095208-d379ee86d136 github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-bindata/go-bindata v3.1.2+incompatible diff --git a/go.sum b/go.sum index b6ab3ed94..42fa09c37 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,8 @@ github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtM github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/codeready-toolchain/api v0.0.0-20250227073728-5999971adb48 h1:jqGcYw4KdQzqe5WEp+06HXBRyosAktgO5Y6ADs+NF5A= -github.com/codeready-toolchain/api v0.0.0-20250227073728-5999971adb48/go.mod h1:gPwicZPTmRm1PF75ysEYXaYKdXoFgwgCggTJd1oYmOs= +github.com/codeready-toolchain/api v0.0.0-20250304130838-c9c2ff18f4de h1:64key4W/2oUqzwt3z4ZOanPGgHKJMiKUwYaUUpeUO8Q= +github.com/codeready-toolchain/api v0.0.0-20250304130838-c9c2ff18f4de/go.mod h1:gPwicZPTmRm1PF75ysEYXaYKdXoFgwgCggTJd1oYmOs= github.com/codeready-toolchain/toolchain-common v0.0.0-20250303095208-d379ee86d136 h1:IqJ1tXl6IJuCqAW9MSji9TbMX2zWLBMEWD82u6+yui8= github.com/codeready-toolchain/toolchain-common v0.0.0-20250303095208-d379ee86d136/go.mod h1:mNRKnxjBHxggT03t6TwGJT5AZvmHMn6oQ32DrkGwV+w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/test/nstemplatetier/assertion.go b/test/nstemplatetier/assertion.go index 7af179809..395275184 100644 --- a/test/nstemplatetier/assertion.go +++ b/test/nstemplatetier/assertion.go @@ -61,3 +61,10 @@ func (a *Assertion) HasNoStatusTierTemplateRevisions() *Assertion { require.Nil(a.t, a.tier.Status.Revisions) return a } + +func (a *Assertion) HasConditions(expected ...toolchainv1alpha1.Condition) *Assertion { + err := a.loadResource() + require.NoError(a.t, err) + test.AssertConditionsMatch(a.t, a.tier.Status.Conditions, expected...) + return a +}