From 8b3181271d89cf8328786dc1d85a77357a07e2ea Mon Sep 17 00:00:00 2001 From: Philipp Matthes Date: Wed, 11 Mar 2026 11:11:10 +0100 Subject: [PATCH] Document initial ideas to route multicluster resources --- helm/bundles/cortex-nova/values.yaml | 18 +++++++++++ pkg/multicluster/client.go | 46 ++++++++++++++++++++++------ 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/helm/bundles/cortex-nova/values.yaml b/helm/bundles/cortex-nova/values.yaml index b2dbba788..138cddcf0 100644 --- a/helm/bundles/cortex-nova/values.yaml +++ b/helm/bundles/cortex-nova/values.yaml @@ -117,6 +117,24 @@ cortex-scheduling-controllers: enabledTasks: - nova-decisions-cleanup-task + # List: iterate over all api servers with the gvk and return a combined list. + # Get: iterate over all api server with the gvk and return the first result that is found. + # Create/Update/Delete: based on the content of the resource, match api server with labels and execute op only there. + # WatchesMulticluster: watch resource in all clusters with the gvk. + multicluster: + # These resources will be written into the home cluster if no match is found. + fallbacks: + - gvk: "cortex.cloud/v1alpha1/Decision" + - # ... + apiservers: + - host: "https://api.cc-b0-qa-de-1.ccloud.external.a-qa-de-200.soil-garden.qa-de-1.cloud.sap" + gvks: # Used for List, Get, Watches + - "cortex.cloud/v1alpha1/Decision" + - "cortex.cloud/v1alpha1/DecisionList" + # ... + labels: # Used for Create/Update/Delete + az: "qa-de-1b" + cortex-knowledge-controllers: <<: *cortex namePrefix: cortex-nova-knowledge diff --git a/pkg/multicluster/client.go b/pkg/multicluster/client.go index d3bd88ae6..82e94582c 100644 --- a/pkg/multicluster/client.go +++ b/pkg/multicluster/client.go @@ -8,6 +8,7 @@ import ( "errors" "sync" + hv1 "github.com/cobaltcore-dev/openstack-hypervisor-operator/api/v1" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -17,7 +18,40 @@ import ( "sigs.k8s.io/controller-runtime/pkg/cluster" ) +type ResourceRouter interface { + Match(obj any, labels map[string]string) (bool, error) +} + +type HypervisorResourceRouter struct{} + +func (h HypervisorResourceRouter) Match(obj any, labels map[string]string) (bool, error) { + hv, ok := obj.(hv1.Hypervisor) + if !ok { + return false, errors.New("object is not a Hypervisor") + } + // Match by hypervisor availability zone label. + az, ok := labels["az"] + if !ok { + return false, errors.New("object does not have availability zone label") + } + hvAZ, ok := hv.Labels["topology.kubernetes.io/zone"] + if !ok { + return false, errors.New("hypervisor does not have availability zone label") + } + return hvAZ == az, nil +} + +func main() { + _ = Client{ + ResourceRouters: map[schema.GroupVersionKind]ResourceRouter{ + hv1.GroupVersion.WithKind("Hypervisor"): HypervisorResourceRouter{}, + }, + } +} + type Client struct { + ResourceRouters map[schema.GroupVersionKind]ResourceRouter + // The cluster in which cortex is deployed. HomeCluster cluster.Cluster // The REST config for the home cluster in which cortex is deployed. @@ -134,17 +168,11 @@ func (c *Client) GVKFromHomeScheme(obj runtime.Object) (gvk schema.GroupVersionK return gvks[0], nil } -// Get the cluster for the given group version kind. -// -// If this object kind does not have a remote cluster configured, -// the home cluster is returned. -func (c *Client) ClusterForResource(gvk schema.GroupVersionKind) cluster.Cluster { +func (c *Client) ClusterForResource(routable Routable) cluster.Cluster { c.remoteClustersMu.RLock() defer c.remoteClustersMu.RUnlock() - cl, ok := c.remoteClusters[gvk] - if ok { - return cl - } + // TODO: Match the approprite cluster. + return c.HomeCluster }