Add Healthy status condition

- record the last health assessment result in a dedicated status condition
- use the condition status when issuing events to prevent notifications spam

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
This commit is contained in:
Stefan Prodan 2021-02-02 13:15:10 +02:00
parent 26ec841147
commit 5e17dd48f4
No known key found for this signature in database
GPG Key ID: 3299AEB0E4085BAF
4 changed files with 33 additions and 6 deletions

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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())