diff --git a/api/v1beta1/condition_types.go b/api/v1beta1/condition_types.go index 972dad33..dd635f93 100644 --- a/api/v1beta1/condition_types.go +++ b/api/v1beta1/condition_types.go @@ -17,6 +17,10 @@ limitations under the License. package v1beta1 const ( + // HealthyCondition is the condition type used + // to record the last health assessment result. + HealthyCondition string = "Healthy" + // PruneFailedReason represents the fact that the // pruning of the Kustomization failed. PruneFailedReason string = "PruneFailed" diff --git a/api/v1beta1/kustomization_types.go b/api/v1beta1/kustomization_types.go index 85d9e8f9..b5dd906c 100644 --- a/api/v1beta1/kustomization_types.go +++ b/api/v1beta1/kustomization_types.go @@ -17,6 +17,7 @@ limitations under the License. package v1beta1 import ( + apimeta "k8s.io/apimachinery/pkg/api/meta" "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -184,6 +185,16 @@ func KustomizationProgressing(k Kustomization) Kustomization { return k } +// SetKustomizationHealthiness sets the HealthyCondition status for a Kustomization. +func SetKustomizationHealthiness(k *Kustomization, status metav1.ConditionStatus, reason, message string) { + switch len(k.Spec.HealthChecks) { + case 0: + apimeta.RemoveStatusCondition(k.GetStatusConditions(), HealthyCondition) + default: + meta.SetResourceCondition(k, HealthyCondition, status, reason, trimString(message, MaxConditionMessageLength)) + } +} + // SetKustomizeReadiness sets the ReadyCondition, ObservedGeneration, and LastAttemptedRevision, // on the Kustomization. func SetKustomizationReadiness(k *Kustomization, status metav1.ConditionStatus, reason, message string, revision string) { @@ -205,6 +216,7 @@ func KustomizationNotReady(k Kustomization, revision, reason, message string) Ku // including a Snapshot. func KustomizationNotReadySnapshot(k Kustomization, snapshot *Snapshot, revision, reason, message string) Kustomization { SetKustomizationReadiness(&k, metav1.ConditionFalse, reason, trimString(message, MaxConditionMessageLength), revision) + SetKustomizationHealthiness(&k, metav1.ConditionFalse, reason, reason) k.Status.Snapshot = snapshot k.Status.LastAttemptedRevision = revision return k @@ -213,6 +225,7 @@ func KustomizationNotReadySnapshot(k Kustomization, snapshot *Snapshot, revision // KustomizationReady registers a successful apply attempt of the given Kustomization. func KustomizationReady(k Kustomization, snapshot *Snapshot, revision, reason, message string) Kustomization { SetKustomizationReadiness(&k, metav1.ConditionTrue, reason, trimString(message, MaxConditionMessageLength), revision) + SetKustomizationHealthiness(&k, metav1.ConditionTrue, reason, reason) k.Status.Snapshot = snapshot k.Status.LastAppliedRevision = revision return k diff --git a/controllers/kustomization_controller.go b/controllers/kustomization_controller.go index 6a5bc100..42d10577 100644 --- a/controllers/kustomization_controller.go +++ b/controllers/kustomization_controller.go @@ -695,10 +695,10 @@ func (r *KustomizationReconciler) checkHealth(ctx context.Context, statusPoller return err } - readiness := apimeta.FindStatusCondition(kustomization.Status.Conditions, meta.ReadyCondition) - ready := readiness != nil && readiness.Status == metav1.ConditionTrue + healthiness := apimeta.FindStatusCondition(kustomization.Status.Conditions, kustomizev1.HealthyCondition) + healthy := healthiness != nil && healthiness.Status == metav1.ConditionTrue - if !ready || (kustomization.Status.LastAppliedRevision != revision && changed) { + if !healthy || (kustomization.Status.LastAppliedRevision != revision && changed) { r.event(ctx, kustomization, revision, events.EventSeverityInfo, "Health check passed", nil) } return nil diff --git a/controllers/kustomization_controller_test.go b/controllers/kustomization_controller_test.go index 298941dd..02fa344d 100644 --- a/controllers/kustomization_controller_test.go +++ b/controllers/kustomization_controller_test.go @@ -25,6 +25,7 @@ import ( . "github.com/onsi/ginkgo/extensions/table" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" + apimeta "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/clientcmd" @@ -170,26 +171,35 @@ var _ = Describe("KustomizationReconciler", func() { Suspend: false, Timeout: nil, Validation: "client", + HealthChecks: []meta.NamespacedObjectKindReference{ + { + APIVersion: "v1", + Kind: "ServiceAccount", + Name: "test", + Namespace: "test", + }, + }, }, } Expect(k8sClient.Create(context.Background(), k)).Should(Succeed()) defer k8sClient.Delete(context.Background(), k) got := &kustomizev1.Kustomization{} - var cond metav1.Condition + var readyCondition metav1.Condition Eventually(func() bool { _ = k8sClient.Get(context.Background(), kName, got) for _, c := range got.Status.Conditions { if c.Reason == t.waitForReason { - cond = c + readyCondition = c return true } } return false }, timeout, interval).Should(BeTrue()) - Expect(cond.Status).To(Equal(t.expectStatus)) + Expect(readyCondition.Status).To(Equal(t.expectStatus)) Expect(got.Status.LastAppliedRevision).To(Equal(t.expectRevision)) + Expect(apimeta.IsStatusConditionTrue(got.Status.Conditions, kustomizev1.HealthyCondition)).To(BeTrue()) ns := &corev1.Namespace{} Expect(k8sClient.Get(context.Background(), types.NamespacedName{Name: "test"}, ns)).Should(Succeed())