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: []