Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
project: operator
kind: Added
body: |-
Console clusterRef now supports an optional `namespace` field to reference a
Redpanda cluster in a different namespace. This requires the operator to be
running in global scope mode (without the `--namespace` flag).
time: 2026-04-14T21:00:00.000000-04:00
15 changes: 12 additions & 3 deletions operator/api/applyconfiguration/redpanda/v1alpha2/clusterref.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions operator/api/redpanda/v1alpha2/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,11 @@ type ClusterRef struct {
// Name specifies the name of the cluster being referenced.
// +kubebuilder:validation:Required
Name string `json:"name"`
// Namespace optionally specifies the namespace of the cluster being
// referenced. When set, allows referencing a cluster in a different
// namespace from the resource. Requires the operator to be running in
// global scope mode (without --namespace flag).
Namespace *string `json:"namespace,omitempty"`
}

const (
Expand All @@ -333,6 +338,19 @@ const (
StretchClusterRefKind = "StretchCluster"
)

// GetNamespace returns the namespace from the ClusterRef if set, otherwise
// falls back to the provided default (typically the referencing object's
// namespace).
func (c *ClusterRef) GetNamespace(defaultNamespace string) string {
return ptr.Deref(c.Namespace, defaultNamespace)
}

// IsCrossNamespace returns true if this ClusterRef points to a namespace
// different from the given one.
func (c *ClusterRef) IsCrossNamespace(objectNamespace string) bool {
return c.Namespace != nil && *c.Namespace != "" && *c.Namespace != objectNamespace
}

func (c *ClusterRef) GetGroup() string {
return ptr.Deref(c.Group, v2ClusterRefGroup)
}
Expand Down
4 changes: 4 additions & 0 deletions operator/api/redpanda/v1alpha2/testdata/crd-docs.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,10 @@ If unspecified, defaults to "cluster.redpanda.com". + | |
If unspecified, defaults to "Redpanda". + | |
| *`name`* __string__ | Name specifies the name of the cluster being referenced. + | | Required: \{} +

| *`namespace`* __string__ | Namespace optionally specifies the namespace of the cluster being +
referenced. When set, allows referencing a cluster in a different +
namespace from the resource. Requires the operator to be running in +
global scope mode (without --namespace flag). + | |
|===


Expand Down
5 changes: 5 additions & 0 deletions operator/api/redpanda/v1alpha2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,13 @@ spec:
description: Name specifies the name of the cluster being
referenced.
type: string
namespace:
description: |-
Namespace optionally specifies the namespace of the cluster being
referenced. When set, allows referencing a cluster in a different
namespace from the resource. Requires the operator to be running in
global scope mode (without --namespace flag).
type: string
required:
- name
type: object
Expand Down
7 changes: 7 additions & 0 deletions operator/config/crd/bases/cluster.redpanda.com_groups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@ spec:
description: Name specifies the name of the cluster being
referenced.
type: string
namespace:
description: |-
Namespace optionally specifies the namespace of the cluster being
referenced. When set, allows referencing a cluster in a different
namespace from the resource. Requires the operator to be running in
global scope mode (without --namespace flag).
type: string
required:
- name
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ spec:
name:
description: Name specifies the name of the cluster being referenced.
type: string
namespace:
description: |-
Namespace optionally specifies the namespace of the cluster being
referenced. When set, allows referencing a cluster in a different
namespace from the resource. Requires the operator to be running in
global scope mode (without --namespace flag).
type: string
required:
- name
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,13 @@ spec:
description: Name specifies the name of the cluster being
referenced.
type: string
namespace:
description: |-
Namespace optionally specifies the namespace of the cluster being
referenced. When set, allows referencing a cluster in a different
namespace from the resource. Requires the operator to be running in
global scope mode (without --namespace flag).
type: string
required:
- name
type: object
Expand Down
7 changes: 7 additions & 0 deletions operator/config/crd/bases/cluster.redpanda.com_schemas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ spec:
description: Name specifies the name of the cluster being
referenced.
type: string
namespace:
description: |-
Namespace optionally specifies the namespace of the cluster being
referenced. When set, allows referencing a cluster in a different
namespace from the resource. Requires the operator to be running in
global scope mode (without --namespace flag).
type: string
required:
- name
type: object
Expand Down
14 changes: 14 additions & 0 deletions operator/config/crd/bases/cluster.redpanda.com_shadowlinks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,13 @@ spec:
description: Name specifies the name of the cluster being
referenced.
type: string
namespace:
description: |-
Namespace optionally specifies the namespace of the cluster being
referenced. When set, allows referencing a cluster in a different
namespace from the resource. Requires the operator to be running in
global scope mode (without --namespace flag).
type: string
required:
- name
type: object
Expand Down Expand Up @@ -2489,6 +2496,13 @@ spec:
description: Name specifies the name of the cluster being
referenced.
type: string
namespace:
description: |-
Namespace optionally specifies the namespace of the cluster being
referenced. When set, allows referencing a cluster in a different
namespace from the resource. Requires the operator to be running in
global scope mode (without --namespace flag).
type: string
required:
- name
type: object
Expand Down
14 changes: 14 additions & 0 deletions operator/config/crd/bases/cluster.redpanda.com_topics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ spec:
description: Name specifies the name of the cluster being
referenced.
type: string
namespace:
description: |-
Namespace optionally specifies the namespace of the cluster being
referenced. When set, allows referencing a cluster in a different
namespace from the resource. Requires the operator to be running in
global scope mode (without --namespace flag).
type: string
required:
- name
type: object
Expand Down Expand Up @@ -3590,6 +3597,13 @@ spec:
description: Name specifies the name of the cluster being
referenced.
type: string
namespace:
description: |-
Namespace optionally specifies the namespace of the cluster being
referenced. When set, allows referencing a cluster in a different
namespace from the resource. Requires the operator to be running in
global scope mode (without --namespace flag).
type: string
required:
- name
type: object
Expand Down
7 changes: 7 additions & 0 deletions operator/config/crd/bases/cluster.redpanda.com_users.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,13 @@ spec:
description: Name specifies the name of the cluster being
referenced.
type: string
namespace:
description: |-
Namespace optionally specifies the namespace of the cluster being
referenced. When set, allows referencing a cluster in a different
namespace from the resource. Requires the operator to be running in
global scope mode (without --namespace flag).
type: string
required:
- name
type: object
Expand Down
24 changes: 23 additions & 1 deletion operator/internal/controller/console/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ type Controller struct {
Ctl *kube.Ctl
Config *kube.RESTConfig

// namespace is the operator's configured namespace scope. Empty means
// global scope (all namespaces). Cross-namespace ClusterRef is only
// allowed when this is empty.
namespace string

// rng is used to generate Console's JWT Signing keys, if they're not
// explicitly specified. If nil, SetupWithManager will set it with a seeded
// value.
Expand All @@ -78,6 +83,8 @@ type Controller struct {
}

func (c *Controller) SetupWithManager(ctx context.Context, mgr multicluster.Manager, namespace string) error {
c.namespace = namespace

// If rng is not set for testing, create and seed a new one.
if c.rng == nil {
// TODO: Weak RNG is probably acceptable here but best to doublecheck
Expand Down Expand Up @@ -124,6 +131,21 @@ func (c *Controller) Reconcile(ctx context.Context, req mcreconcile.Request) (ct
return ctrl.Result{}, err
}

// Reject cross-namespace ClusterRef when the operator is running in
// namespace-scoped mode. Cross-namespace references require global
// scope because the operator needs cache access to the target namespace.
if c.namespace != "" {
if src := cr.Spec.ClusterSource; src != nil {
if ref := src.ClusterRef; ref != nil && ref.IsCrossNamespace(cr.Namespace) {
return ctrl.Result{}, fmt.Errorf(
"cross-namespace clusterRef (namespace %q) is not allowed when the operator is running in namespace-scoped mode (--namespace=%q); "+
"remove the --namespace flag to enable global scope",
ptr.Deref(ref.Namespace, ""), c.namespace,
)
}
}
}

syncer, err := c.syncerFor(cr)
if err != nil {
return ctrl.Result{}, err
Expand Down Expand Up @@ -419,7 +441,7 @@ func (r *render) clusterFragment(ctx context.Context) (console.PartialRenderValu
if ref := r.console.Spec.ClusterSource.ClusterRef; ref != nil {
key := kube.ObjectKey{
Name: ref.Name,
Namespace: r.console.Namespace,
Namespace: ref.GetNamespace(r.console.Namespace),
}

// TODO: Add support for vectorized clusters?
Expand Down
Loading
Loading