diff --git a/controllers/logging/logging_controller_test.go b/controllers/logging/logging_controller_test.go index 2601bb524..7029c0916 100644 --- a/controllers/logging/logging_controller_test.go +++ b/controllers/logging/logging_controller_test.go @@ -279,6 +279,7 @@ func TestLogginResourcesWithNonUniqueLoggingRefs(t *testing.T) { }, Spec: v1beta1.LoggingSpec{ ControlNamespace: controlNamespace, + WatchNamespaces: []string{"a", "b"}, }, } logging2 := &v1beta1.Logging{ @@ -287,6 +288,7 @@ func TestLogginResourcesWithNonUniqueLoggingRefs(t *testing.T) { }, Spec: v1beta1.LoggingSpec{ ControlNamespace: controlNamespace, + WatchNamespaces: []string{"b", "c"}, }, } logging3 := &v1beta1.Logging{ @@ -305,7 +307,7 @@ func TestLogginResourcesWithNonUniqueLoggingRefs(t *testing.T) { // The first logging resource won't be populated with a warning initially since at the time of creation it is unique g.Eventually(getLoggingProblems(logging1)).WithPolling(time.Second).WithTimeout(5 * time.Second).Should(gomega.BeEmpty()) - g.Eventually(getLoggingProblems(logging2)).WithPolling(time.Second).WithTimeout(5 * time.Second).Should(gomega.ContainElement(gomega.ContainSubstring("Deprecated"))) + g.Eventually(getLoggingProblems(logging2)).WithPolling(time.Second).WithTimeout(5 * time.Second).Should(gomega.ContainElement(gomega.ContainSubstring(model.LoggingRefConflict))) g.Eventually(getLoggingProblems(logging3)).WithPolling(time.Second).WithTimeout(5 * time.Second).Should(gomega.BeEmpty()) g.Eventually(func() error { @@ -316,7 +318,7 @@ func TestLogginResourcesWithNonUniqueLoggingRefs(t *testing.T) { l.Spec.ErrorOutputRef = "trigger reconcile" return mgr.GetClient().Update(context.TODO(), l) }).WithPolling(time.Second).WithTimeout(5 * time.Second).Should(gomega.Succeed()) - g.Eventually(getLoggingProblems(logging1)).WithPolling(time.Second).WithTimeout(5 * time.Second).Should(gomega.ContainElement(gomega.ContainSubstring("Deprecated"))) + g.Eventually(getLoggingProblems(logging1)).WithPolling(time.Second).WithTimeout(5 * time.Second).Should(gomega.ContainElement(gomega.ContainSubstring(model.LoggingRefConflict))) } func getLoggingProblems(logging *v1beta1.Logging) func() ([]string, error) { diff --git a/pkg/resources/model/reconciler.go b/pkg/resources/model/reconciler.go index d4a81c849..2738b3757 100644 --- a/pkg/resources/model/reconciler.go +++ b/pkg/resources/model/reconciler.go @@ -34,6 +34,8 @@ import ( "github.com/kube-logging/logging-operator/pkg/mirror" ) +const LoggingRefConflict = "Other logging resources exist with the same loggingRef" + func NewValidationReconciler( repo client.StatusClient, resources LoggingResources, @@ -291,13 +293,13 @@ func NewValidationReconciler( if l.Name == resources.Logging.Name { continue } - if l.Spec.LoggingRef == resources.Logging.Spec.LoggingRef { + if l.Spec.LoggingRef == resources.Logging.Spec.LoggingRef && hasIntersection(l.Status.WatchNamespaces, resources.Logging.Status.WatchNamespaces) { loggingsForTheSameRef = append(loggingsForTheSameRef, l.Name) } } if len(loggingsForTheSameRef) > 0 { - problem := fmt.Sprintf("Deprecated behaviour! Other logging resources exist with the same loggingRef: %s. This is going to be an error with the next major release.", + problem := fmt.Sprintf("%s (%s) and their watchNamespaces conflict", LoggingRefConflict, strings.Join(loggingsForTheSameRef, ",")) logger.Info(fmt.Sprintf("WARNING %s", problem)) resources.Logging.Status.Problems = append(resources.Logging.Status.Problems, problem) @@ -417,3 +419,14 @@ func jsonFieldName(f reflect.StructField) string { } return f.Name } + +func hasIntersection(a, b []string) bool { + for _, i := range a { + for _, j := range b { + if i == j { + return true + } + } + } + return false +} diff --git a/pkg/resources/model/reconciler_test.go b/pkg/resources/model/reconciler_test.go new file mode 100644 index 000000000..a4b0f25a0 --- /dev/null +++ b/pkg/resources/model/reconciler_test.go @@ -0,0 +1,61 @@ +// Copyright © 2024 Kube logging authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +import "testing" + +func Test_hasIntersection(t *testing.T) { + type args struct { + a []string + b []string + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "no intersection empty", + args: args{ + a: []string{}, + b: []string{}, + }, + want: false, + }, + { + name: "no intersection nonempty", + args: args{ + a: []string{"a", "b", "c"}, + b: []string{"d", "e"}, + }, + want: false, + }, + { + name: "has intersection", + args: args{ + a: []string{"a", "b", "c"}, + b: []string{"b"}, + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := hasIntersection(tt.args.a, tt.args.b); got != tt.want { + t.Errorf("hasIntersection() = %v, want %v", got, tt.want) + } + }) + } +}