From c95528abe37621b80b890df5e2512cb894a95956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Sch=C3=BCnemann?= Date: Wed, 5 Nov 2025 14:05:33 +0100 Subject: [PATCH 1/3] fix: ensure compliant condition type and reason --- pkg/conditions/updater.go | 4 ++-- pkg/controller/status_updater.go | 20 ++++++++++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/pkg/conditions/updater.go b/pkg/conditions/updater.go index 458a42d..b022e4e 100644 --- a/pkg/conditions/updater.go +++ b/pkg/conditions/updater.go @@ -5,6 +5,7 @@ import ( "slices" "strings" + "github.com/openmcp-project/controller-utils/pkg/controller" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -90,8 +91,7 @@ func (c *conditionUpdater) WithEventRecorder(recorder record.EventRecorder, verb func (c *conditionUpdater) UpdateCondition(conType string, status metav1.ConditionStatus, observedGeneration int64, reason, message string) *conditionUpdater { if reason == "" { // the metav1.Condition type requires a reason, so let's add a dummy if none is given - // the type field allows dots ('.'), while the reason field does not, so replace them with colons (':') (which are not allowed in the type field) - reason = strings.ReplaceAll(conType, ".", ":") + "_" + string(status) + reason = controller.ReplaceIllegalCharsInConditionReason(conType + "_" + string(status)) } con := metav1.Condition{ Type: conType, diff --git a/pkg/controller/status_updater.go b/pkg/controller/status_updater.go index 8349832..766941f 100644 --- a/pkg/controller/status_updater.go +++ b/pkg/controller/status_updater.go @@ -485,7 +485,7 @@ func ReplaceIllegalCharsInConditionType(s string) string { result = append(result, '_') } } - return string(result) + return ensureStartsAndEndsWithLetter(string(result), 'T', 't') } // ReplaceIllegalCharsInConditionReason replaces all characters in the given string that are not allowed in condition reasons with underscores. @@ -515,5 +515,21 @@ func ReplaceIllegalCharsInConditionReason(s string) string { result = append(result, '_') } } - return string(result) + return ensureStartsAndEndsWithLetter(string(result), 'R', 'r') +} + +func ensureStartsAndEndsWithLetter(s string, start, end rune) string { + if s == "" { + return s + } + runes := []rune(s) + // Ensure starts with letter + if (runes[0] < 'a' || runes[0] > 'z') && (runes[0] < 'A' || runes[0] > 'Z') { + runes = append([]rune{start}, runes...) + } + // Ensure ends with letter + if (runes[len(runes)-1] < 'a' || runes[len(runes)-1] > 'z') && (runes[len(runes)-1] < 'A' || runes[len(runes)-1] > 'Z') { + runes = append(runes, end) + } + return string(runes) } From b15895f692711c050af428cc043c2b1f36678904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Sch=C3=BCnemann?= Date: Wed, 5 Nov 2025 14:05:46 +0100 Subject: [PATCH 2/3] feat: release v0.23.3 --- VERSION | 2 +- go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 646e9bc..480de63 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.23.2-dev \ No newline at end of file +v0.23.3 \ No newline at end of file diff --git a/go.mod b/go.mod index 9c46687..fd2293c 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/google/uuid v1.6.0 github.com/onsi/ginkgo/v2 v2.27.2 github.com/onsi/gomega v1.38.2 - github.com/openmcp-project/controller-utils/api v0.23.2 + github.com/openmcp-project/controller-utils/api v0.23.3 github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.11.1 go.uber.org/zap v1.27.0 From 82ffe456f705d3b234b631664e541a62f0d10ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Sch=C3=BCnemann?= Date: Wed, 5 Nov 2025 14:27:24 +0100 Subject: [PATCH 3/3] update --- pkg/conditions/updater.go | 79 +++++++++++++++++++++++++- pkg/conditions/updater_test.go | 2 +- pkg/controller/status_updater.go | 80 +-------------------------- pkg/controller/status_updater_test.go | 6 +- 4 files changed, 83 insertions(+), 84 deletions(-) diff --git a/pkg/conditions/updater.go b/pkg/conditions/updater.go index b022e4e..a7d5afa 100644 --- a/pkg/conditions/updater.go +++ b/pkg/conditions/updater.go @@ -5,7 +5,6 @@ import ( "slices" "strings" - "github.com/openmcp-project/controller-utils/pkg/controller" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -91,7 +90,7 @@ func (c *conditionUpdater) WithEventRecorder(recorder record.EventRecorder, verb func (c *conditionUpdater) UpdateCondition(conType string, status metav1.ConditionStatus, observedGeneration int64, reason, message string) *conditionUpdater { if reason == "" { // the metav1.Condition type requires a reason, so let's add a dummy if none is given - reason = controller.ReplaceIllegalCharsInConditionReason(conType + "_" + string(status)) + reason = ReplaceIllegalCharsInConditionReason(conType + "_" + string(status)) } con := metav1.Condition{ Type: conType, @@ -263,3 +262,79 @@ func (c *conditionUpdater) Record(obj runtime.Object) *conditionUpdater { return c } + +// ReplaceIllegalCharsInConditionType replaces all characters in the given string that are not allowed in condition types with underscores. +func ReplaceIllegalCharsInConditionType(s string) string { + if s == "" { + return s + } + + result := make([]rune, 0, len(s)) + for _, r := range s { + // Valid characters for condition types are: + // - lowercase letters (a-z) + // - uppercase letters (A-Z) + // - digits (0-9) + // - underscore (_) + // - hyphen (-) + // - dot (.) + // All other characters are replaced with underscore + if (r >= 'a' && r <= 'z') || + (r >= 'A' && r <= 'Z') || + (r >= '0' && r <= '9') || + r == '_' || + r == '-' || + r == '.' { + result = append(result, r) + } else { + result = append(result, '_') + } + } + return ensureStartsAndEndsWithLetter(string(result), 'T', 't') +} + +// ReplaceIllegalCharsInConditionReason replaces all characters in the given string that are not allowed in condition reasons with underscores. +func ReplaceIllegalCharsInConditionReason(s string) string { + if s == "" { + return s + } + + result := make([]rune, 0, len(s)) + for _, r := range s { + // Valid characters for condition types are: + // - lowercase letters (a-z) + // - uppercase letters (A-Z) + // - digits (0-9) + // - underscore (_) + // - colon (:) + //- comma (,) + // All other characters are replaced with underscore + if (r >= 'a' && r <= 'z') || + (r >= 'A' && r <= 'Z') || + (r >= '0' && r <= '9') || + r == '_' || + r == ':' || + r == ',' { + result = append(result, r) + } else { + result = append(result, '_') + } + } + return ensureStartsAndEndsWithLetter(string(result), 'R', 'r') +} + +func ensureStartsAndEndsWithLetter(s string, start, end rune) string { + if s == "" { + return s + } + runes := []rune(s) + // Ensure starts with letter + if (runes[0] < 'a' || runes[0] > 'z') && (runes[0] < 'A' || runes[0] > 'Z') { + runes = append([]rune{start}, runes...) + } + // Ensure ends with letter + if (runes[len(runes)-1] < 'a' || runes[len(runes)-1] > 'z') && (runes[len(runes)-1] < 'A' || runes[len(runes)-1] > 'Z') { + runes = append(runes, end) + } + return string(runes) +} diff --git a/pkg/conditions/updater_test.go b/pkg/conditions/updater_test.go index e704815..5818a97 100644 --- a/pkg/conditions/updater_test.go +++ b/pkg/conditions/updater_test.go @@ -238,7 +238,7 @@ var _ = Describe("Conditions", func() { MatchCondition(TestCondition(). WithType("TestCondition.Test"). WithStatus(metav1.ConditionFalse). - WithReason("TestCondition:Test_False"). + WithReason("TestCondition_Test_False"). WithMessage("")), )) }) diff --git a/pkg/controller/status_updater.go b/pkg/controller/status_updater.go index 766941f..2c4f99c 100644 --- a/pkg/controller/status_updater.go +++ b/pkg/controller/status_updater.go @@ -449,87 +449,11 @@ func GenerateCreateConditionFunc[Obj client.Object](rr *ReconcileResult[Obj]) fu } return func(conType string, status metav1.ConditionStatus, reason, message string) { rr.Conditions = append(rr.Conditions, metav1.Condition{ - Type: ReplaceIllegalCharsInConditionType(conType), + Type: conditions.ReplaceIllegalCharsInConditionType(conType), Status: status, ObservedGeneration: gen, - Reason: ReplaceIllegalCharsInConditionReason(reason), + Reason: conditions.ReplaceIllegalCharsInConditionReason(reason), Message: message, }) } } - -// ReplaceIllegalCharsInConditionType replaces all characters in the given string that are not allowed in condition types with underscores. -func ReplaceIllegalCharsInConditionType(s string) string { - if s == "" { - return s - } - - result := make([]rune, 0, len(s)) - for _, r := range s { - // Valid characters for condition types are: - // - lowercase letters (a-z) - // - uppercase letters (A-Z) - // - digits (0-9) - // - underscore (_) - // - hyphen (-) - // - dot (.) - // All other characters are replaced with underscore - if (r >= 'a' && r <= 'z') || - (r >= 'A' && r <= 'Z') || - (r >= '0' && r <= '9') || - r == '_' || - r == '-' || - r == '.' { - result = append(result, r) - } else { - result = append(result, '_') - } - } - return ensureStartsAndEndsWithLetter(string(result), 'T', 't') -} - -// ReplaceIllegalCharsInConditionReason replaces all characters in the given string that are not allowed in condition reasons with underscores. -func ReplaceIllegalCharsInConditionReason(s string) string { - if s == "" { - return s - } - - result := make([]rune, 0, len(s)) - for _, r := range s { - // Valid characters for condition types are: - // - lowercase letters (a-z) - // - uppercase letters (A-Z) - // - digits (0-9) - // - underscore (_) - // - colon (:) - //- comma (,) - // All other characters are replaced with underscore - if (r >= 'a' && r <= 'z') || - (r >= 'A' && r <= 'Z') || - (r >= '0' && r <= '9') || - r == '_' || - r == ':' || - r == ',' { - result = append(result, r) - } else { - result = append(result, '_') - } - } - return ensureStartsAndEndsWithLetter(string(result), 'R', 'r') -} - -func ensureStartsAndEndsWithLetter(s string, start, end rune) string { - if s == "" { - return s - } - runes := []rune(s) - // Ensure starts with letter - if (runes[0] < 'a' || runes[0] > 'z') && (runes[0] < 'A' || runes[0] > 'Z') { - runes = append([]rune{start}, runes...) - } - // Ensure ends with letter - if (runes[len(runes)-1] < 'a' || runes[len(runes)-1] > 'z') && (runes[len(runes)-1] < 'A' || runes[len(runes)-1] > 'Z') { - runes = append(runes, end) - } - return string(runes) -} diff --git a/pkg/controller/status_updater_test.go b/pkg/controller/status_updater_test.go index 7e598b3..4b9e43a 100644 --- a/pkg/controller/status_updater_test.go +++ b/pkg/controller/status_updater_test.go @@ -128,10 +128,10 @@ var _ = Describe("Status Updater", func() { } condFunc := controller.GenerateCreateConditionFunc(rr) - condFunc("CondType :,;-_.Test02@", metav1.ConditionTrue, "Reason -.,:_Test93$", "Message") + condFunc("0CondType :,;-_.Test02@", metav1.ConditionTrue, "1Reason -.,:_Test93$", "Message") Expect(rr.Conditions).To(HaveLen(1)) - Expect(rr.Conditions[0].Type).To(Equal("CondType____-_.Test02_")) - Expect(rr.Conditions[0].Reason).To(Equal("Reason___,:_Test93_")) + Expect(rr.Conditions[0].Type).To(Equal("T0CondType____-_.Test02_t")) + Expect(rr.Conditions[0].Reason).To(Equal("R1Reason___,:_Test93_r")) }) It("should not update disabled fields", func() {