Skip to content
Open
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,351 @@
apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this
name: "Ingress"
crdName: ingresses.config.openshift.io
featureGates:
- IngressComponentRouteLabels
tests:
onCreate:
- name: Should be able to create an Ingress with componentRoutes containing labels
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
ingress: shard-console
expected: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
ingress: shard-console
- name: Should be able to create an Ingress with multiple componentRoutes with labels
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console-2
namespace: openshift-console
hostname: console.internal.corp.example.com
labels:
ingress: shard-console2
- name: console-3
namespace: openshift-console
hostname: console.private.corp.example.com
labels:
ingress: shard-console3
expected: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console-2
namespace: openshift-console
hostname: console.internal.corp.example.com
labels:
ingress: shard-console2
- name: console-3
namespace: openshift-console
hostname: console.private.corp.example.com
labels:
ingress: shard-console3
- name: Should be able to create componentRoutes with a DNS-prefixed label key
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
example.com/my-label: value
expected: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
example.com/my-label: value
- name: Should be able to create componentRoutes with max-length label key and value
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz012: abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz012
expected: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz012: abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz012
- name: Should reject componentRoutes with invalid label key
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
"!!!bad": value
expectedError: "label keys must be valid Kubernetes qualified names"
- name: Should reject componentRoutes with invalid label value
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
ingress: "invalid value with spaces!"
expectedError: "label values must be valid Kubernetes label values"
- name: Should reject componentRoutes with reserved kubernetes.io/ label prefix
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
kubernetes.io/name: value
expectedError: "label keys must not use reserved prefixes"
- name: Should reject componentRoutes with reserved k8s.io/ label prefix
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
k8s.io/name: value
expectedError: "label keys must not use reserved prefixes"
- name: Should accept componentRoutes with empty string label value
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
ingress: ""
expected: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
ingress: ""
- name: Should accept componentRoutes with non-reserved prefix like openshift.io
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
openshift.io/my-label: value
expected: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
openshift.io/my-label: value
- name: Should reject componentRoutes with label key name over 63 characters
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123: value
expectedError: "label keys must be valid Kubernetes qualified names"
- name: Should reject componentRoutes with label value starting with dash
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
ingress: "-starts-with-dash"
expectedError: "label values must be valid Kubernetes label values"
- name: Should reject componentRoutes with more than 8 labels
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
label1: value1
label2: value2
label3: value3
label4: value4
label5: value5
label6: value6
label7: value7
label8: value8
label9: value9
expectedError: "Too many properties"
onUpdate:
Copy link
Copy Markdown
Member

@saschagrunert saschagrunert May 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests cover basic CRUD and some negatives but the CEL validations need more coverage. Please add:

  • Empty string value (ingress: "") accepted (valid per K8s label spec, non-obvious edge case)
  • Key name part over 63 characters rejected (tests format.qualifiedName() enforcement)
  • Value with valid characters in invalid position (e.g., -starts-with-dash) rejected
  • Non-reserved prefix accepted (e.g., openshift.io/my-label), confirms the reserved check is not overly broad

The MinProperties/MaxProperties boundary tests are basic OpenAPI and do not need separate test cases.

- name: Should be able to add labels to componentRoutes on update
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
updated: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
ingress: shard-console
expected: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
ingress: shard-console
- name: Should be able to change an existing label value on update
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
ingress: shard-old
updated: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
ingress: shard-new
expected: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
ingress: shard-new
- name: Should be able to remove labels from componentRoutes on update
initial: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
labels:
ingress: shard-console
updated: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
expected: |
apiVersion: config.openshift.io/v1
kind: Ingress
spec:
domain: apps.example.com
componentRoutes:
- name: console
namespace: openshift-console
hostname: console.example.com
19 changes: 19 additions & 0 deletions config/v1/types_ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,25 @@ type ComponentRouteSpec struct {
// the Secret specification for a serving certificate will not be needed.
// +optional
ServingCertKeyPairSecret SecretNameReference `json:"servingCertKeyPairSecret"`

// labels defines additional labels to be applied to the route created
// for the component. These labels are used by the IngressController to
// determine which routes it should manage. Changing labels may cause the
// route to be reassigned to a different IngressController.
// When omitted, no additional labels are applied to the component route.
// Label keys and values must conform to Kubernetes label conventions.
// Keys with the "kubernetes.io/" and "k8s.io/" prefixes are reserved
// for Kubernetes use and may not be specified.
// When specified, labels must contain at least one entry, up to a maximum of 8.
// +openshift:enable:FeatureGate=IngressComponentRouteLabels
// +optional
// +mapType=granular
// +kubebuilder:validation:MinProperties=1
// +kubebuilder:validation:MaxProperties=8
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the rationale for limiting to 8 labels? Please document the reasoning.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The limit of 8 was chosen as a practical upper bound — in typical route sharding scenarios, IngressController selectors only need 1-2 labels, so 8 seemed generous while preventing unbounded growth. That said, there is no strong technical justification for this specific number.

Would you prefer we remove the limit entirely, or do you have a recommended ceiling for map fields like this? Happy to adjust. @saschagrunert

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8 is fine. Maps need a bound for CEL cost estimation and to prevent unbounded growth. For route sharding where 1-2 labels is typical, 8 is generous enough. No need to change it.

Comment thread
coderabbitai[bot] marked this conversation as resolved.
// +kubebuilder:validation:XValidation:rule="self.all(key, !format.qualifiedName().validate(key).hasValue())",message="label keys must be valid Kubernetes qualified names"
// +kubebuilder:validation:XValidation:rule="self.all(key, !key.startsWith('kubernetes.io/') && !key.startsWith('k8s.io/'))",message="label keys must not use reserved prefixes kubernetes.io/ or k8s.io/"
// +kubebuilder:validation:XValidation:rule="self.all(key, !format.labelValue().validate(self[key]).hasValue())",message="label values must be valid Kubernetes label values (at most 63 characters, alphanumeric, '-', '_', or '.', must start and end with alphanumeric)"
Labels map[string]string `json:"labels,omitempty"`
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two issues here:

  1. FeatureGate required. New fields on stable (compatibility-level-1) APIs must be behind a FeatureGate. Add a gate in features/features.go and mark this field with +openshift:enable:FeatureGate=<GateName>.

  2. make lint fails. Add +kubebuilder:validation:MinProperties=1 to prevent semantically meaningless labels: {}.

}

// ComponentRouteStatus contains information allowing configuration of a route's hostname and serving certificate.
Expand Down
Loading