From d37ac4e7cae5d6a7767bf0b519f65d00899b64ac Mon Sep 17 00:00:00 2001 From: Philipp Matthes Date: Mon, 9 Feb 2026 14:39:48 +0100 Subject: [PATCH 1/3] Fix multicluster client indexing home cluster twice --- pkg/multicluster/client.go | 11 +++- pkg/multicluster/client_test.go | 100 ++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/pkg/multicluster/client.go b/pkg/multicluster/client.go index bcc8b6a2..37885310 100644 --- a/pkg/multicluster/client.go +++ b/pkg/multicluster/client.go @@ -343,7 +343,8 @@ func (c *Client) IndexField(ctx context.Context, obj client.Object, list client. if err != nil { return err } - if err := c.ClusterForResource(gvkObj). + objCluster := c.ClusterForResource(gvkObj) + if err := objCluster. GetCache(). IndexField(ctx, obj, field, extractValue); err != nil { return err @@ -353,7 +354,13 @@ func (c *Client) IndexField(ctx context.Context, obj client.Object, list client. if err != nil { return err } - if err := c.ClusterForResource(gvkList). + objListCluster := c.ClusterForResource(gvkList) + // If the object and list map to the same cluster, we have already indexed + // the field above and re-defining the index will lead to an indexer conflict. + if objCluster == objListCluster { + return nil + } + if err := objListCluster. GetCache(). IndexField(ctx, obj, field, extractValue); err != nil { return err diff --git a/pkg/multicluster/client_test.go b/pkg/multicluster/client_test.go index 4d815028..576f0f64 100644 --- a/pkg/multicluster/client_test.go +++ b/pkg/multicluster/client_test.go @@ -91,6 +91,7 @@ func newFakeCluster(scheme *runtime.Scheme, objs ...client.Object) *fakeCluster } } +//nolint:unparam func newFakeClusterWithCache(scheme *runtime.Scheme, fakeCache *fakeCache, objs ...client.Object) *fakeCluster { return &fakeCluster{ fakeClient: fake.NewClientBuilder().WithScheme(scheme).WithObjects(objs...).Build(), @@ -1559,3 +1560,102 @@ func TestClient_IndexField_WithRemoteClusters(t *testing.T) { t.Errorf("expected 0 IndexField calls on home cluster, got %d", len(homeCalls)) } } + +// TestClient_IndexField_SameClusterSkipsSecondIndex tests that when object and list map to +// the same cluster, IndexField is only called once to avoid re-defining the index (which would error). +func TestClient_IndexField_SameClusterSkipsSecondIndex(t *testing.T) { + scheme := newTestScheme(t) + + // Use the same cache/cluster for both object and list GVKs + remoteCache := &fakeCache{} + remoteCluster := newFakeClusterWithCache(scheme, remoteCache) + + homeCache := &fakeCache{} + homeCluster := newFakeClusterWithCache(scheme, homeCache) + + objGVK := schema.GroupVersionKind{ + Group: "", + Version: "v1", + Kind: "ConfigMap", + } + listGVK := schema.GroupVersionKind{ + Group: "", + Version: "v1", + Kind: "ConfigMapList", + } + + // Both object and list GVKs point to the SAME remote cluster instance + c := &Client{ + HomeCluster: homeCluster, + HomeScheme: scheme, + remoteClusters: map[schema.GroupVersionKind]cluster.Cluster{ + objGVK: remoteCluster, + listGVK: remoteCluster, // Same cluster instance + }, + } + + ctx := context.Background() + + obj := &corev1.ConfigMap{} + list := &corev1.ConfigMapList{} + field := "metadata.name" + extractValue := func(obj client.Object) []string { + return []string{obj.GetName()} + } + + err := c.IndexField(ctx, obj, list, field, extractValue) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Key assertion: IndexField should only be called ONCE because both object + // and list resolve to the same cluster. Calling it twice would cause an error + // from re-defining the same index. + remoteCalls := remoteCache.getIndexFieldCalls() + if len(remoteCalls) != 1 { + t.Errorf("expected 1 IndexField call (skipping duplicate for same cluster), got %d", len(remoteCalls)) + } + + // Home cluster should not be called at all + homeCalls := homeCache.getIndexFieldCalls() + if len(homeCalls) != 0 { + t.Errorf("expected 0 IndexField calls on home cluster, got %d", len(homeCalls)) + } +} + +// TestClient_IndexField_HomeClusterSkipsSecondIndex tests that when both object and list +// use the home cluster (no remote clusters configured), IndexField is only called once. +func TestClient_IndexField_HomeClusterSkipsSecondIndex(t *testing.T) { + scheme := newTestScheme(t) + + homeCache := &fakeCache{} + homeCluster := newFakeClusterWithCache(scheme, homeCache) + + // No remote clusters configured - both object and list will use home cluster + c := &Client{ + HomeCluster: homeCluster, + HomeScheme: scheme, + } + + ctx := context.Background() + + obj := &corev1.ConfigMap{} + list := &corev1.ConfigMapList{} + field := "metadata.name" + extractValue := func(obj client.Object) []string { + return []string{obj.GetName()} + } + + err := c.IndexField(ctx, obj, list, field, extractValue) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Key assertion: IndexField should only be called ONCE because both object + // and list resolve to the same home cluster. Calling it twice would cause + // an error from re-defining the same index. + homeCalls := homeCache.getIndexFieldCalls() + if len(homeCalls) != 1 { + t.Errorf("expected 1 IndexField call (skipping duplicate for same home cluster), got %d", len(homeCalls)) + } +} From 4811cd436b4145ee53fb51409577b8512b374f86 Mon Sep 17 00:00:00 2001 From: Philipp Matthes Date: Mon, 9 Feb 2026 14:40:41 +0100 Subject: [PATCH 2/3] Bump core to v0.0.19 and bundles to 0.0.32 --- helm/bundles/cortex-cinder/Chart.yaml | 6 +++--- helm/bundles/cortex-crds/Chart.yaml | 4 ++-- helm/bundles/cortex-ironcore/Chart.yaml | 4 ++-- helm/bundles/cortex-manila/Chart.yaml | 6 +++--- helm/bundles/cortex-nova/Chart.yaml | 6 +++--- helm/bundles/cortex-pods/Chart.yaml | 2 +- helm/library/cortex/Chart.yaml | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/helm/bundles/cortex-cinder/Chart.yaml b/helm/bundles/cortex-cinder/Chart.yaml index f4c3eab7..8fa203e9 100644 --- a/helm/bundles/cortex-cinder/Chart.yaml +++ b/helm/bundles/cortex-cinder/Chart.yaml @@ -5,7 +5,7 @@ apiVersion: v2 name: cortex-cinder description: A Helm chart deploying Cortex for Cinder. type: application -version: 0.0.31 +version: 0.0.32 appVersion: 0.1.0 dependencies: # from: file://../../library/cortex-postgres @@ -16,12 +16,12 @@ dependencies: # from: file://../../library/cortex - name: cortex repository: oci://ghcr.io/cobaltcore-dev/cortex/charts - version: 0.0.18 + version: 0.0.19 alias: cortex-knowledge-controllers # from: file://../../library/cortex - name: cortex repository: oci://ghcr.io/cobaltcore-dev/cortex/charts - version: 0.0.18 + version: 0.0.19 alias: cortex-scheduling-controllers # Owner info adds a configmap to the kubernetes cluster with information on diff --git a/helm/bundles/cortex-crds/Chart.yaml b/helm/bundles/cortex-crds/Chart.yaml index 298106d9..819acd61 100644 --- a/helm/bundles/cortex-crds/Chart.yaml +++ b/helm/bundles/cortex-crds/Chart.yaml @@ -5,13 +5,13 @@ apiVersion: v2 name: cortex-crds description: A Helm chart deploying Cortex CRDs. type: application -version: 0.0.31 +version: 0.0.32 appVersion: 0.1.0 dependencies: # from: file://../../library/cortex - name: cortex repository: oci://ghcr.io/cobaltcore-dev/cortex/charts - version: 0.0.18 + version: 0.0.19 # Owner info adds a configmap to the kubernetes cluster with information on # the service owner. This makes it easier to find out who to contact in case diff --git a/helm/bundles/cortex-ironcore/Chart.yaml b/helm/bundles/cortex-ironcore/Chart.yaml index 59e62de6..e95ba21a 100644 --- a/helm/bundles/cortex-ironcore/Chart.yaml +++ b/helm/bundles/cortex-ironcore/Chart.yaml @@ -5,13 +5,13 @@ apiVersion: v2 name: cortex-ironcore description: A Helm chart deploying Cortex for IronCore. type: application -version: 0.0.31 +version: 0.0.32 appVersion: 0.1.0 dependencies: # from: file://../../library/cortex - name: cortex repository: oci://ghcr.io/cobaltcore-dev/cortex/charts - version: 0.0.18 + version: 0.0.19 # Owner info adds a configmap to the kubernetes cluster with information on # the service owner. This makes it easier to find out who to contact in case diff --git a/helm/bundles/cortex-manila/Chart.yaml b/helm/bundles/cortex-manila/Chart.yaml index 8509d733..f93f1c2c 100644 --- a/helm/bundles/cortex-manila/Chart.yaml +++ b/helm/bundles/cortex-manila/Chart.yaml @@ -5,7 +5,7 @@ apiVersion: v2 name: cortex-manila description: A Helm chart deploying Cortex for Manila. type: application -version: 0.0.31 +version: 0.0.32 appVersion: 0.1.0 dependencies: # from: file://../../library/cortex-postgres @@ -16,12 +16,12 @@ dependencies: # from: file://../../library/cortex - name: cortex repository: oci://ghcr.io/cobaltcore-dev/cortex/charts - version: 0.0.18 + version: 0.0.19 alias: cortex-knowledge-controllers # from: file://../../library/cortex - name: cortex repository: oci://ghcr.io/cobaltcore-dev/cortex/charts - version: 0.0.18 + version: 0.0.19 alias: cortex-scheduling-controllers # Owner info adds a configmap to the kubernetes cluster with information on diff --git a/helm/bundles/cortex-nova/Chart.yaml b/helm/bundles/cortex-nova/Chart.yaml index c146e611..3dd901d4 100644 --- a/helm/bundles/cortex-nova/Chart.yaml +++ b/helm/bundles/cortex-nova/Chart.yaml @@ -5,7 +5,7 @@ apiVersion: v2 name: cortex-nova description: A Helm chart deploying Cortex for Nova. type: application -version: 0.0.31 +version: 0.0.32 appVersion: 0.1.0 dependencies: # from: file://../../library/cortex-postgres @@ -16,12 +16,12 @@ dependencies: # from: file://../../library/cortex - name: cortex repository: oci://ghcr.io/cobaltcore-dev/cortex/charts - version: 0.0.18 + version: 0.0.19 alias: cortex-knowledge-controllers # from: file://../../library/cortex - name: cortex repository: oci://ghcr.io/cobaltcore-dev/cortex/charts - version: 0.0.18 + version: 0.0.19 alias: cortex-scheduling-controllers # Owner info adds a configmap to the kubernetes cluster with information on diff --git a/helm/bundles/cortex-pods/Chart.yaml b/helm/bundles/cortex-pods/Chart.yaml index 79048eb5..3f11bb99 100644 --- a/helm/bundles/cortex-pods/Chart.yaml +++ b/helm/bundles/cortex-pods/Chart.yaml @@ -11,7 +11,7 @@ dependencies: # from: file://../../library/cortex - name: cortex repository: oci://ghcr.io/cobaltcore-dev/cortex/charts - version: 0.0.18 + version: 0.0.19 # Owner info adds a configmap to the kubernetes cluster with information on # the service owner. This makes it easier to find out who to contact in case diff --git a/helm/library/cortex/Chart.yaml b/helm/library/cortex/Chart.yaml index b7817588..0f543965 100644 --- a/helm/library/cortex/Chart.yaml +++ b/helm/library/cortex/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: cortex description: A Helm chart to distribute cortex. type: application -version: 0.0.18 +version: 0.0.19 appVersion: "sha-35848cf3" icon: "https://example.com/icon.png" dependencies: [] From db5948f7179fada5323d9b71e081351118e7e9b7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 9 Feb 2026 13:49:33 +0000 Subject: [PATCH 3/3] Bump cortex chart appVersions to sha-4811cd43 [skip ci] --- helm/library/cortex/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helm/library/cortex/Chart.yaml b/helm/library/cortex/Chart.yaml index 0f543965..f6bb7b7c 100644 --- a/helm/library/cortex/Chart.yaml +++ b/helm/library/cortex/Chart.yaml @@ -3,6 +3,6 @@ name: cortex description: A Helm chart to distribute cortex. type: application version: 0.0.19 -appVersion: "sha-35848cf3" +appVersion: "sha-4811cd43" icon: "https://example.com/icon.png" dependencies: []