diff --git a/modules/common/annotations/annotations.go b/modules/common/annotations/annotations.go index 468c3cde..4b23a18f 100644 --- a/modules/common/annotations/annotations.go +++ b/modules/common/annotations/annotations.go @@ -29,6 +29,10 @@ const ( // a reconciliation. Changing its value forces a new reconcile event. // Used in multiple operators, therefore defined as a shared constant. ReconcileTriggerAnnotation = "openstack.org/reconcile-trigger" + + // SkipValidationAnnotation is set on a resource to skip webhook validation. + // The annotation key presence is what matters; the value is ignored. + SkipValidationAnnotation = "openstack.org/skip-webhook-validation" ) // IsPaused returns true if the PausedAnnotation key is present on the object. @@ -40,3 +44,13 @@ func IsPaused(obj metav1.Object) bool { _, exists := annotations[PausedAnnotation] return exists } + +// SkipValidation returns true if the SkipValidationAnnotation key is present on the object. +func SkipValidation(obj metav1.Object) bool { + annotations := obj.GetAnnotations() + if annotations == nil { + return false + } + _, exists := annotations[SkipValidationAnnotation] + return exists +} diff --git a/modules/common/annotations/annotations_test.go b/modules/common/annotations/annotations_test.go index 0a310831..34dcf899 100644 --- a/modules/common/annotations/annotations_test.go +++ b/modules/common/annotations/annotations_test.go @@ -69,3 +69,48 @@ func TestIsPaused(t *testing.T) { g.Expect(IsPaused(obj)).To(BeTrue()) }) } + +func TestSkipValidation(t *testing.T) { + t.Run("returns false when annotations are nil", func(t *testing.T) { + g := NewWithT(t) + obj := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + } + g.Expect(SkipValidation(obj)).To(BeFalse()) + }) + + t.Run("returns false when annotation is not present", func(t *testing.T) { + g := NewWithT(t) + obj := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Annotations: map[string]string{"other": "value"}, + }, + } + g.Expect(SkipValidation(obj)).To(BeFalse()) + }) + + t.Run("returns true when annotation is present with empty value", func(t *testing.T) { + g := NewWithT(t) + obj := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Annotations: map[string]string{SkipValidationAnnotation: ""}, + }, + } + g.Expect(SkipValidation(obj)).To(BeTrue()) + }) + + t.Run("returns true when annotation is present with any value", func(t *testing.T) { + g := NewWithT(t) + obj := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Annotations: map[string]string{SkipValidationAnnotation: "true"}, + }, + } + g.Expect(SkipValidation(obj)).To(BeTrue()) + }) +}