diff --git a/api/go.mod b/api/go.mod index 77149f651..91cc2fc4a 100644 --- a/api/go.mod +++ b/api/go.mod @@ -2,11 +2,13 @@ module github.com/openshift-online/rosa-hyperfleet-api/api go 1.26.3 +replace github.com/openshift/hypershift/api => github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345 + require ( - github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 + github.com/openshift/api v0.0.0-20260805160557-b61243060d5f github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 - k8s.io/api v0.35.1 - k8s.io/apimachinery v0.36.0 + k8s.io/api v0.36.2 + k8s.io/apimachinery v0.36.2 ) require ( @@ -21,7 +23,7 @@ require ( golang.org/x/text v0.41.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect k8s.io/klog/v2 v2.140.0 // indirect - k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect + k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 // indirect k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect diff --git a/api/go.sum b/api/go.sum index b194acbea..6b859b9e6 100644 --- a/api/go.sum +++ b/api/go.sum @@ -17,10 +17,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 h1:r0S/yoZAI0iWo1JvoIijaIgWGWf/izg4WiV7Wrtz16k= -github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo= -github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 h1:QDSh3vkKYq7Fn9utYGlAJadkTdyaRl9IY7Cr6cNDAow= -github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16/go.mod h1:Z3lkj5pFqY+KTl3Do9gXdEZdKWLnkUTSDShLD1HE0CM= +github.com/openshift/api v0.0.0-20260805160557-b61243060d5f h1:NU7ltJhtFhqAJC+77DcNk6jmIpsJ3a+mebZIceiPW+U= +github.com/openshift/api v0.0.0-20260805160557-b61243060d5f/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -30,6 +28,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345 h1:4Hi+KoXlzdHAiKSMnGFF1yfvPFpkb08r0yO6SPlq4vQ= +github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345/go.mod h1:v7kWzwoisePl3ewusWeexcHlkO5MJNs+x9ORRPkqDC4= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= @@ -42,14 +42,14 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.35.1 h1:0PO/1FhlK/EQNVK5+txc4FuhQibV25VLSdLMmGpDE/Q= -k8s.io/api v0.35.1/go.mod h1:28uR9xlXWml9eT0uaGo6y71xK86JBELShLy4wR1XtxM= -k8s.io/apimachinery v0.36.0 h1:jZyPzhd5Z+3h9vJLt0z9XdzW9VzNzWAUw+P1xZ9PXtQ= -k8s.io/apimachinery v0.36.0/go.mod h1:FklypaRJt6n5wUIwWXIP6GJlIpUizTgfo1T/As+Tyxc= +k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY= +k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg= +k8s.io/apimachinery v0.36.2 h1:0PE/W/WNy1UX61NLbXY5TMbJ6UwLL6E6lAPkYrKFxbQ= +k8s.io/apimachinery v0.36.2/go.mod h1:fvf/HOLXq9RId0rnDIbN1OEBvHXdQbLMM8nu0LcBUf4= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= +k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 h1:A7Lby6ekC6nv+6oO38huCMFBRP0Os+tIeq1GkwxOQes= +k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288/go.mod h1:V/QaCUYDa+0QpcHhVVc5l99Uz56wEMEXBSj9oCDkNDY= k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 h1:jVkFFVfXdXP74B/zbO3hM3hpSFD0xvhQ5U686DPurkE= k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3/go.mod h1:M2s5JB1lIYP3jzZdorPLHXIPJzt9vv2muW5a6L9DtNM= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= diff --git a/api/v1alpha1/cluster_types.go b/api/v1alpha1/cluster_types.go index 4f8159579..aabf99930 100644 --- a/api/v1alpha1/cluster_types.go +++ b/api/v1alpha1/cluster_types.go @@ -104,7 +104,7 @@ type ClusterSpec struct { // ClusterStatus defines the observed state of a Cluster. type ClusterStatus struct { // Conditions represent the latest observations of the cluster's state. - // Known condition types: Synced, Available, Degraded, ControlPlaneUpgradeState. + // Known condition types: Synced, Available, Degraded, ControlPlaneUpgradeState, AWSManagedDNSAvailable. // +listType=map // +listMapKey=type // +optional @@ -122,6 +122,11 @@ type ClusterStatus struct { // +optional Version string `json:"version,omitempty"` + // DNSZones contains DNS zone information for zones managed by the control plane. + // Populated from the HostedCluster's platform status when managed ingress DNS is enabled. + // +optional + DNSZones []hypershiftv1beta1.AWSDNSZoneStatus `json:"dnsZones,omitempty"` + // PlacementRef references the Placement that assigned this cluster to a management cluster. // +optional PlacementRef *PlacementReference `json:"placementRef,omitempty"` diff --git a/api/v1alpha1/public/clusterstatus_types.go b/api/v1alpha1/public/clusterstatus_types.go index f3f1cc2af..0387cdbe8 100644 --- a/api/v1alpha1/public/clusterstatus_types.go +++ b/api/v1alpha1/public/clusterstatus_types.go @@ -10,7 +10,7 @@ import ( // ClusterStatus defines the observed state of a Cluster. type ClusterStatus struct { // Conditions represent the latest observations of the cluster's state. - // Known condition types: Synced, Available, Degraded, ControlPlaneUpgradeState. + // Known condition types: Synced, Available, Degraded, ControlPlaneUpgradeState, AWSManagedDNSAvailable. // +listType=map // +listMapKey=type // +optional @@ -24,6 +24,10 @@ type ClusterStatus struct { // Version is the running OpenShift version. // +optional Version string `json:"version,omitempty"` + // DNSZones contains DNS zone information for zones managed by the control plane. + // Populated from the HostedCluster's platform status when managed ingress DNS is enabled. + // +optional + DNSZones []hypershiftv1beta1.AWSDNSZoneStatus `json:"dnsZones,omitempty"` // PlacementRef references the Placement that assigned this cluster to a management cluster. // +optional PlacementRef *PlacementReference `json:"placementRef,omitempty"` diff --git a/api/v1alpha1/public/openapi.yaml b/api/v1alpha1/public/openapi.yaml index c153c69bb..a16898b1c 100644 --- a/api/v1alpha1/public/openapi.yaml +++ b/api/v1alpha1/public/openapi.yaml @@ -3003,6 +3003,67 @@ components: x-kubernetes-validations: - message: mtu is immutable once set rule: self == oldSelf + v4InternalSubnet: + description: |- + v4InternalSubnet configures the IPv4 subnet used by OVN-Kubernetes for gateway + router logical router port (LRP) addresses and masquerade/SNAT traffic within + the OVN logical topology. It must not overlap with any other subnet being used + by OpenShift or by the node network. The size of the subnet must be larger than + the number of nodes. + This field is distinct from ipv4.internalJoinSubnet, which configures the subnet + for the join switch that interconnects per-node gateway routers with the cluster + router. Both default to 100.64.0.0/16 but control different OVN-Kubernetes + internal networks and can be configured independently to avoid overlaps with + existing network infrastructure. + Once set, the value is immutable and cannot be modified in subsequent updates. + The default is 100.64.0.0/16. + The value must be in IPv4 CIDR notation (e.g., 192.168.0.0/16), consisting of + four decimal octets (0-255) separated by dots, followed by a slash and a prefix + length. The prefix length must be between 0 and 30 inclusive, and the first + octet must not be 0. + The value must be between 9 and 18 characters in length. + This field is immutable once set. + maxLength: 18 + minLength: 9 + type: string + x-kubernetes-validations: + - message: v4InternalSubnet is immutable once set + rule: self == oldSelf + - message: Subnet must be in a valid IPv4 CIDR format + rule: isCIDR(self) && cidr(self).ip().family() == 4 + - message: subnet must be in the range /0 to /30 inclusive + rule: isCIDR(self) && cidr(self).prefixLength() <= 30 + - message: first IP address octet must not be 0 + rule: isCIDR(self) && cidr(self).ip().family() == 4 && int(self.split('.')[0]) > 0 + v6InternalSubnet: + description: |- + v6InternalSubnet configures the IPv6 subnet used by OVN-Kubernetes for gateway + router logical router port (LRP) addresses and masquerade/SNAT traffic within + the OVN logical topology. It must not overlap with any other subnet being used + by OpenShift or by the node network. The size of the subnet must be larger than + the number of nodes. + This field is distinct from ipv6.internalJoinSubnet, which configures the subnet + for the join switch that interconnects per-node gateway routers with the cluster + router. Both default to fd98::/64 but control different OVN-Kubernetes internal + networks and can be configured independently to avoid overlaps with existing + network infrastructure. + Once set, the value is immutable and cannot be modified in subsequent updates. + The default is fd98::/64. + The value must be in IPv6 CIDR notation (e.g., fd98::/64), consisting of an + IPv6 address followed by a slash and a prefix length. The prefix length must + be between 0 and 125 inclusive. + The value must be between 4 and 48 characters in length. + This field is immutable once set. + maxLength: 48 + minLength: 4 + type: string + x-kubernetes-validations: + - message: v6InternalSubnet is immutable once set + rule: self == oldSelf + - message: Subnet must be in valid IPv6 CIDR format + rule: isCIDR(self) && cidr(self).ip().family() == 6 + - message: subnet must be in the range /0 to /125 inclusive + rule: isCIDR(self) && cidr(self).prefixLength() <= 125 type: object x-kubernetes-validations: - message: internalJoinSubnet and internalTransitSwitchSubnet must not be the same @@ -3017,6 +3078,10 @@ components: rule: '!has(oldSelf.ipv6) || !has(oldSelf.ipv6.internalJoinSubnet) || (has(self.ipv6) && has(self.ipv6.internalJoinSubnet))' - message: ipv6.internalTransitSwitchSubnet cannot be removed once set rule: '!has(oldSelf.ipv6) || !has(oldSelf.ipv6.internalTransitSwitchSubnet) || (has(self.ipv6) && has(self.ipv6.internalTransitSwitchSubnet))' + - message: v4InternalSubnet is immutable once set and cannot be removed + rule: '!has(oldSelf.v4InternalSubnet) || has(self.v4InternalSubnet)' + - message: v6InternalSubnet is immutable once set and cannot be removed + rule: '!has(oldSelf.v6InternalSubnet) || has(self.v6InternalSubnet)' type: object x-kubernetes-validations: - message: ovnKubernetesConfig is immutable once set and cannot be removed @@ -3032,18 +3097,88 @@ components: Valid values are: "Normal", "Debug", "Trace", "TraceAll". Defaults to "Normal". enum: - - "" - Normal - Debug - Trace - TraceAll type: string type: object + etcd: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + etcd configures the etcd component. + Setting the logLevel field triggers a rolling restart of the component. + Note: etcd supports fewer log levels than klog-based components, + etcd supports only Normal and Debug log levels. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + x-kubernetes-validations: + - message: etcd only supports Normal and Debug log levels; Trace and TraceAll are not valid for etcd + rule: '!has(self.logLevel) || self.logLevel in [''Normal'', ''Debug'']' ingressOperator: description: |- ingressOperator specifies the configuration for the Ingress Operator in the hosted cluster. This allows configuring how the default ingress controller endpoints are published. properties: + defaultCertificate: + description: |- + defaultCertificate is a reference to a secret in the HostedCluster namespace + that contains the default certificate served by the default ingress controller. + When Routes don't specify their own certificate, defaultCertificate is used. + The secret must contain the following keys and data: + tls.crt: certificate file contents + tls.key: key file contents + When set, this certificate replaces the auto-generated wildcard certificate + that is normally created by the control plane operator. The secret is synced + from the HostedCluster namespace to the control plane, and then propagated + to the hosted cluster's openshift-ingress namespace. + When the referenced secret is updated, the new certificate data is + automatically propagated to the hosted cluster. + When not set, the control plane operator generates a wildcard certificate + signed by the cluster's root CA. + Note: a cluster-admin in the hosted cluster can override the default ingress + controller's certificate directly. That override takes precedence and the + certificate referenced here is no longer served. + properties: + name: + description: |- + name is the name of the Secret containing tls.crt and tls.key. + The Secret must exist in the same namespace as the HostedCluster. + name must be a valid DNS subdomain name (RFC 1123): it must contain only + lowercase alphanumeric characters, '-' or '.', and start and end with an + alphanumeric character. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'name must be a valid DNS subdomain name: contain no more than 253 characters, contain only lowercase alphanumeric characters, ''-'' or ''.'', and start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$') + required: + - name + type: object endpointPublishingStrategy: description: |- endpointPublishingStrategy is used to publish the default ingress controller endpoints. @@ -3308,6 +3443,32 @@ components: x-kubernetes-validations: - message: eipAllocations cannot contain duplicates rule: self.all(x, self.exists_one(y, x == y)) + protocol: + description: |- + protocol specifies whether the Network Load Balancer uses PROXY + protocol to forward connections to the IngressController. + When set to "TCP", the NLB uses AWS's native client IP preservation. + This may cause hairpin connection failures for internal load + balancers when connections are made from pods to router pods on + the same node. + When set to "PROXY", the NLB disables native client IP preservation + and uses PROXY protocol v2. The IngressController enables PROXY + protocol on HAProxy so that it can parse PROXY protocol headers to + obtain the original client IP. This avoids hairpin connection + failures. + The following values are valid for this field: + * "TCP". + * "PROXY". + When omitted, this means the user has no opinion and the value is + left to the platform to choose a reasonable default, which is subject to + change over time. The current default is "PROXY". + Note that changing this field may cause brief connection failures + during the transition as the NLB attribute change and router rollout + occur independently. + enum: + - TCP + - PROXY + type: string subnets: description: |- subnets specifies the subnets to which the load balancer will @@ -3623,6 +3784,216 @@ components: type: object x-kubernetes-preserve-unknown-fields: true type: object + kubeAPIServer: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + kubeAPIServer configures the kube-apiserver component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + kubeControllerManager: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + kubeControllerManager configures the kube-controller-manager component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + kubeScheduler: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + kubeScheduler configures the kube-scheduler component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + oauthServer: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + oauthServer configures the oauth-server component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + openShiftAPIServer: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + openShiftAPIServer configures the openshift-apiserver component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + openShiftControllerManager: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + openShiftControllerManager configures the openshift-controller-manager component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + openShiftOAuthAPIServer: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + openShiftOAuthAPIServer configures the openshift-oauth-apiserver component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object type: object pausedUntil: description: pausedUntil is a field that can be used to pause reconciliation on the HostedCluster controller, resulting in any change to the HostedCluster being ignored. @@ -3708,6 +4079,49 @@ components: - PublicAndPrivate - Private type: string + managedDNS: + description: |- + managedDNS configures CPO-managed Route53 DNS zones for this cluster. + An empty object ({}) enables managed DNS with all defaults. + minProperties: 0 + properties: + delegation: + description: |- + delegation configures service-side DNS delegation for certificate generation. + When set, the CPO creates an ACME DNS01 challenge CNAME in the public ingress + zone and handles NS delegation based on the nsDelegation mode. + When absent, only zones are created and the consuming platform handles + delegation and certificate management. + properties: + nsDelegation: + description: |- + nsDelegation specifies how NS delegation records are created in the parent zone. + "ExternalDNS": the CPO creates a DNSEndpoint CR in the control plane namespace; + external-dns creates NS records in the parent zone. + "Manual": the consuming platform handles NS delegation using nameservers + reported in HostedCluster status. + enum: + - ExternalDNS + - Manual + type: string + required: + - nsDelegation + type: object + ingressDomainPrefix: + default: in + description: |- + ingressDomainPrefix is the subdomain prefix for ingress DNS zones. + Zones are created as {prefix}.{baseDomainPrefix}.{baseDomain}. + When delegation is configured, the prefix creates a DNS delegation boundary + that separates the ingress zone from the cluster domain, enabling ACME + challenge CNAME delegation back to the parent zone. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: ingressDomainPrefix must consist of lowercase alphanumeric characters or '-', and must start and end with an alphanumeric character + rule: self.matches('^[a-z0-9]([a-z0-9-]*[a-z0-9])?$') + type: object multiArch: default: false description: |- @@ -3736,26 +4150,54 @@ components: Changes to this field will be propagated in-place to AWS resources (VPC Endpoints, EC2 instances, initial EBS volumes and default/endpoint security groups). These tags will be propagated to the infrastructure CR in the guest cluster, where other OCP operators might choose to honor this input to reconcile AWS resources created by them. Please consult the official documentation for a list of all AWS resources that support in-place tag updates. + For NodePool-created resources (EC2 instances and their initial EBS volumes), these will be merged with NodePool-scoped tags. + By default, HostedCluster tags take precedence over NodePool tags when both specify the same key. + To allow a NodePool tag to override a specific HostedCluster tag, set overridePolicy to "Allow" on that tag. + Cluster-scoped resources (VPC endpoints, security groups) only receive HostedCluster tags. These take precedence over tags defined out of band (i.e., tags added manually or by other tools outside of HyperShift) in AWS in case of conflicts. items: - description: AWSResourceTag is a tag to apply to AWS resources created for the cluster. + description: |- + AWSClusterResourceTag is a tag to apply to AWS resources created for a + HostedCluster. It extends the base tag with an overridePolicy field that + controls whether NodePool-level tags can override this tag. properties: key: - description: key is the key of the tag. + description: |- + key is the key of the tag. + Must be between 1 and 128 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ maxLength: 128 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ + type: string + x-kubernetes-validations: + - message: 'key must only contain letters, digits, spaces, and the characters _ . : / = + - @' + rule: self.matches('^[0-9A-Za-z _.:/=+@-]+$') + overridePolicy: + description: |- + overridePolicy controls whether a NodePool-level tag with the same key can + override this HostedCluster-level tag. + When set to "Allow", a NodePool tag with the same key will take precedence + over this HostedCluster tag. When set to "Deny" or omitted, the + HostedCluster value is preserved and the NodePool tag is ignored for that + key. + enum: + - Allow + - Deny type: string value: description: |- value is the value of the tag. + Must be between 1 and 256 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ Some AWS service do not support empty values. Since tags are added to resources in many services, the length of the tag value must meet the requirements of all services. maxLength: 256 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ type: string + x-kubernetes-validations: + - message: 'value must only contain letters, digits, spaces, and the characters _ . : / = + - @' + rule: self.matches('^[0-9A-Za-z _.:/=+@-]+$') required: - key - value @@ -4359,7 +4801,7 @@ components: conditions: description: |- Conditions represent the latest observations of the cluster's state. - Known condition types: Synced, Available, Degraded, ControlPlaneUpgradeState. + Known condition types: Synced, Available, Degraded, ControlPlaneUpgradeState, AWSManagedDNSAvailable. items: description: Condition contains details for one aspect of the current state of this API Resource. properties: @@ -4443,6 +4885,47 @@ components: format: date-time type: string type: object + dnsZones: + description: |- + DNSZones contains DNS zone information for zones managed by the control plane. + Populated from the HostedCluster's platform status when managed ingress DNS is enabled. + items: + description: AWSDNSZoneStatus represents a managed Route53 DNS zone and its metadata. + properties: + name: + description: name is the DNS name of the hosted zone. + maxLength: 253 + minLength: 1 + type: string + nameServers: + description: |- + nameServers are the authoritative name servers for this zone. + Used for NS delegation when external-dns is not available. + items: + maxLength: 253 + minLength: 1 + type: string + maxItems: 10 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + zoneID: + description: zoneID is the Route53 hosted zone ID. + maxLength: 32 + minLength: 1 + type: string + zoneType: + description: zoneType indicates the purpose of the zone. + enum: + - PublicIngress + - PrivateIngress + type: string + required: + - name + - zoneID + - zoneType + type: object + type: array observedGeneration: description: ObservedGeneration is the most recent generation observed by the controller. format: int64 @@ -5312,6 +5795,67 @@ components: x-kubernetes-validations: - message: mtu is immutable once set rule: self == oldSelf + v4InternalSubnet: + description: |- + v4InternalSubnet configures the IPv4 subnet used by OVN-Kubernetes for gateway + router logical router port (LRP) addresses and masquerade/SNAT traffic within + the OVN logical topology. It must not overlap with any other subnet being used + by OpenShift or by the node network. The size of the subnet must be larger than + the number of nodes. + This field is distinct from ipv4.internalJoinSubnet, which configures the subnet + for the join switch that interconnects per-node gateway routers with the cluster + router. Both default to 100.64.0.0/16 but control different OVN-Kubernetes + internal networks and can be configured independently to avoid overlaps with + existing network infrastructure. + Once set, the value is immutable and cannot be modified in subsequent updates. + The default is 100.64.0.0/16. + The value must be in IPv4 CIDR notation (e.g., 192.168.0.0/16), consisting of + four decimal octets (0-255) separated by dots, followed by a slash and a prefix + length. The prefix length must be between 0 and 30 inclusive, and the first + octet must not be 0. + The value must be between 9 and 18 characters in length. + This field is immutable once set. + maxLength: 18 + minLength: 9 + type: string + x-kubernetes-validations: + - message: v4InternalSubnet is immutable once set + rule: self == oldSelf + - message: Subnet must be in a valid IPv4 CIDR format + rule: isCIDR(self) && cidr(self).ip().family() == 4 + - message: subnet must be in the range /0 to /30 inclusive + rule: isCIDR(self) && cidr(self).prefixLength() <= 30 + - message: first IP address octet must not be 0 + rule: isCIDR(self) && cidr(self).ip().family() == 4 && int(self.split('.')[0]) > 0 + v6InternalSubnet: + description: |- + v6InternalSubnet configures the IPv6 subnet used by OVN-Kubernetes for gateway + router logical router port (LRP) addresses and masquerade/SNAT traffic within + the OVN logical topology. It must not overlap with any other subnet being used + by OpenShift or by the node network. The size of the subnet must be larger than + the number of nodes. + This field is distinct from ipv6.internalJoinSubnet, which configures the subnet + for the join switch that interconnects per-node gateway routers with the cluster + router. Both default to fd98::/64 but control different OVN-Kubernetes internal + networks and can be configured independently to avoid overlaps with existing + network infrastructure. + Once set, the value is immutable and cannot be modified in subsequent updates. + The default is fd98::/64. + The value must be in IPv6 CIDR notation (e.g., fd98::/64), consisting of an + IPv6 address followed by a slash and a prefix length. The prefix length must + be between 0 and 125 inclusive. + The value must be between 4 and 48 characters in length. + This field is immutable once set. + maxLength: 48 + minLength: 4 + type: string + x-kubernetes-validations: + - message: v6InternalSubnet is immutable once set + rule: self == oldSelf + - message: Subnet must be in valid IPv6 CIDR format + rule: isCIDR(self) && cidr(self).ip().family() == 6 + - message: subnet must be in the range /0 to /125 inclusive + rule: isCIDR(self) && cidr(self).prefixLength() <= 125 type: object x-kubernetes-validations: - message: internalJoinSubnet and internalTransitSwitchSubnet must not be the same @@ -5326,6 +5870,10 @@ components: rule: '!has(oldSelf.ipv6) || !has(oldSelf.ipv6.internalJoinSubnet) || (has(self.ipv6) && has(self.ipv6.internalJoinSubnet))' - message: ipv6.internalTransitSwitchSubnet cannot be removed once set rule: '!has(oldSelf.ipv6) || !has(oldSelf.ipv6.internalTransitSwitchSubnet) || (has(self.ipv6) && has(self.ipv6.internalTransitSwitchSubnet))' + - message: v4InternalSubnet is immutable once set and cannot be removed + rule: '!has(oldSelf.v4InternalSubnet) || has(self.v4InternalSubnet)' + - message: v6InternalSubnet is immutable once set and cannot be removed + rule: '!has(oldSelf.v6InternalSubnet) || has(self.v6InternalSubnet)' type: object x-kubernetes-validations: - message: ovnKubernetesConfig is immutable once set and cannot be removed @@ -5341,18 +5889,88 @@ components: Valid values are: "Normal", "Debug", "Trace", "TraceAll". Defaults to "Normal". enum: - - "" - Normal - Debug - Trace - TraceAll type: string type: object + etcd: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + etcd configures the etcd component. + Setting the logLevel field triggers a rolling restart of the component. + Note: etcd supports fewer log levels than klog-based components, + etcd supports only Normal and Debug log levels. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + x-kubernetes-validations: + - message: etcd only supports Normal and Debug log levels; Trace and TraceAll are not valid for etcd + rule: '!has(self.logLevel) || self.logLevel in [''Normal'', ''Debug'']' ingressOperator: description: |- ingressOperator specifies the configuration for the Ingress Operator in the hosted cluster. This allows configuring how the default ingress controller endpoints are published. properties: + defaultCertificate: + description: |- + defaultCertificate is a reference to a secret in the HostedCluster namespace + that contains the default certificate served by the default ingress controller. + When Routes don't specify their own certificate, defaultCertificate is used. + The secret must contain the following keys and data: + tls.crt: certificate file contents + tls.key: key file contents + When set, this certificate replaces the auto-generated wildcard certificate + that is normally created by the control plane operator. The secret is synced + from the HostedCluster namespace to the control plane, and then propagated + to the hosted cluster's openshift-ingress namespace. + When the referenced secret is updated, the new certificate data is + automatically propagated to the hosted cluster. + When not set, the control plane operator generates a wildcard certificate + signed by the cluster's root CA. + Note: a cluster-admin in the hosted cluster can override the default ingress + controller's certificate directly. That override takes precedence and the + certificate referenced here is no longer served. + properties: + name: + description: |- + name is the name of the Secret containing tls.crt and tls.key. + The Secret must exist in the same namespace as the HostedCluster. + name must be a valid DNS subdomain name (RFC 1123): it must contain only + lowercase alphanumeric characters, '-' or '.', and start and end with an + alphanumeric character. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'name must be a valid DNS subdomain name: contain no more than 253 characters, contain only lowercase alphanumeric characters, ''-'' or ''.'', and start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$') + required: + - name + type: object endpointPublishingStrategy: description: |- endpointPublishingStrategy is used to publish the default ingress controller endpoints. @@ -5617,6 +6235,32 @@ components: x-kubernetes-validations: - message: eipAllocations cannot contain duplicates rule: self.all(x, self.exists_one(y, x == y)) + protocol: + description: |- + protocol specifies whether the Network Load Balancer uses PROXY + protocol to forward connections to the IngressController. + When set to "TCP", the NLB uses AWS's native client IP preservation. + This may cause hairpin connection failures for internal load + balancers when connections are made from pods to router pods on + the same node. + When set to "PROXY", the NLB disables native client IP preservation + and uses PROXY protocol v2. The IngressController enables PROXY + protocol on HAProxy so that it can parse PROXY protocol headers to + obtain the original client IP. This avoids hairpin connection + failures. + The following values are valid for this field: + * "TCP". + * "PROXY". + When omitted, this means the user has no opinion and the value is + left to the platform to choose a reasonable default, which is subject to + change over time. The current default is "PROXY". + Note that changing this field may cause brief connection failures + during the transition as the NLB attribute change and router rollout + occur independently. + enum: + - TCP + - PROXY + type: string subnets: description: |- subnets specifies the subnets to which the load balancer will @@ -5932,6 +6576,216 @@ components: type: object x-kubernetes-preserve-unknown-fields: true type: object + kubeAPIServer: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + kubeAPIServer configures the kube-apiserver component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + kubeControllerManager: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + kubeControllerManager configures the kube-controller-manager component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + kubeScheduler: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + kubeScheduler configures the kube-scheduler component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + oauthServer: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + oauthServer configures the oauth-server component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + openShiftAPIServer: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + openShiftAPIServer configures the openshift-apiserver component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + openShiftControllerManager: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + openShiftControllerManager configures the openshift-controller-manager component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + openShiftOAuthAPIServer: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + openShiftOAuthAPIServer configures the openshift-oauth-apiserver component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object type: object pausedUntil: description: pausedUntil is a field that can be used to pause reconciliation on the HostedCluster controller, resulting in any change to the HostedCluster being ignored. @@ -6017,6 +6871,49 @@ components: - PublicAndPrivate - Private type: string + managedDNS: + description: |- + managedDNS configures CPO-managed Route53 DNS zones for this cluster. + An empty object ({}) enables managed DNS with all defaults. + minProperties: 0 + properties: + delegation: + description: |- + delegation configures service-side DNS delegation for certificate generation. + When set, the CPO creates an ACME DNS01 challenge CNAME in the public ingress + zone and handles NS delegation based on the nsDelegation mode. + When absent, only zones are created and the consuming platform handles + delegation and certificate management. + properties: + nsDelegation: + description: |- + nsDelegation specifies how NS delegation records are created in the parent zone. + "ExternalDNS": the CPO creates a DNSEndpoint CR in the control plane namespace; + external-dns creates NS records in the parent zone. + "Manual": the consuming platform handles NS delegation using nameservers + reported in HostedCluster status. + enum: + - ExternalDNS + - Manual + type: string + required: + - nsDelegation + type: object + ingressDomainPrefix: + default: in + description: |- + ingressDomainPrefix is the subdomain prefix for ingress DNS zones. + Zones are created as {prefix}.{baseDomainPrefix}.{baseDomain}. + When delegation is configured, the prefix creates a DNS delegation boundary + that separates the ingress zone from the cluster domain, enabling ACME + challenge CNAME delegation back to the parent zone. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: ingressDomainPrefix must consist of lowercase alphanumeric characters or '-', and must start and end with an alphanumeric character + rule: self.matches('^[a-z0-9]([a-z0-9-]*[a-z0-9])?$') + type: object multiArch: default: false description: |- @@ -6045,26 +6942,54 @@ components: Changes to this field will be propagated in-place to AWS resources (VPC Endpoints, EC2 instances, initial EBS volumes and default/endpoint security groups). These tags will be propagated to the infrastructure CR in the guest cluster, where other OCP operators might choose to honor this input to reconcile AWS resources created by them. Please consult the official documentation for a list of all AWS resources that support in-place tag updates. + For NodePool-created resources (EC2 instances and their initial EBS volumes), these will be merged with NodePool-scoped tags. + By default, HostedCluster tags take precedence over NodePool tags when both specify the same key. + To allow a NodePool tag to override a specific HostedCluster tag, set overridePolicy to "Allow" on that tag. + Cluster-scoped resources (VPC endpoints, security groups) only receive HostedCluster tags. These take precedence over tags defined out of band (i.e., tags added manually or by other tools outside of HyperShift) in AWS in case of conflicts. items: - description: AWSResourceTag is a tag to apply to AWS resources created for the cluster. + description: |- + AWSClusterResourceTag is a tag to apply to AWS resources created for a + HostedCluster. It extends the base tag with an overridePolicy field that + controls whether NodePool-level tags can override this tag. properties: key: - description: key is the key of the tag. + description: |- + key is the key of the tag. + Must be between 1 and 128 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ maxLength: 128 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ + type: string + x-kubernetes-validations: + - message: 'key must only contain letters, digits, spaces, and the characters _ . : / = + - @' + rule: self.matches('^[0-9A-Za-z _.:/=+@-]+$') + overridePolicy: + description: |- + overridePolicy controls whether a NodePool-level tag with the same key can + override this HostedCluster-level tag. + When set to "Allow", a NodePool tag with the same key will take precedence + over this HostedCluster tag. When set to "Deny" or omitted, the + HostedCluster value is preserved and the NodePool tag is ignored for that + key. + enum: + - Allow + - Deny type: string value: description: |- value is the value of the tag. + Must be between 1 and 256 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ Some AWS service do not support empty values. Since tags are added to resources in many services, the length of the tag value must meet the requirements of all services. maxLength: 256 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ type: string + x-kubernetes-validations: + - message: 'value must only contain letters, digits, spaces, and the characters _ . : / = + - @' + rule: self.matches('^[0-9A-Za-z _.:/=+@-]+$') required: - key - value @@ -6668,7 +7593,7 @@ components: conditions: description: |- Conditions represent the latest observations of the cluster's state. - Known condition types: Synced, Available, Degraded, ControlPlaneUpgradeState. + Known condition types: Synced, Available, Degraded, ControlPlaneUpgradeState, AWSManagedDNSAvailable. items: description: Condition contains details for one aspect of the current state of this API Resource. properties: @@ -6752,6 +7677,47 @@ components: format: date-time type: string type: object + dnsZones: + description: |- + DNSZones contains DNS zone information for zones managed by the control plane. + Populated from the HostedCluster's platform status when managed ingress DNS is enabled. + items: + description: AWSDNSZoneStatus represents a managed Route53 DNS zone and its metadata. + properties: + name: + description: name is the DNS name of the hosted zone. + maxLength: 253 + minLength: 1 + type: string + nameServers: + description: |- + nameServers are the authoritative name servers for this zone. + Used for NS delegation when external-dns is not available. + items: + maxLength: 253 + minLength: 1 + type: string + maxItems: 10 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + zoneID: + description: zoneID is the Route53 hosted zone ID. + maxLength: 32 + minLength: 1 + type: string + zoneType: + description: zoneType indicates the purpose of the zone. + enum: + - PublicIngress + - PrivateIngress + type: string + required: + - name + - zoneID + - zoneType + type: object + type: array observedGeneration: description: ObservedGeneration is the most recent generation observed by the controller. format: int64 @@ -6917,6 +7883,25 @@ components: is chosen based on the NodePool release payload image. maxLength: 255 type: string + cpuOptions: + description: |- + cpuOptions specifies CPU configuration for EC2 instances. + Supported on C8i, M8i, and R8i instance families. + When omitted, AWS defaults are used (nested virtualization is not enabled). + To revert to default behavior after setting cpuOptions, remove the entire + cpuOptions field rather than clearing individual sub-fields. + minProperties: 1 + properties: + nestedVirtualizationPolicy: + description: |- + nestedVirtualizationPolicy indicates whether to enable nested virtualization on the instance. + Supported on C8i, M8i, and R8i instance families. + When omitted, nested virtualization is not enabled (AWS default behavior). + enum: + - Enabled + - Disabled + type: string + type: object imageType: description: |- imageType specifies the type of image to use for node instances. @@ -7060,34 +8045,56 @@ components: rule: '!has(self.spot) || (has(self.marketType) && self.marketType == ''Spot'')' resourceTags: description: |- - resourceTags is an optional list of additional tags to apply to AWS node - instances. Changes to this field will be propagated in-place to AWS EC2 instances and their initial EBS volumes. - Volumes created by the storage operator and attached to instances after they are created do not get these tags applied. - These will be merged with HostedCluster scoped tags, which take precedence in case of conflicts. - These take precedence over tags defined out of band (i.e., tags added manually or by other tools outside of HyperShift) in AWS in case of conflicts. + resourceTags is a list of additional tags to apply to AWS resources created + for the NodePool. Changes to this field will be propagated in-place to AWS + EC2 instances and their initial EBS volumes. Volumes created by the storage + operator and attached to instances after they are created do not get these + tags applied. + These are merged with HostedCluster-level tags. By default, HostedCluster + tags take precedence when both specify the same key. To allow a NodePool + tag to override a specific HostedCluster tag, set overridePolicy to "Allow" + on the HostedCluster tag. + Tags that only exist at the NodePool level (no conflict) are always applied. + These take precedence over tags defined out of band (i.e., tags added + manually or by other tools outside of HyperShift) in AWS in case of + conflicts. See https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html for information on tagging AWS resources. AWS supports a maximum of 50 tags per resource. OpenShift reserves 25 tags for its use, leaving 25 tags available for the user. items: - description: AWSResourceTag is a tag to apply to AWS resources created for the cluster. + description: |- + AWSNodePoolResourceTag is a tag to apply to AWS resources created for a + NodePool. These tags are merged with HostedCluster-level tags. By default, + HostedCluster tags take precedence when both specify the same key. To allow + a NodePool tag to override a specific HostedCluster tag, set overridePolicy + to "Allow" on the HostedCluster tag. properties: key: - description: key is the key of the tag. + description: |- + key is the key of the tag. + Must be between 1 and 128 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ maxLength: 128 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ type: string + x-kubernetes-validations: + - message: 'key must only contain letters, digits, spaces, and the characters _ . : / = + - @' + rule: self.matches('^[0-9A-Za-z _.:/=+@-]+$') value: description: |- value is the value of the tag. + Must be between 1 and 256 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ Some AWS service do not support empty values. Since tags are added to resources in many services, the length of the tag value must meet the requirements of all services. maxLength: 256 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ type: string + x-kubernetes-validations: + - message: 'value must only contain letters, digits, spaces, and the characters _ . : / = + - @' + rule: self.matches('^[0-9A-Za-z _.:/=+@-]+$') required: - key - value @@ -7394,6 +8401,25 @@ components: is chosen based on the NodePool release payload image. maxLength: 255 type: string + cpuOptions: + description: |- + cpuOptions specifies CPU configuration for EC2 instances. + Supported on C8i, M8i, and R8i instance families. + When omitted, AWS defaults are used (nested virtualization is not enabled). + To revert to default behavior after setting cpuOptions, remove the entire + cpuOptions field rather than clearing individual sub-fields. + minProperties: 1 + properties: + nestedVirtualizationPolicy: + description: |- + nestedVirtualizationPolicy indicates whether to enable nested virtualization on the instance. + Supported on C8i, M8i, and R8i instance families. + When omitted, nested virtualization is not enabled (AWS default behavior). + enum: + - Enabled + - Disabled + type: string + type: object imageType: description: |- imageType specifies the type of image to use for node instances. @@ -7537,34 +8563,56 @@ components: rule: '!has(self.spot) || (has(self.marketType) && self.marketType == ''Spot'')' resourceTags: description: |- - resourceTags is an optional list of additional tags to apply to AWS node - instances. Changes to this field will be propagated in-place to AWS EC2 instances and their initial EBS volumes. - Volumes created by the storage operator and attached to instances after they are created do not get these tags applied. - These will be merged with HostedCluster scoped tags, which take precedence in case of conflicts. - These take precedence over tags defined out of band (i.e., tags added manually or by other tools outside of HyperShift) in AWS in case of conflicts. + resourceTags is a list of additional tags to apply to AWS resources created + for the NodePool. Changes to this field will be propagated in-place to AWS + EC2 instances and their initial EBS volumes. Volumes created by the storage + operator and attached to instances after they are created do not get these + tags applied. + These are merged with HostedCluster-level tags. By default, HostedCluster + tags take precedence when both specify the same key. To allow a NodePool + tag to override a specific HostedCluster tag, set overridePolicy to "Allow" + on the HostedCluster tag. + Tags that only exist at the NodePool level (no conflict) are always applied. + These take precedence over tags defined out of band (i.e., tags added + manually or by other tools outside of HyperShift) in AWS in case of + conflicts. See https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html for information on tagging AWS resources. AWS supports a maximum of 50 tags per resource. OpenShift reserves 25 tags for its use, leaving 25 tags available for the user. items: - description: AWSResourceTag is a tag to apply to AWS resources created for the cluster. + description: |- + AWSNodePoolResourceTag is a tag to apply to AWS resources created for a + NodePool. These tags are merged with HostedCluster-level tags. By default, + HostedCluster tags take precedence when both specify the same key. To allow + a NodePool tag to override a specific HostedCluster tag, set overridePolicy + to "Allow" on the HostedCluster tag. properties: key: - description: key is the key of the tag. + description: |- + key is the key of the tag. + Must be between 1 and 128 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ maxLength: 128 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ type: string + x-kubernetes-validations: + - message: 'key must only contain letters, digits, spaces, and the characters _ . : / = + - @' + rule: self.matches('^[0-9A-Za-z _.:/=+@-]+$') value: description: |- value is the value of the tag. + Must be between 1 and 256 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ Some AWS service do not support empty values. Since tags are added to resources in many services, the length of the tag value must meet the requirements of all services. maxLength: 256 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ type: string + x-kubernetes-validations: + - message: 'value must only contain letters, digits, spaces, and the characters _ . : / = + - @' + rule: self.matches('^[0-9A-Za-z _.:/=+@-]+$') required: - key - value @@ -8104,7 +9152,7 @@ components: conditions: description: |- Conditions represent the latest observations of the cluster's state. - Known condition types: Synced, Available, Degraded, ControlPlaneUpgradeState. + Known condition types: Synced, Available, Degraded, ControlPlaneUpgradeState, AWSManagedDNSAvailable. items: description: Condition contains details for one aspect of the current state of this API Resource. properties: @@ -8188,6 +9236,47 @@ components: format: date-time type: string type: object + dnsZones: + description: |- + DNSZones contains DNS zone information for zones managed by the control plane. + Populated from the HostedCluster's platform status when managed ingress DNS is enabled. + items: + description: AWSDNSZoneStatus represents a managed Route53 DNS zone and its metadata. + properties: + name: + description: name is the DNS name of the hosted zone. + maxLength: 253 + minLength: 1 + type: string + nameServers: + description: |- + nameServers are the authoritative name servers for this zone. + Used for NS delegation when external-dns is not available. + items: + maxLength: 253 + minLength: 1 + type: string + maxItems: 10 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + zoneID: + description: zoneID is the Route53 hosted zone ID. + maxLength: 32 + minLength: 1 + type: string + zoneType: + description: zoneType indicates the purpose of the zone. + enum: + - PublicIngress + - PrivateIngress + type: string + required: + - name + - zoneID + - zoneType + type: object + type: array observedGeneration: description: ObservedGeneration is the most recent generation observed by the controller. format: int64 @@ -8794,6 +9883,25 @@ components: is chosen based on the NodePool release payload image. maxLength: 255 type: string + cpuOptions: + description: |- + cpuOptions specifies CPU configuration for EC2 instances. + Supported on C8i, M8i, and R8i instance families. + When omitted, AWS defaults are used (nested virtualization is not enabled). + To revert to default behavior after setting cpuOptions, remove the entire + cpuOptions field rather than clearing individual sub-fields. + minProperties: 1 + properties: + nestedVirtualizationPolicy: + description: |- + nestedVirtualizationPolicy indicates whether to enable nested virtualization on the instance. + Supported on C8i, M8i, and R8i instance families. + When omitted, nested virtualization is not enabled (AWS default behavior). + enum: + - Enabled + - Disabled + type: string + type: object imageType: description: |- imageType specifies the type of image to use for node instances. @@ -8937,34 +10045,56 @@ components: rule: '!has(self.spot) || (has(self.marketType) && self.marketType == ''Spot'')' resourceTags: description: |- - resourceTags is an optional list of additional tags to apply to AWS node - instances. Changes to this field will be propagated in-place to AWS EC2 instances and their initial EBS volumes. - Volumes created by the storage operator and attached to instances after they are created do not get these tags applied. - These will be merged with HostedCluster scoped tags, which take precedence in case of conflicts. - These take precedence over tags defined out of band (i.e., tags added manually or by other tools outside of HyperShift) in AWS in case of conflicts. + resourceTags is a list of additional tags to apply to AWS resources created + for the NodePool. Changes to this field will be propagated in-place to AWS + EC2 instances and their initial EBS volumes. Volumes created by the storage + operator and attached to instances after they are created do not get these + tags applied. + These are merged with HostedCluster-level tags. By default, HostedCluster + tags take precedence when both specify the same key. To allow a NodePool + tag to override a specific HostedCluster tag, set overridePolicy to "Allow" + on the HostedCluster tag. + Tags that only exist at the NodePool level (no conflict) are always applied. + These take precedence over tags defined out of band (i.e., tags added + manually or by other tools outside of HyperShift) in AWS in case of + conflicts. See https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html for information on tagging AWS resources. AWS supports a maximum of 50 tags per resource. OpenShift reserves 25 tags for its use, leaving 25 tags available for the user. items: - description: AWSResourceTag is a tag to apply to AWS resources created for the cluster. + description: |- + AWSNodePoolResourceTag is a tag to apply to AWS resources created for a + NodePool. These tags are merged with HostedCluster-level tags. By default, + HostedCluster tags take precedence when both specify the same key. To allow + a NodePool tag to override a specific HostedCluster tag, set overridePolicy + to "Allow" on the HostedCluster tag. properties: key: - description: key is the key of the tag. + description: |- + key is the key of the tag. + Must be between 1 and 128 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ maxLength: 128 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ type: string + x-kubernetes-validations: + - message: 'key must only contain letters, digits, spaces, and the characters _ . : / = + - @' + rule: self.matches('^[0-9A-Za-z _.:/=+@-]+$') value: description: |- value is the value of the tag. + Must be between 1 and 256 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ Some AWS service do not support empty values. Since tags are added to resources in many services, the length of the tag value must meet the requirements of all services. maxLength: 256 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ type: string + x-kubernetes-validations: + - message: 'value must only contain letters, digits, spaces, and the characters _ . : / = + - @' + rule: self.matches('^[0-9A-Za-z _.:/=+@-]+$') required: - key - value @@ -9176,6 +10306,49 @@ components: - PublicAndPrivate - Private type: string + managedDNS: + description: |- + managedDNS configures CPO-managed Route53 DNS zones for this cluster. + An empty object ({}) enables managed DNS with all defaults. + minProperties: 0 + properties: + delegation: + description: |- + delegation configures service-side DNS delegation for certificate generation. + When set, the CPO creates an ACME DNS01 challenge CNAME in the public ingress + zone and handles NS delegation based on the nsDelegation mode. + When absent, only zones are created and the consuming platform handles + delegation and certificate management. + properties: + nsDelegation: + description: |- + nsDelegation specifies how NS delegation records are created in the parent zone. + "ExternalDNS": the CPO creates a DNSEndpoint CR in the control plane namespace; + external-dns creates NS records in the parent zone. + "Manual": the consuming platform handles NS delegation using nameservers + reported in HostedCluster status. + enum: + - ExternalDNS + - Manual + type: string + required: + - nsDelegation + type: object + ingressDomainPrefix: + default: in + description: |- + ingressDomainPrefix is the subdomain prefix for ingress DNS zones. + Zones are created as {prefix}.{baseDomainPrefix}.{baseDomain}. + When delegation is configured, the prefix creates a DNS delegation boundary + that separates the ingress zone from the cluster domain, enabling ACME + challenge CNAME delegation back to the parent zone. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: ingressDomainPrefix must consist of lowercase alphanumeric characters or '-', and must start and end with an alphanumeric character + rule: self.matches('^[a-z0-9]([a-z0-9-]*[a-z0-9])?$') + type: object multiArch: default: false description: |- @@ -9204,26 +10377,54 @@ components: Changes to this field will be propagated in-place to AWS resources (VPC Endpoints, EC2 instances, initial EBS volumes and default/endpoint security groups). These tags will be propagated to the infrastructure CR in the guest cluster, where other OCP operators might choose to honor this input to reconcile AWS resources created by them. Please consult the official documentation for a list of all AWS resources that support in-place tag updates. + For NodePool-created resources (EC2 instances and their initial EBS volumes), these will be merged with NodePool-scoped tags. + By default, HostedCluster tags take precedence over NodePool tags when both specify the same key. + To allow a NodePool tag to override a specific HostedCluster tag, set overridePolicy to "Allow" on that tag. + Cluster-scoped resources (VPC endpoints, security groups) only receive HostedCluster tags. These take precedence over tags defined out of band (i.e., tags added manually or by other tools outside of HyperShift) in AWS in case of conflicts. items: - description: AWSResourceTag is a tag to apply to AWS resources created for the cluster. + description: |- + AWSClusterResourceTag is a tag to apply to AWS resources created for a + HostedCluster. It extends the base tag with an overridePolicy field that + controls whether NodePool-level tags can override this tag. properties: key: - description: key is the key of the tag. + description: |- + key is the key of the tag. + Must be between 1 and 128 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ maxLength: 128 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ + type: string + x-kubernetes-validations: + - message: 'key must only contain letters, digits, spaces, and the characters _ . : / = + - @' + rule: self.matches('^[0-9A-Za-z _.:/=+@-]+$') + overridePolicy: + description: |- + overridePolicy controls whether a NodePool-level tag with the same key can + override this HostedCluster-level tag. + When set to "Allow", a NodePool tag with the same key will take precedence + over this HostedCluster tag. When set to "Deny" or omitted, the + HostedCluster value is preserved and the NodePool tag is ignored for that + key. + enum: + - Allow + - Deny type: string value: description: |- value is the value of the tag. + Must be between 1 and 256 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ Some AWS service do not support empty values. Since tags are added to resources in many services, the length of the tag value must meet the requirements of all services. maxLength: 256 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ type: string + x-kubernetes-validations: + - message: 'value must only contain letters, digits, spaces, and the characters _ . : / = + - @' + rule: self.matches('^[0-9A-Za-z _.:/=+@-]+$') required: - key - value diff --git a/api/v1alpha1/public/zz_generated.deepcopy.go b/api/v1alpha1/public/zz_generated.deepcopy.go index 51075fd20..8fae677c2 100644 --- a/api/v1alpha1/public/zz_generated.deepcopy.go +++ b/api/v1alpha1/public/zz_generated.deepcopy.go @@ -149,6 +149,13 @@ func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) { } } out.ControlPlaneEndpoint = in.ControlPlaneEndpoint + if in.DNSZones != nil { + in, out := &in.DNSZones, &out.DNSZones + *out = make([]v1beta1.AWSDNSZoneStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.PlacementRef != nil { in, out := &in.PlacementRef, &out.PlacementRef *out = new(PlacementReference) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 08596d1e1..bfeb11abb 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -225,6 +225,13 @@ func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) { } } out.ControlPlaneEndpoint = in.ControlPlaneEndpoint + if in.DNSZones != nil { + in, out := &in.DNSZones, &out.DNSZones + *out = make([]v1beta1.AWSDNSZoneStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.PlacementRef != nil { in, out := &in.PlacementRef, &out.PlacementRef *out = new(PlacementReference) diff --git a/clientset/go.mod b/clientset/go.mod index 6dafceab7..6c968b272 100644 --- a/clientset/go.mod +++ b/clientset/go.mod @@ -39,7 +39,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 // indirect + github.com/openshift/api v0.0.0-20260805160557-b61243060d5f // indirect github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect @@ -52,9 +52,9 @@ require ( google.golang.org/protobuf v1.36.12 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/api v0.36.0 // indirect + k8s.io/api v0.36.2 // indirect k8s.io/klog/v2 v2.140.0 // indirect - k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect + k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 // indirect k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect @@ -63,3 +63,5 @@ require ( ) replace github.com/openshift-online/rosa-hyperfleet-api/api => ../api + +replace github.com/openshift/hypershift/api => github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345 diff --git a/clientset/go.sum b/clientset/go.sum index f68c9f49e..a422beb65 100644 --- a/clientset/go.sum +++ b/clientset/go.sum @@ -70,10 +70,8 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 h1:r0S/yoZAI0iWo1JvoIijaIgWGWf/izg4WiV7Wrtz16k= -github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo= -github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 h1:QDSh3vkKYq7Fn9utYGlAJadkTdyaRl9IY7Cr6cNDAow= -github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16/go.mod h1:Z3lkj5pFqY+KTl3Do9gXdEZdKWLnkUTSDShLD1HE0CM= +github.com/openshift/api v0.0.0-20260805160557-b61243060d5f h1:NU7ltJhtFhqAJC+77DcNk6jmIpsJ3a+mebZIceiPW+U= +github.com/openshift/api v0.0.0-20260805160557-b61243060d5f/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -87,6 +85,8 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345 h1:4Hi+KoXlzdHAiKSMnGFF1yfvPFpkb08r0yO6SPlq4vQ= +github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345/go.mod h1:v7kWzwoisePl3ewusWeexcHlkO5MJNs+x9ORRPkqDC4= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= @@ -116,16 +116,16 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.36.0 h1:SgqDhZzHdOtMk40xVSvCXkP9ME0H05hPM3p9AB1kL80= -k8s.io/api v0.36.0/go.mod h1:m1LVrGPNYax5NBHdO+QuAedXyuzTt4RryI/qnmNvs34= +k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY= +k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg= k8s.io/apimachinery v0.36.3 h1:PkzMRBRG8joFD8EhCuQAtNPvJlxb82FwplP26HIzvAM= k8s.io/apimachinery v0.36.3/go.mod h1:cTSjBWgPe/6CQyBKzY/hDIRWCQQQeK0mfLbml0UYFHE= k8s.io/client-go v0.36.0 h1:pOYi7C4RHChYjMiHpZSpSbIM6ZxVbRXBy7CuiIwqA3c= k8s.io/client-go v0.36.0/go.mod h1:ZKKcpwF0aLYfkHFCjillCKaTK/yBkEDHTDXCFY6AS9Y= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= +k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 h1:A7Lby6ekC6nv+6oO38huCMFBRP0Os+tIeq1GkwxOQes= +k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288/go.mod h1:V/QaCUYDa+0QpcHhVVc5l99Uz56wEMEXBSj9oCDkNDY= k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 h1:jVkFFVfXdXP74B/zbO3hM3hpSFD0xvhQ5U686DPurkE= k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3/go.mod h1:M2s5JB1lIYP3jzZdorPLHXIPJzt9vv2muW5a6L9DtNM= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= diff --git a/clientset/pathbind/pathbind-draft.yaml b/clientset/pathbind/pathbind-draft.yaml index 7db92fb94..f3f777681 100644 --- a/clientset/pathbind/pathbind-draft.yaml +++ b/clientset/pathbind/pathbind-draft.yaml @@ -180,6 +180,16 @@ resources: operations: - create - update + - path: spec.hostedCluster.platform.aws.managedDNS.delegation.nsDelegation + goType: string + operations: + - create + - update + - path: spec.hostedCluster.platform.aws.managedDNS.ingressDomainPrefix + goType: string + operations: + - create + - update - path: spec.hostedCluster.platform.aws.multiArch goType: boolean operations: @@ -310,6 +320,11 @@ resources: operations: - create - update + - path: spec.nodePool.platform.aws.cpuOptions.nestedVirtualizationPolicy + goType: string + operations: + - create + - update - path: spec.nodePool.platform.aws.imageType goType: string operations: diff --git a/hack/api-codegen/go.mod b/hack/api-codegen/go.mod index 34cd101bc..093af219d 100644 --- a/hack/api-codegen/go.mod +++ b/hack/api-codegen/go.mod @@ -7,7 +7,7 @@ require ( github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 gopkg.in/yaml.v3 v3.0.1 k8s.io/apiextensions-apiserver v0.36.0 - k8s.io/apimachinery v0.36.0 + k8s.io/apimachinery v0.36.2 sigs.k8s.io/controller-tools v0.21.0 ) @@ -21,7 +21,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect - github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 // indirect + github.com/openshift/api v0.0.0-20260805160557-b61243060d5f // indirect github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect golang.org/x/mod v0.40.0 // indirect @@ -31,7 +31,7 @@ require ( golang.org/x/tools v0.49.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/api v0.36.0 // indirect + k8s.io/api v0.36.2 // indirect k8s.io/klog/v2 v2.140.0 // indirect k8s.io/kube-openapi v0.0.0-20260706235625-cdb1db5517a0 // indirect k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 // indirect @@ -39,3 +39,5 @@ require ( sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect ) + +replace github.com/openshift/hypershift/api => github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345 diff --git a/hack/api-codegen/go.sum b/hack/api-codegen/go.sum index 03fd7961a..2239e8151 100644 --- a/hack/api-codegen/go.sum +++ b/hack/api-codegen/go.sum @@ -88,10 +88,8 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.40.0 h1:Vtol0e1MghCD2ZVIilPDIg44XSL9l2QAn8ZNaljWcJc= github.com/onsi/gomega v1.40.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A= -github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 h1:r0S/yoZAI0iWo1JvoIijaIgWGWf/izg4WiV7Wrtz16k= -github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo= -github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 h1:QDSh3vkKYq7Fn9utYGlAJadkTdyaRl9IY7Cr6cNDAow= -github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16/go.mod h1:Z3lkj5pFqY+KTl3Do9gXdEZdKWLnkUTSDShLD1HE0CM= +github.com/openshift/api v0.0.0-20260805160557-b61243060d5f h1:NU7ltJhtFhqAJC+77DcNk6jmIpsJ3a+mebZIceiPW+U= +github.com/openshift/api v0.0.0-20260805160557-b61243060d5f/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -120,6 +118,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345 h1:4Hi+KoXlzdHAiKSMnGFF1yfvPFpkb08r0yO6SPlq4vQ= +github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345/go.mod h1:v7kWzwoisePl3ewusWeexcHlkO5MJNs+x9ORRPkqDC4= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= @@ -188,12 +188,12 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.36.0 h1:SgqDhZzHdOtMk40xVSvCXkP9ME0H05hPM3p9AB1kL80= -k8s.io/api v0.36.0/go.mod h1:m1LVrGPNYax5NBHdO+QuAedXyuzTt4RryI/qnmNvs34= +k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY= +k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg= k8s.io/apiextensions-apiserver v0.36.0 h1:Wt7E8J+VBCbj4FjiBfDTK/neXDDjyJVJc7xfuOHImZ0= k8s.io/apiextensions-apiserver v0.36.0/go.mod h1:kGDjH0msuiIB3tgsYRV0kS9GqpMYMUsQ3GHv7TApyug= -k8s.io/apimachinery v0.36.0 h1:jZyPzhd5Z+3h9vJLt0z9XdzW9VzNzWAUw+P1xZ9PXtQ= -k8s.io/apimachinery v0.36.0/go.mod h1:FklypaRJt6n5wUIwWXIP6GJlIpUizTgfo1T/As+Tyxc= +k8s.io/apimachinery v0.36.2 h1:0PE/W/WNy1UX61NLbXY5TMbJ6UwLL6E6lAPkYrKFxbQ= +k8s.io/apimachinery v0.36.2/go.mod h1:fvf/HOLXq9RId0rnDIbN1OEBvHXdQbLMM8nu0LcBUf4= k8s.io/apiserver v0.36.0 h1:Jg5OFAENUACByUCg15CmhZAYrr5ZyJ+jodyA1mHl3YE= k8s.io/apiserver v0.36.0/go.mod h1:mHvwdHf+qKEm+1/hYm756SV+oREOKSPnsjagOpx6Vho= k8s.io/client-go v0.36.0 h1:pOYi7C4RHChYjMiHpZSpSbIM6ZxVbRXBy7CuiIwqA3c= diff --git a/hyperfleet-operator/config/crd/bases/hyperfleet.io_clusters.yaml b/hyperfleet-operator/config/crd/bases/hyperfleet.io_clusters.yaml index c81c1d4ab..66a02ed83 100644 --- a/hyperfleet-operator/config/crd/bases/hyperfleet.io_clusters.yaml +++ b/hyperfleet-operator/config/crd/bases/hyperfleet.io_clusters.yaml @@ -556,41 +556,189 @@ spec: managing the lifecyle of the encryption keys outside of the control plane. This allows integration with an external provider to manage the data encryption keys securely. properties: - aws: + type: + description: |- + type defines the kind of platform for the KMS provider. + Allowed values are Vault. + When set to Vault, the plugin connects to a HashiCorp Vault server for key management. + enum: + - Vault + type: string + vault: description: |- - aws defines the key config for using an AWS KMS instance - for the encryption. The AWS KMS instance is managed + vault defines the configuration for the Vault KMS plugin. + The plugin connects to a Vault Enterprise server that is managed by the user outside the purview of the control plane. + This field must be set when type is Vault, and must be unset otherwise. properties: - keyARN: + authentication: + description: authentication defines the authentication method used to authenticate with Vault. + properties: + appRole: + description: |- + appRole defines the configuration for AppRole authentication. + This field must be set when type is AppRole, and must be unset otherwise. + properties: + secret: + description: |- + secret references a secret in the openshift-config namespace containing + the AppRole credentials used to authenticate with Vault. + The referenced Secret must contain two keys: "role-id" for the AppRole Role ID and "secret-id" for the AppRole Secret ID. + properties: + name: + description: |- + name is the metadata.name of the referenced secret in the openshift-config namespace. + The name must be a valid DNS subdomain name: it must contain no more than 253 characters, + contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character. + maxLength: 253 + minLength: 1 + type: string + required: + - name + type: object + required: + - secret + type: object + type: + description: |- + type defines the authentication method used to authenticate with Vault. + Allowed values are AppRole. + When set to AppRole, the plugin uses AppRole credentials to authenticate with Vault. + enum: + - AppRole + type: string + required: + - type + type: object + kmsPluginImage: description: |- - keyARN specifies the Amazon Resource Name (ARN) of the AWS KMS key used for encryption. - The value must adhere to the format `arn:aws:kms:::key/`, where: - - `` is the AWS region consisting of lowercase letters and hyphens followed by a number. - - `` is a 12-digit numeric identifier for the AWS account. - - `` is a unique identifier for the KMS key, consisting of lowercase hexadecimal characters and hyphens. - maxLength: 128 + kmsPluginImage specifies the container image for the HashiCorp Vault KMS plugin. + + The image must be a fully qualified OCI image pull spec with a SHA256 digest. + The format is: host[:port][/namespace]/name@sha256: + where the digest must be 64 characters long and consist only of lowercase hexadecimal characters, a-f and 0-9. + The total length must be between 75 and 447 characters. + + Short names (e.g., "vault-plugin" or "hashicorp/vault-plugin") are not allowed. + The registry hostname must be included and must contain at least one dot. + Image tags (e.g., ":latest", ":v1.0.0") are not allowed. + + Consult the OpenShift documentation for compatible plugin versions with your cluster version, + then obtain the image digest for that version from HashiCorp's container registry. + + For disconnected environments, mirror the plugin image to an accessible registry + and reference the mirrored location with its digest. + maxLength: 447 + minLength: 75 + type: string + tls: + description: |- + tls contains the TLS configuration for connecting to the Vault server. + When this field is not set, system default TLS settings are used. + minProperties: 1 + properties: + caBundle: + description: |- + caBundle references a ConfigMap in the openshift-config namespace containing + the CA certificate bundle used to verify the TLS connection to the Vault server. + The referenced ConfigMap must contain the CA bundle in the key "ca-bundle.crt". + When this field is not set, the system's trusted CA certificates are used. + + The namespace for the ConfigMap is openshift-config. + + Example ConfigMap: + apiVersion: v1 + kind: ConfigMap + metadata: + name: vault-ca-bundle + namespace: openshift-config + data: + ca-bundle.crt: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + properties: + name: + description: |- + name is the metadata.name of the referenced ConfigMap in the openshift-config namespace. + The name must be a valid DNS subdomain name: it must contain no more than 253 characters, + contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character. + maxLength: 253 + minLength: 1 + type: string + required: + - name + type: object + serverName: + description: |- + serverName specifies the Server Name Indication (SNI) to use when connecting to Vault via TLS. + This is useful when the Vault server's hostname doesn't match its TLS certificate. + When this field is not set, the hostname from vaultAddress is used for SNI. + + The value must be a valid DNS hostname: it must contain no more than 253 characters, + contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character. + maxLength: 253 + minLength: 1 + type: string + type: object + vaultAddress: + description: |- + vaultAddress specifies the address of the HashiCorp Vault instance. + The value must be a valid HTTPS URL containing only scheme, host, and optional port. + Paths, user info, query parameters, and fragments are not allowed. + + Format: https://hostname[:port] + Example: https://vault.example.com:8200 + + The value must be between 1 and 512 characters. + maxLength: 512 minLength: 1 type: string - region: + vaultAuthNamespace: + description: |- + vaultAuthNamespace specifies the Vault namespace to use for authentication. + This is only applicable for Vault Enterprise installations where authentication + and Transit operations may be in different namespaces. + When this field is not set, the value of vaultNamespace is used for both + authentication and Transit key operations. + + The value must be between 1 and 4096 characters. + The namespace cannot end with a forward slash, cannot contain spaces, and cannot be one of the reserved strings: root, sys, audit, auth, cubbyhole, or identity. + maxLength: 4096 + minLength: 1 + type: string + vaultKeyPath: + description: |- + vaultKeyPath specifies the full path to the encryption key in Vault's Transit secrets engine, + combining the Transit engine mount path and the key name separated by "/keys/". + Format: /keys/ (e.g., transit/keys/my-key, myteam/transit/keys/production-key). + + The total path length must be between 8 and 1542 characters. + The path cannot start or end with a forward slash, cannot contain consecutive forward slashes, + must only contain RFC 3986 unreserved characters (alphanumeric, hyphen, period, underscore, tilde) + and forward slashes as path separators, and must not contain "." or ".." path segments. + The key name must start and end with an alphanumeric character or underscore, and may contain + alphanumeric characters, underscores, hyphens, and periods in the middle. + maxLength: 1542 + minLength: 8 + type: string + vaultNamespace: description: |- - region specifies the AWS region where the KMS instance exists, and follows the format - `--`, e.g.: `us-east-1`. - Only lowercase letters and hyphens followed by numbers are allowed. - maxLength: 64 + vaultNamespace specifies the Vault namespace where the Transit secrets engine is mounted. + This is only applicable for Vault Enterprise installations. + When this field is not set, no namespace is used. + + The value must be between 1 and 4096 characters. + The namespace cannot end with a forward slash, cannot contain spaces, and cannot be one of the reserved strings: root, sys, audit, auth, cubbyhole, or identity. + maxLength: 4096 minLength: 1 type: string required: - - keyARN - - region + - authentication + - kmsPluginImage + - vaultAddress + - vaultKeyPath type: object - type: - description: |- - type defines the kind of platform for the KMS provider. - Available provider types are AWS only. - enum: - - AWS - type: string required: - type type: object @@ -698,8 +846,11 @@ spec: custom: description: |- custom is a user-defined TLS security profile. Be extremely careful using a custom - profile as invalid configurations can be catastrophic. An example custom profile - looks like this: + profile as invalid configurations can be catastrophic. + + The supported groups list for this profile is empty by default. + + An example custom profile looks like this: minTLSVersion: VersionTLS11 ciphers: @@ -724,6 +875,46 @@ spec: type: string type: array x-kubernetes-list-type: atomic + groups: + description: |- + groups is an optional, ordered field used to specify the supported groups (formerly known as + elliptic curves) that are used during the TLS handshake. The order of the groups represents + a suggested preference, with the most preferred group first. Note that not all platform + components honor the ordering: Go-based components use Go's internal preference order and + treat this list as a filter of allowed groups rather than an ordered preference. + Operators may remove entries their operands do not support. + + When omitted, this means no opinion and the platform is left to choose reasonable defaults which are + subject to change over time and may be different per platform component depending on the underlying TLS + libraries they use. If specified, the list must contain at least one and at most 7 groups, + and each group must be unique. + + For example, to use X25519 and secp256r1 (yaml): + + groups: + - X25519 + - secp256r1 + items: + description: |- + TLSGroup is a supported group identifier that can be used in TLSProfile.Groups. + There is a one-to-one mapping between these names and the group IDs defined + in Go's crypto/tls package based on IANA's "TLS Supported Groups" registry: + https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 + Note that X25519MLKEM768 is a post-quantum hybrid group that is not + FIPS-approved and should be ignored by components running in FIPS mode. + enum: + - X25519 + - secp256r1 + - secp384r1 + - secp521r1 + - X25519MLKEM768 + - SecP256r1MLKEM768 + - SecP384r1MLKEM1024 + type: string + maxItems: 7 + minItems: 1 + type: array + x-kubernetes-list-type: set minTLSVersion: description: |- minTLSVersion is used to specify the minimal version of the TLS protocol @@ -744,6 +935,10 @@ spec: legacy clients and want to remain highly secure while being compatible with most clients currently in use. + The supported groups list includes by default the following groups + in suggested preference order (ordering may not be honored by all implementations): + X25519MLKEM768, X25519, secp256r1, secp384r1. + This profile is equivalent to a Custom profile specified as: minTLSVersion: VersionTLS12 ciphers: @@ -762,7 +957,9 @@ spec: description: |- modern is a TLS security profile for use with clients that support TLS 1.3 and do not need backward compatibility for older clients. - + The supported groups list includes by default the following groups + in suggested preference order (ordering may not be honored by all implementations): + X25519MLKEM768, X25519, secp256r1, secp384r1. This profile is equivalent to a Custom profile specified as: minTLSVersion: VersionTLS13 ciphers: @@ -776,6 +973,10 @@ spec: old is a TLS profile for use when services need to be accessed by very old clients or libraries and should be used only as a last resort. + The supported groups list includes by default the following groups + in suggested preference order (ordering may not be honored by all implementations): + X25519MLKEM768, X25519, secp256r1, secp384r1. + This profile is equivalent to a Custom profile specified as: minTLSVersion: VersionTLS10 ciphers: @@ -792,11 +993,14 @@ spec: - ECDHE-RSA-AES128-SHA256 - ECDHE-ECDSA-AES128-SHA - ECDHE-RSA-AES128-SHA + - ECDHE-ECDSA-AES256-SHA384 + - ECDHE-RSA-AES256-SHA384 - ECDHE-ECDSA-AES256-SHA - ECDHE-RSA-AES256-SHA - AES128-GCM-SHA256 - AES256-GCM-SHA384 - AES128-SHA256 + - AES256-SHA256 - AES128-SHA - AES256-SHA - DES-CBC3-SHA @@ -807,10 +1011,16 @@ spec: type is one of Old, Intermediate, Modern or Custom. Custom provides the ability to specify individual TLS security profile parameters. - The profiles are based on version 5.7 of the Mozilla Server Side TLS - configuration guidelines. The cipher lists consist of the configuration's - "ciphersuites" followed by the Go-specific "ciphers" from the guidelines. - See: https://ssl-config.mozilla.org/guidelines/5.7.json + The cipher and groups lists in these profiles are based on version 5.8 of the + Mozilla Server Side TLS configuration guidelines. + See: https://ssl-config.mozilla.org/guidelines/5.8.json + + The groups are listed in suggested preference order, with the most preferred group first. + Note that not all platform components honor the ordering: Go-based components use Go's + internal preference order and treat this list as a filter of allowed groups rather than + an ordered preference. + Note that X25519MLKEM768 is a post-quantum hybrid group that is not + FIPS-approved and should be ignored by components running in FIPS mode. The profiles are intent based, so they may change over time as new ciphers are developed and existing ciphers are found to be insecure. Depending on @@ -827,6 +1037,8 @@ spec: description: |- authentication specifies cluster-wide settings for authentication (like OAuth and webhook token authenticators). + Note: the serviceAccountIssuer field within this configuration is ignored; the + HostedCluster's spec.issuerURL is always used as the service account issuer instead. properties: oauthMetadata: description: |- @@ -1143,6 +1355,359 @@ spec: type: object type: array x-kubernetes-list-type: atomic + externalClaimsSources: + description: |- + externalClaimsSources is an optional field that can be used to configure + sources, external to the token provided in a request, in which claims + should be fetched from and made available to the claim mapping process + that is used to build the identity of a token holder. + + For example, fetching additional user metadata from an OIDC provider's UserInfo endpoint. + + When not specified, only claims present in the token itself will be available + in the claim mapping process. + + When specified, at least one external claim source must be specified and no more than 5 + sources may be specified. + All external claim sources must have unique claim mappings. + When an external source responds and resolves additional claims successfully, they will + be made available as claims during the claim mapping process. + Externally sourced claims with the same name as a claim existing within the token will + overwrite the claim data from the token with the externally sourced information. + If an external source does not respond, responds with an error, or the additional + claim data cannot be resolved from the response successfully it will not be + included in the claim data passed to the claim mapping process. + items: + description: ExternalClaimsSource provides the configuration for a single external claim source. + properties: + authentication: + description: |- + authentication is an optional field that configures how the apiserver authenticates with an external claims source. + When not specified, anonymous authentication is used which means no 'Authorization' header + is sent in the HTTP request to fetch the external claims. + properties: + clientCredential: + description: |- + clientCredential configures the client credentials + and token endpoint to use to get an access token. + clientCredential is required when type is 'ClientCredential', and forbidden otherwise. + properties: + clientID: + description: |- + clientID is a required client identifier to use during the OAuth2 client credentials flow. + clientID must be at least 1 character in length, must not exceed 256 characters in length, + and must only contain printable ASCII characters. + maxLength: 256 + minLength: 1 + type: string + clientSecret: + description: |- + clientSecret is a required reference to a Secret in the openshift-config namespace to be used + as the client secret during the OAuth2 client credentials flow. + + The key 'client-secret' is used to locate the client secret data in the Secret. + properties: + name: + description: |- + name is the required name of the Secret that exists in the openshift-config namespace. + + It must be at least 1 character in length, must not exceed 253 characters in length, + must start and end with a lowercase alphanumeric character, and must only contain + lowercase alphanumeric characters, '-' or '.'. + maxLength: 253 + minLength: 1 + type: string + required: + - name + type: object + scopes: + description: |- + scopes is an optional list of OAuth2 scopes to request when obtaining + an access token. + + If not specified, the token endpoint's default scopes + will be used. + + When specified, there must be at least 1 entry and must not exceed 16 entries. + Each entry must be at least 1 character in length and must not exceed 256 characters in length. + Each entry must only contain printable ASCII characters, excluding spaces, double quotes and backslashes. + Entries must be unique. + items: + description: |- + OAuth2Scope is a string alias that represents an OAuth2 Scope as defined by https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.4 + Must be at least 1 character in length, must not exceed 256 characters in length and must only contain printable ASCII characters, excluding spaces, double quotes and backslashes. + maxLength: 256 + minLength: 1 + type: string + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-type: set + tls: + description: |- + tls is an optional field that allows configuring the TLS + settings used to interact with the identity provider + as an OAuth2 client. + + When omitted, system default TLS settings will be used + for the OAuth2 client. + properties: + certificateAuthority: + description: |- + certificateAuthority is a required reference to a ConfigMap in the openshift-config + namespace that contains the CA certificate to use to validate TLS connections with the external claims source. + The key "ca-bundle.crt" must be present in the referenced ConfigMap and must contain the CA certificate to be used + to verify the external source's TLS certificate. + properties: + name: + description: |- + name is the required name of the ConfigMap that exists in the openshift-config namespace. + The key "ca-bundle.crt" must be present and must contain the CA certificate to be used + to verify the external source's TLS certificate. + + It must be at least 1 character in length, must not exceed 253 characters in length, + must start and end with a lowercase alphanumeric character, and must only contain + lowercase alphanumeric characters, '-' or '.'. + maxLength: 253 + minLength: 1 + type: string + required: + - name + type: object + required: + - certificateAuthority + type: object + tokenEndpoint: + description: |- + tokenEndpoint is a required URL to query for an access token using + the client credential OAuth2 flow. + tokenEndpoint must be at least 1 character in length and must not exceed 2048 characters in length. + tokenEndpoint must be a valid HTTPS URL. + tokenEndpoint must have a host and a path. + tokenEndpoint must not contain query parameters, fragments, + or user information (e.g., "user:password@host"). + maxLength: 2048 + minLength: 1 + type: string + required: + - clientID + - clientSecret + - tokenEndpoint + type: object + type: + description: |- + type is a required field that sets the type of + authentication method used by the authenticator + when fetching external claims. + + Allowed values are 'RequestProvidedToken' and 'ClientCredential'. + + When set to 'RequestProvidedToken', the authenticator will + use the token provided to the kube-apiserver as part of the + request to authenticate with the external claims source. + + When set to 'ClientCredential', the authenticator will + use the configured client-id, client-secret, and token endpoint + to fetch an access token using the OAuth2 client credentials grant + flow. The fetched access token will then be used to authenticate + with the external claims source. + enum: + - RequestProvidedToken + - ClientCredential + type: string + required: + - type + type: object + mappings: + description: |- + mappings is a required list of the claim + and response handling expression pairs + that produces the claims from the external source. + mappings must have at least 1 entry and must not exceed 16 entries. + Entries must have a unique name across all external claim sources. + items: + description: |- + SourcedClaimMapping configures the mapping behavior for a single external claim + from the response the apiserver received from the external claim source. + properties: + expression: + description: |- + expression is a required CEL expression that + will produce a value to be assigned to the claim. + The full response body from the request to the + external claim source is provided via the + `response.body` variable. + + The contents of the `response.body` variable varies based on the response received + from the external source. It is the responsibility of those configuring + this expression to understand what is returned from the external source. + + expression must be at least 1 character and must not exceed 1024 characters in length. + maxLength: 1024 + minLength: 1 + type: string + name: + description: |- + name is a required name of the claim that + will be produced and made available during + the claim-to-identity mapping process. + name must consist of only lowercase alpha characters and underscores ('_'). + name must be at least 1 character and must not exceed 256 characters in length. + maxLength: 256 + minLength: 1 + type: string + required: + - expression + - name + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + predicates: + description: |- + predicates is an optional list of constraints in + which claims should attempt to be fetched from this + external source. + + When omitted, claims are always fetched + from this external source. + + When specified, all predicates must evaluate to 'true' + before claims are attempted to be fetched from this external source. + predicates must have at least 1 entry and must not exceed 16 entries. + Entries must have unique expressions. + items: + description: |- + ExternalSourcePredicate configures a singular condition + that must return true before the external source is queried + to retrieve external claims. + properties: + expression: + description: |- + expression is a required CEL expression that + is used to determine whether or not an external + source should be used to fetch external claims. + + The expression must return a boolean value, + where true means that the source should be consulted + and false means that it should not. + + Claims from the token used for the request to the kube-apiserver + are made available via the `claims` variable. + + The contents of the `claims` variable varies based on the claims that are + present in the token being validated. It is the responsibility of those configuring this + field to understand what claims the identity provider includes when issuing tokens. + + expression must be at least 1 character and must not exceed 1024 characters in length. + maxLength: 1024 + minLength: 1 + type: string + required: + - expression + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - expression + x-kubernetes-list-type: map + tls: + description: |- + tls is an optional field that configures the http client TLS + settings when fetching external claims from this source. + + When omitted, system default TLS settings will be used + for fetching claims from the external source. + properties: + certificateAuthority: + description: |- + certificateAuthority is a required reference to a ConfigMap in the openshift-config + namespace that contains the CA certificate to use to validate TLS connections with the external claims source. + The key "ca-bundle.crt" must be present in the referenced ConfigMap and must contain the CA certificate to be used + to verify the external source's TLS certificate. + properties: + name: + description: |- + name is the required name of the ConfigMap that exists in the openshift-config namespace. + The key "ca-bundle.crt" must be present and must contain the CA certificate to be used + to verify the external source's TLS certificate. + + It must be at least 1 character in length, must not exceed 253 characters in length, + must start and end with a lowercase alphanumeric character, and must only contain + lowercase alphanumeric characters, '-' or '.'. + maxLength: 253 + minLength: 1 + type: string + required: + - name + type: object + required: + - certificateAuthority + type: object + url: + description: |- + url is a required configuration of the URL + for which the external claims are located. + properties: + hostname: + description: |- + hostname is a required hostname for which the external claims are located. + + It must be a valid DNS subdomain name as per RFC1123. + + This means that it must start and end with a lowercase alphanumeric character, + must only consist of lowercase alphanumeric characters, '-', and '.'. + hostname may optionally specify a port in the format ':{port}'. + If a port is specified it must not exceed 65535. + + hostname must be at least 1 character in length. + When specifying a port, hostname must not exceed 259 characters in length. + When not specifying a port, hostname must not exceed 253 characters in length. + maxLength: 259 + minLength: 1 + type: string + pathExpression: + description: |- + pathExpression is a required CEL expression that returns a list + of string values used to construct the URL path. + Claims from the token used for the request to the kube-apiserver + are made available via the `claims` variable. + expression must be at least 1 character in length and must not exceed 1024 characters in length. + + Values in the returned list will be joined with the hostname using a forward slash + (`/`) as a separator. Values in the returned list do not need to include the forward slash. + If a forward slash is included in a returned value, it will be encoded as `%2F`. + + Example of a static path configuration: + + pathExpression: ['realms', 'k8s', 'protocol', 'openid-connect', 'userinfo'] + + The above example would resolve to the path: '/realms/k8s/protocol/openid-connect/userinfo' + + Example of a dynamic path configuration: + + pathExpression: "['admin', 'realms', 'k8s', 'users'] + [claims.sub] + ['groups']" + + Assuming 'claims.sub' is set to '12345', the above example would resolve to the path: '/admin/realms/k8s/users/12345/groups' + maxLength: 1024 + minLength: 1 + type: string + required: + - hostname + - pathExpression + type: object + required: + - mappings + - url + type: object + maxItems: 5 + minItems: 1 + type: array + x-kubernetes-list-type: atomic issuer: description: issuer is a required field that configures how the platform interacts with the identity provider and how tokens issued from the identity provider are evaluated by the Kubernetes API server. properties: @@ -1532,19 +2097,37 @@ spec: allowedRegistries: description: |- allowedRegistries are the only registries permitted for image pull and push actions. All other registries are denied. + Each entry must be a valid registry scope in the format hostname[:port][/path], + optionally prefixed with "*." for wildcard subdomains (e.g., "*.example.com"). + The hostname must consist of valid DNS labels separated by dots, where each label + contains only alphanumeric characters and hyphens and does not start or end with a hyphen. + Entries must not be empty, must not include tags (e.g., ":latest") or digests (e.g., "@sha256:..."), + and must be at most 256 characters in length. The list may contain at most 1024 entries. Only one of BlockedRegistries or AllowedRegistries may be set. items: + maxLength: 256 + minLength: 1 type: string + maxItems: 1024 type: array x-kubernetes-list-type: atomic blockedRegistries: description: |- blockedRegistries cannot be used for image pull and push actions. All other registries are permitted. + Each entry must be a valid registry scope in the format hostname[:port][/path], + optionally prefixed with "*." for wildcard subdomains (e.g., "*.example.com"). + The hostname must consist of valid DNS labels separated by dots, where each label + contains only alphanumeric characters and hyphens and does not start or end with a hyphen. + Entries must not be empty, must not include tags (e.g., ":latest") or digests (e.g., "@sha256:..."), + and must be at most 256 characters in length. The list may contain at most 1024 entries. Only one of BlockedRegistries or AllowedRegistries may be set. items: + maxLength: 256 + minLength: 1 type: string + maxItems: 1024 type: array x-kubernetes-list-type: atomic containerRuntimeSearchRegistries: @@ -1559,9 +2142,19 @@ spec: type: array x-kubernetes-list-type: set insecureRegistries: - description: insecureRegistries are registries which do not have a valid TLS certificates or only support HTTP connections. + description: |- + insecureRegistries are registries which do not have a valid TLS certificates or only support HTTP connections. + Each entry must be a valid registry scope in the format hostname[:port][/path], + optionally prefixed with "*." for wildcard subdomains (e.g., "*.example.com"). + The hostname must consist of valid DNS labels separated by dots, where each label + contains only alphanumeric characters and hyphens and does not start or end with a hyphen. + Entries must not be empty, must not include tags (e.g., ":latest") or digests (e.g., "@sha256:..."), + and must be at most 256 characters in length. The list may contain at most 1024 entries. items: + maxLength: 256 + minLength: 1 type: string + maxItems: 1024 type: array x-kubernetes-list-type: atomic type: object @@ -1591,6 +2184,7 @@ spec: To determine the set of configurable Routes, look at namespace and name of entries in the .status.componentRoutes list, where participating operators write the status of configurable routes. + A maximum of 250 component routes may be configured. items: description: ComponentRouteSpec allows for configuration of a route's hostname and serving certificate. properties: @@ -1598,6 +2192,38 @@ spec: description: hostname is the hostname that should be used by the route. pattern: ^([a-zA-Z0-9\p{S}\p{L}]((-?[a-zA-Z0-9\p{S}\p{L}]{0,62})?)|([a-zA-Z0-9\p{S}\p{L}](([a-zA-Z0-9-\p{S}\p{L}]{0,61}[a-zA-Z0-9\p{S}\p{L}])?)(\.)){1,}([a-zA-Z\p{L}]){2,63})$|^(([a-z0-9][-a-z0-9]{0,61}[a-z0-9]|[a-z0-9]{1,63})[\.]){0,}([a-z0-9][-a-z0-9]{0,61}[a-z0-9]|[a-z0-9]{1,63})$ type: string + labels: + additionalProperties: + description: |- + LabelValue is the value part of a Kubernetes label. + A label value must be either empty or 1-63 characters, consisting of + alphanumeric characters, '-', '_', or '.', starting and ending with + an alphanumeric character. + maxLength: 63 + minLength: 0 + type: string + description: |- + 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. + When specified, labels must contain at least one entry, up to a maximum of 8. + Label keys must be valid qualified names, consisting of a name segment and + an optional prefix separated by a slash (/). The name segment must be at most + 63 characters in length and must consist only of alphanumeric characters, + dashes (-), underscores (_), and dots (.), and must start and end with + alphanumeric characters. The prefix, if specified, must be a DNS subdomain: + at most 253 characters in length, consisting of dot-separated segments where + each segment starts and ends with an alphanumeric character. + Label values must be either empty or 1-63 characters, consisting of + alphanumeric characters, dashes (-), underscores (_), or dots (.), + starting and ending with an alphanumeric character. + Keys with the "kubernetes.io/", "k8s.io/", and "openshift.io/" prefixes are reserved and may not be used. + maxProperties: 8 + minProperties: 1 + type: object + x-kubernetes-map-type: granular name: description: |- name is the logical name of the route to customize. @@ -1635,6 +2261,7 @@ spec: - name - namespace type: object + maxItems: 250 type: array x-kubernetes-list-map-keys: - namespace @@ -2073,6 +2700,28 @@ spec: x-kubernetes-list-type: atomic type: object type: object + networkObservability: + description: |- + networkObservability is an optional field that configures network observability installation + during cluster deployment (day-0). + When omitted, unless this is a SNO cluster, network observability will be installed if not already present, after that, no action taken. + properties: + installationPolicy: + description: |- + installationPolicy controls whether network observability is installed during cluster deployment. + Valid values are "InstallAndEnable" and "NoAction". + When set to "InstallAndEnable", ensure that network observability will be installed and enabled on the cluster. If already installed, no action taken, but if it gets uninstalled, it will install it again. + When set to "NoAction", nothing will be done regarding Network observability. + During the installation of NetworkObservability, the platform checks for any existing manual installations. + If a successful installation using the OLMv0 or OLMv1 API is detected, it will be used. + If the platform cannot determine how the current version was installed, or if the existing installation is incomplete, the installation process will stop. + enum: + - InstallAndEnable + - NoAction + type: string + required: + - installationPolicy + type: object networkType: description: |- networkType is the plugin that is to be deployed (e.g. OVNKubernetes). @@ -2990,9 +3639,10 @@ spec: properties: encryptionKeyURL: description: |- - encryptionKeyURL is the URL of the Azure Key Vault key to use for encrypting etcd backup artifacts. - Must be a valid Azure Key Vault key URL in the format - "https://.vault.azure.net/keys/[/]". + encryptionKeyURL is the URL of the Azure Key Vault or Managed HSM key to use for encrypting etcd backup artifacts. + Key Vault URLs are supported in Azure Public Cloud (vault.azure.net), Azure US Government Cloud (vault.usgovcloudapi.net), Azure China Cloud (vault.azure.cn), Azure German Cloud (vault.microsoftazure.de), and Azure Bleu Cloud (vault.sovcloud-api.fr). + Managed HSM URLs are supported in Azure Public Cloud (managedhsm.azure.net), Azure US Government Cloud (managedhsm.usgovcloudapi.net), Azure China Cloud (managedhsm.azure.cn), Azure German Cloud (managedhsm.microsoftazure.de), and Azure Bleu Cloud (managedhsm.sovcloud-api.fr). + Supporting another cloud requires adding its DNS suffix to this validation and the Azure endpoint resolver. maxLength: 210 minLength: 1 type: string @@ -3010,6 +3660,291 @@ spec: required: - platform type: object + scheduling: + description: scheduling specifies scheduling constraints for the default etcd shard pods. + minProperties: 1 + properties: + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector constrains this shard's pods to nodes matching the + specified labels, in addition to the framework's control plane node + selector. Keys and values must be valid Kubernetes label key/value + pairs. Maximum 16 entries. + maxProperties: 16 + minProperties: 1 + type: object + tolerations: + description: |- + tolerations allows this shard's pods to schedule on nodes with + matching taints, in addition to the framework's control plane + tolerations. Maximum 16 entries. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + type: object + shards: + description: |- + shards defines additional etcd shards for resource-level routing. + The existing storage and scheduling fields above configure + the default shard (catch-all for all resources not explicitly + routed). Entries in this list define non-default shards, + each deployed as an independent StatefulSet and ControlPlaneComponent. + Minimum 1, maximum 10 entries. Resources must not overlap across + shards. Immutable after creation: shards cannot be added, removed, + or reordered. + + WARNING: In the current TechPreview implementation, shard data is NOT + included in HCPEtcdBackup. Resources routed to shards will not be + backed up. This will be addressed before promotion beyond TechPreview. + items: + description: |- + ManagedEtcdShardSpec defines the configuration for a single etcd shard + within a managed etcd deployment. + properties: + name: + description: |- + name is a unique identifier for this shard. It is used to derive + resource names (e.g., StatefulSet "etcd-{name}", Service + "etcd-client-{name}"). + Must be a valid DNS1123 label (lowercase alphanumeric with hyphens, + starting and ending with an alphanumeric character), max 48 characters. + Immutable once set. + maxLength: 48 + minLength: 1 + type: string + replicas: + description: |- + replicas is the number of etcd replicas for this shard. Must be 1 or 3. + Immutable once set. + enum: + - 1 + - 3 + format: int32 + minimum: 1 + type: integer + resources: + description: |- + resources is the list of Kubernetes resource types routed to this + shard. Each entry identifies a resource by its API group and plural + resource name. For example, events in the core group would be + {apiGroup: "", resource: "events"}, and leases in the coordination group would be + {apiGroup: "coordination.k8s.io", resource: "leases"}. + Only resource types built into the kube-apiserver are routed; entries + for CRD-backed or aggregated API resources have no effect (see + EtcdShardResource). + Minimum 1, maximum 20 entries. Immutable once set. + items: + description: |- + EtcdShardResource identifies a Kubernetes resource type to be routed to an + etcd shard. It is used to build the KAS --etcd-servers-overrides flag. + The combination of apiGroup and resource uniquely identifies a resource type. + + Routing only takes effect for resource types compiled into the + kube-apiserver binary (built-in types such as events, pods, or + coordination.k8s.io/leases). This is a kube-apiserver limitation: + --etcd-servers-overrides does not apply to other resource types. In + particular, resources backed by CustomResourceDefinitions and resources + served by aggregated API servers (such as the openshift.io groups served + by openshift-apiserver and oauth-apiserver) are NOT routed: entries for + such resources are accepted but have no effect, and their data remains in + the default shard while the configured shard stays empty. + properties: + apiGroup: + description: |- + apiGroup is the API group of the resource (e.g., "coordination.k8s.io" + for leases). An empty string designates the core API group (e.g., + events, pods, configmaps). For core-group resources, specify + apiGroup: "" explicitly (e.g., {apiGroup: "", resource: "events"}). + When non-empty, must be at most 253 characters in length and consist + of only lowercase alphanumeric characters, hyphens and periods. Each + period separated segment must start and end with an alphanumeric + character. + maxLength: 253 + minLength: 0 + type: string + resource: + description: |- + resource is the plural resource name (e.g., "events", "leases", + "configmaps"). Must be a valid DNS label (RFC 1123): lowercase + alphanumeric characters or hyphens, starting and ending with an + alphanumeric character, max 63 characters. + maxLength: 63 + minLength: 1 + type: string + required: + - apiGroup + - resource + type: object + maxItems: 20 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - apiGroup + - resource + x-kubernetes-list-type: map + scheduling: + description: |- + scheduling configures per-shard pod placement constraints. These + constraints are merged with the framework's control plane node + isolation settings (nodeSelector, tolerations, topology spread). + minProperties: 1 + properties: + nodeSelector: + additionalProperties: + type: string + description: |- + nodeSelector constrains this shard's pods to nodes matching the + specified labels, in addition to the framework's control plane node + selector. Keys and values must be valid Kubernetes label key/value + pairs. Maximum 16 entries. + maxProperties: 16 + minProperties: 1 + type: object + tolerations: + description: |- + tolerations allows this shard's pods to schedule on nodes with + matching taints, in addition to the framework's control plane + tolerations. Maximum 16 entries. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + type: object + storage: + description: |- + storage configures the storage backend for this shard. + If not specified, the shard inherits PersistentVolume storage from + the parent ManagedEtcdSpec.Storage. Immutable once set. + properties: + persistentVolume: + description: |- + persistentVolume configures PVC-based storage for this shard. + Only valid when type is PersistentVolume. + When omitted and type is PersistentVolume, the shard inherits the + StorageClass and volume size from the parent + spec.etcd.managed.storage.persistentVolume configuration. + minProperties: 1 + properties: + storageClassName: + description: |- + storageClassName overrides the StorageClass for this shard's PVCs. + If not specified, the parent ManagedEtcdSpec's storageClassName is used. + Must be a valid DNS1123 subdomain (lowercase alphanumeric, hyphens, or + dots, starting and ending with an alphanumeric character), max 253 + characters. + maxLength: 253 + minLength: 1 + type: string + type: object + type: + description: |- + type is the kind of storage backend to use for this shard. + Valid values are PersistentVolume and EmptyDir. + When set to PersistentVolume, a PersistentVolumeClaim is created for + each etcd replica via the StatefulSet volumeClaimTemplates. The + optional persistentVolume field can override the StorageClass for + this shard; when persistentVolume is omitted, the shard inherits + the StorageClass and size from the parent spec.etcd.managed.storage + configuration. + When set to EmptyDir, the shard uses memory-backed ephemeral + storage (tmpfs). Data is lost when the pod restarts. This is + suitable for shards holding expendable, high-churn data such as + events or leases. + enum: + - PersistentVolume + - EmptyDir + type: string + required: + - type + type: object + required: + - name + - replicas + - resources + type: object + maxItems: 10 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map storage: description: storage specifies how etcd data is persisted. properties: @@ -3088,6 +4023,109 @@ spec: maxLength: 255 pattern: ^https:// type: string + shards: + description: |- + shards defines additional etcd shards for resource-level routing. + The top-level endpoint and tls fields define the default shard + (the catch-all for all resources not explicitly routed). Entries + in this list define non-default shards, each with its own endpoint + and TLS configuration. + Minimum 1, maximum 10 entries. Resources must not overlap across + shards. Immutable after creation: shards cannot be added, removed, + or reordered. + items: + description: |- + UnmanagedEtcdShardSpec defines the configuration for a single etcd shard + within an unmanaged (externally operated) etcd deployment. + properties: + endpoint: + description: |- + endpoint is the full etcd client endpoint URL for this shard. + Must be a valid HTTPS URL, max 267 characters. Immutable once set. + All shards must share the same CA and client certificate as the + top-level UnmanagedEtcdSpec.TLS, because kube-apiserver uses a + single --etcd-cafile/--etcd-certfile/--etcd-keyfile for all etcd + connections; --etcd-servers-overrides only overrides server URLs. + maxLength: 267 + minLength: 1 + type: string + name: + description: |- + name is a unique identifier for this shard. + Must be a valid DNS1123 label (lowercase alphanumeric with hyphens, + starting and ending with an alphanumeric character), max 48 characters. + Immutable once set. + maxLength: 48 + minLength: 1 + type: string + resources: + description: |- + resources is the list of Kubernetes resource types routed to this + shard. Uses the same format as ManagedEtcdShardSpec.Resources. + Only resource types built into the kube-apiserver are routed; entries + for CRD-backed or aggregated API resources have no effect (see + EtcdShardResource). + Minimum 1, maximum 20 entries. Immutable once set. + items: + description: |- + EtcdShardResource identifies a Kubernetes resource type to be routed to an + etcd shard. It is used to build the KAS --etcd-servers-overrides flag. + The combination of apiGroup and resource uniquely identifies a resource type. + + Routing only takes effect for resource types compiled into the + kube-apiserver binary (built-in types such as events, pods, or + coordination.k8s.io/leases). This is a kube-apiserver limitation: + --etcd-servers-overrides does not apply to other resource types. In + particular, resources backed by CustomResourceDefinitions and resources + served by aggregated API servers (such as the openshift.io groups served + by openshift-apiserver and oauth-apiserver) are NOT routed: entries for + such resources are accepted but have no effect, and their data remains in + the default shard while the configured shard stays empty. + properties: + apiGroup: + description: |- + apiGroup is the API group of the resource (e.g., "coordination.k8s.io" + for leases). An empty string designates the core API group (e.g., + events, pods, configmaps). For core-group resources, specify + apiGroup: "" explicitly (e.g., {apiGroup: "", resource: "events"}). + When non-empty, must be at most 253 characters in length and consist + of only lowercase alphanumeric characters, hyphens and periods. Each + period separated segment must start and end with an alphanumeric + character. + maxLength: 253 + minLength: 0 + type: string + resource: + description: |- + resource is the plural resource name (e.g., "events", "leases", + "configmaps"). Must be a valid DNS label (RFC 1123): lowercase + alphanumeric characters or hyphens, starting and ending with an + alphanumeric character, max 63 characters. + maxLength: 63 + minLength: 1 + type: string + required: + - apiGroup + - resource + type: object + maxItems: 20 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - apiGroup + - resource + x-kubernetes-list-type: map + required: + - endpoint + - name + - resources + type: object + maxItems: 10 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map tls: description: tls specifies TLS configuration for HTTPS etcd client endpoints. properties: @@ -3442,6 +4480,51 @@ spec: maximum: 9216 minimum: 576 type: integer + v4InternalSubnet: + description: |- + v4InternalSubnet configures the IPv4 subnet used by OVN-Kubernetes for gateway + router logical router port (LRP) addresses and masquerade/SNAT traffic within + the OVN logical topology. It must not overlap with any other subnet being used + by OpenShift or by the node network. The size of the subnet must be larger than + the number of nodes. + This field is distinct from ipv4.internalJoinSubnet, which configures the subnet + for the join switch that interconnects per-node gateway routers with the cluster + router. Both default to 100.64.0.0/16 but control different OVN-Kubernetes + internal networks and can be configured independently to avoid overlaps with + existing network infrastructure. + Once set, the value is immutable and cannot be modified in subsequent updates. + The default is 100.64.0.0/16. + The value must be in IPv4 CIDR notation (e.g., 192.168.0.0/16), consisting of + four decimal octets (0-255) separated by dots, followed by a slash and a prefix + length. The prefix length must be between 0 and 30 inclusive, and the first + octet must not be 0. + The value must be between 9 and 18 characters in length. + This field is immutable once set. + maxLength: 18 + minLength: 9 + type: string + v6InternalSubnet: + description: |- + v6InternalSubnet configures the IPv6 subnet used by OVN-Kubernetes for gateway + router logical router port (LRP) addresses and masquerade/SNAT traffic within + the OVN logical topology. It must not overlap with any other subnet being used + by OpenShift or by the node network. The size of the subnet must be larger than + the number of nodes. + This field is distinct from ipv6.internalJoinSubnet, which configures the subnet + for the join switch that interconnects per-node gateway routers with the cluster + router. Both default to fd98::/64 but control different OVN-Kubernetes internal + networks and can be configured independently to avoid overlaps with existing + network infrastructure. + Once set, the value is immutable and cannot be modified in subsequent updates. + The default is fd98::/64. + The value must be in IPv6 CIDR notation (e.g., fd98::/64), consisting of an + IPv6 address followed by a slash and a prefix length. The prefix length must + be between 0 and 125 inclusive. + The value must be between 4 and 48 characters in length. + This field is immutable once set. + maxLength: 48 + minLength: 4 + type: string type: object type: object clusterVersionOperator: @@ -3456,7 +4539,38 @@ spec: Valid values are: "Normal", "Debug", "Trace", "TraceAll". Defaults to "Normal". enum: - - "" + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + etcd: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + etcd configures the etcd component. + Setting the logLevel field triggers a rolling restart of the component. + Note: etcd supports fewer log levels than klog-based components, + etcd supports only Normal and Debug log levels. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: - Normal - Debug - Trace @@ -3468,6 +4582,44 @@ spec: ingressOperator specifies the configuration for the Ingress Operator in the hosted cluster. This allows configuring how the default ingress controller endpoints are published. properties: + defaultCertificate: + description: |- + defaultCertificate is a reference to a secret in the HostedCluster namespace + that contains the default certificate served by the default ingress controller. + When Routes don't specify their own certificate, defaultCertificate is used. + + The secret must contain the following keys and data: + tls.crt: certificate file contents + tls.key: key file contents + + When set, this certificate replaces the auto-generated wildcard certificate + that is normally created by the control plane operator. The secret is synced + from the HostedCluster namespace to the control plane, and then propagated + to the hosted cluster's openshift-ingress namespace. + + When the referenced secret is updated, the new certificate data is + automatically propagated to the hosted cluster. + + When not set, the control plane operator generates a wildcard certificate + signed by the cluster's root CA. + + Note: a cluster-admin in the hosted cluster can override the default ingress + controller's certificate directly. That override takes precedence and the + certificate referenced here is no longer served. + properties: + name: + description: |- + name is the name of the Secret containing tls.crt and tls.key. + The Secret must exist in the same namespace as the HostedCluster. + name must be a valid DNS subdomain name (RFC 1123): it must contain only + lowercase alphanumeric characters, '-' or '.', and start and end with an + alphanumeric character. + maxLength: 253 + minLength: 1 + type: string + required: + - name + type: object endpointPublishingStrategy: description: |- endpointPublishingStrategy is used to publish the default ingress controller endpoints. @@ -3722,6 +4874,38 @@ spec: maxItems: 10 type: array x-kubernetes-list-type: atomic + protocol: + description: |- + protocol specifies whether the Network Load Balancer uses PROXY + protocol to forward connections to the IngressController. + + When set to "TCP", the NLB uses AWS's native client IP preservation. + This may cause hairpin connection failures for internal load + balancers when connections are made from pods to router pods on + the same node. + + When set to "PROXY", the NLB disables native client IP preservation + and uses PROXY protocol v2. The IngressController enables PROXY + protocol on HAProxy so that it can parse PROXY protocol headers to + obtain the original client IP. This avoids hairpin connection + failures. + + The following values are valid for this field: + + * "TCP". + * "PROXY". + + When omitted, this means the user has no opinion and the value is + left to the platform to choose a reasonable default, which is subject to + change over time. The current default is "PROXY". + + Note that changing this field may cause brief connection failures + during the transition as the NLB attribute change and router rollout + occur independently. + enum: + - TCP + - PROXY + type: string subnets: description: |- subnets specifies the subnets to which the load balancer will @@ -4042,6 +5226,216 @@ spec: type: object x-kubernetes-preserve-unknown-fields: true type: object + kubeAPIServer: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + kubeAPIServer configures the kube-apiserver component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + kubeControllerManager: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + kubeControllerManager configures the kube-controller-manager component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + kubeScheduler: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + kubeScheduler configures the kube-scheduler component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + oauthServer: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + oauthServer configures the oauth-server component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + openShiftAPIServer: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + openShiftAPIServer configures the openshift-apiserver component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + openShiftControllerManager: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + openShiftControllerManager configures the openshift-controller-manager component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object + openShiftOAuthAPIServer: + allOf: + - minProperties: 1 + - minProperties: 1 + description: |- + openShiftOAuthAPIServer configures the openshift-oauth-apiserver component. + Setting the logLevel field triggers a rolling restart of the component. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + properties: + logLevel: + description: |- + logLevel sets the log verbosity for the component. + Valid values are: "Normal", "Debug", "Trace", "TraceAll". + When set to Normal, standard operational log messages are produced for auditing and common operations. + When set to Debug, more verbose logging is enabled for diagnosing problems. + When set to Trace, very verbose logging is enabled including function-level tracing. + When set to TraceAll, the most verbose logging is used, including full API body content, + this can cause significant performance impact and produce large volumes of logs. + When omitted, this means the user has no opinion and the platform + chooses a reasonable default, which is subject to change over time. + The current default log level is Normal. + enum: + - Normal + - Debug + - Trace + - TraceAll + type: string + type: object type: object pausedUntil: description: pausedUntil is a field that can be used to pause reconciliation on the HostedCluster controller, resulting in any change to the HostedCluster being ignored. @@ -4137,6 +5531,46 @@ spec: - PublicAndPrivate - Private type: string + managedDNS: + description: |- + managedDNS configures CPO-managed Route53 DNS zones for this cluster. + An empty object ({}) enables managed DNS with all defaults. + minProperties: 0 + properties: + delegation: + description: |- + delegation configures service-side DNS delegation for certificate generation. + When set, the CPO creates an ACME DNS01 challenge CNAME in the public ingress + zone and handles NS delegation based on the nsDelegation mode. + When absent, only zones are created and the consuming platform handles + delegation and certificate management. + properties: + nsDelegation: + description: |- + nsDelegation specifies how NS delegation records are created in the parent zone. + "ExternalDNS": the CPO creates a DNSEndpoint CR in the control plane namespace; + external-dns creates NS records in the parent zone. + "Manual": the consuming platform handles NS delegation using nameservers + reported in HostedCluster status. + enum: + - ExternalDNS + - Manual + type: string + required: + - nsDelegation + type: object + ingressDomainPrefix: + default: in + description: |- + ingressDomainPrefix is the subdomain prefix for ingress DNS zones. + Zones are created as {prefix}.{baseDomainPrefix}.{baseDomain}. + When delegation is configured, the prefix creates a DNS delegation boundary + that separates the ingress zone from the cluster domain, enabling ACME + challenge CNAME delegation back to the parent zone. + maxLength: 63 + minLength: 1 + type: string + type: object multiArch: default: false description: |- @@ -4165,26 +5599,49 @@ spec: Changes to this field will be propagated in-place to AWS resources (VPC Endpoints, EC2 instances, initial EBS volumes and default/endpoint security groups). These tags will be propagated to the infrastructure CR in the guest cluster, where other OCP operators might choose to honor this input to reconcile AWS resources created by them. Please consult the official documentation for a list of all AWS resources that support in-place tag updates. + For NodePool-created resources (EC2 instances and their initial EBS volumes), these will be merged with NodePool-scoped tags. + By default, HostedCluster tags take precedence over NodePool tags when both specify the same key. + To allow a NodePool tag to override a specific HostedCluster tag, set overridePolicy to "Allow" on that tag. + Cluster-scoped resources (VPC endpoints, security groups) only receive HostedCluster tags. These take precedence over tags defined out of band (i.e., tags added manually or by other tools outside of HyperShift) in AWS in case of conflicts. items: - description: AWSResourceTag is a tag to apply to AWS resources created for the cluster. + description: |- + AWSClusterResourceTag is a tag to apply to AWS resources created for a + HostedCluster. It extends the base tag with an overridePolicy field that + controls whether NodePool-level tags can override this tag. properties: key: - description: key is the key of the tag. + description: |- + key is the key of the tag. + Must be between 1 and 128 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ maxLength: 128 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ + type: string + overridePolicy: + description: |- + overridePolicy controls whether a NodePool-level tag with the same key can + override this HostedCluster-level tag. + + When set to "Allow", a NodePool tag with the same key will take precedence + over this HostedCluster tag. When set to "Deny" or omitted, the + HostedCluster value is preserved and the NodePool tag is ignored for that + key. + enum: + - Allow + - Deny type: string value: description: |- value is the value of the tag. + Must be between 1 and 256 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ Some AWS service do not support empty values. Since tags are added to resources in many services, the length of the tag value must meet the requirements of all services. maxLength: 256 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ type: string required: - key @@ -4979,12 +6436,13 @@ spec: type: object cloud: default: AzurePublicCloud - description: 'cloud is the cloud environment identifier, valid values could be found here: https://github.com/Azure/go-autorest/blob/4c0e21ca2bbb3251fe7853e6f9df6397f53dd419/autorest/azure/environments.go#L33' + description: cloud is the Azure cloud environment identifier. enum: - AzurePublicCloud - AzureUSGovernmentCloud - AzureChinaCloud - AzureGermanCloud + - AzureBleuCloud - AzureStackCloud type: string containerRegistry: @@ -5295,7 +6753,8 @@ spec: - Contain only lowercase letters, digits, underscores, or hyphens - End with a lowercase letter or digit (not a hyphen or underscore) - Be 1-63 characters long - GCP reserves the 'goog' prefix for system labels. + GCP reserves the 'goog' prefix for system labels, with the exception of + 'goog-partner-solution' which Google requires for partner attribution tracking. See https://cloud.google.com/compute/docs/labeling-resources for Compute Engine label requirements. maxLength: 63 minLength: 1 @@ -6562,14 +8021,14 @@ spec: description: activeKey defines the active key used to encrypt new secrets properties: keyName: - description: keyName is the name of the keyvault key used for encrypt/decrypt + description: keyName is the name of the key used for encrypt/decrypt. maxLength: 255 minLength: 1 type: string keyVaultName: description: |- - keyVaultName is the name of the keyvault. Must match criteria specified at https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates#vault-name-and-object-name - Your Microsoft Entra application used to create the cluster must be authorized to access this keyvault, e.g using the AzureCLI: + keyVaultName is the name of the Key Vault or Managed HSM. Must match criteria specified at https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates#vault-name-and-object-name + Your Microsoft Entra application used to create the cluster must be authorized to access this resource, e.g using the AzureCLI: `az keyvault set-policy -n $KEYVAULT_NAME --key-permissions decrypt encrypt --spn ` maxLength: 255 minLength: 1 @@ -6593,14 +8052,14 @@ spec: The system automatically manages the previous key via the status field. properties: keyName: - description: keyName is the name of the keyvault key used for encrypt/decrypt + description: keyName is the name of the key used for encrypt/decrypt. maxLength: 255 minLength: 1 type: string keyVaultName: description: |- - keyVaultName is the name of the keyvault. Must match criteria specified at https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates#vault-name-and-object-name - Your Microsoft Entra application used to create the cluster must be authorized to access this keyvault, e.g using the AzureCLI: + keyVaultName is the name of the Key Vault or Managed HSM. Must match criteria specified at https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates#vault-name-and-object-name + Your Microsoft Entra application used to create the cluster must be authorized to access this resource, e.g using the AzureCLI: `az keyvault set-policy -n $KEYVAULT_NAME --key-permissions decrypt encrypt --spn ` maxLength: 255 minLength: 1 @@ -6626,6 +8085,18 @@ spec: - Private - "" type: string + keyVaultType: + description: |- + keyVaultType specifies whether activeKey and backupKey are hosted by Azure Key Vault or Azure Managed HSM. + Valid values are "KeyVault" and "ManagedHSM". + When set to "KeyVault", both keys are hosted by Azure Key Vault. + When set to "ManagedHSM", both keys are hosted by Azure Managed HSM. + The type is immutable; key rotation must remain within the same service. + When omitted, the keys are treated as Key Vault keys. + enum: + - KeyVault + - ManagedHSM + type: string kms: description: |- kms is a pre-existing managed identity used to authenticate with Azure KMS. @@ -7004,7 +8475,7 @@ spec: conditions: description: |- Conditions represent the latest observations of the cluster's state. - Known condition types: Synced, Available, Degraded, ControlPlaneUpgradeState. + Known condition types: Synced, Available, Degraded, ControlPlaneUpgradeState, AWSManagedDNSAvailable. items: description: Condition contains details for one aspect of the current state of this API Resource. properties: @@ -7088,6 +8559,47 @@ spec: format: date-time type: string type: object + dnsZones: + description: |- + DNSZones contains DNS zone information for zones managed by the control plane. + Populated from the HostedCluster's platform status when managed ingress DNS is enabled. + items: + description: AWSDNSZoneStatus represents a managed Route53 DNS zone and its metadata. + properties: + name: + description: name is the DNS name of the hosted zone. + maxLength: 253 + minLength: 1 + type: string + nameServers: + description: |- + nameServers are the authoritative name servers for this zone. + Used for NS delegation when external-dns is not available. + items: + maxLength: 253 + minLength: 1 + type: string + maxItems: 10 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + zoneID: + description: zoneID is the Route53 hosted zone ID. + maxLength: 32 + minLength: 1 + type: string + zoneType: + description: zoneType indicates the purpose of the zone. + enum: + - PublicIngress + - PrivateIngress + type: string + required: + - name + - zoneID + - zoneType + type: object + type: array observedGeneration: description: ObservedGeneration is the most recent generation observed by the controller. format: int64 diff --git a/hyperfleet-operator/config/crd/bases/hyperfleet.io_nodepools.yaml b/hyperfleet-operator/config/crd/bases/hyperfleet.io_nodepools.yaml index f2cc7c0eb..9475eb9e8 100644 --- a/hyperfleet-operator/config/crd/bases/hyperfleet.io_nodepools.yaml +++ b/hyperfleet-operator/config/crd/bases/hyperfleet.io_nodepools.yaml @@ -90,7 +90,7 @@ spec: min: description: |- min is the minimum number of nodes to maintain in the pool. - Can be set to 0 for scale-from-zero for AWS platform. + Can be set to 0 for scale-from-zero for AWS and Azure platforms. Must be >= 0 and <= .Max. format: int32 minimum: 0 @@ -331,6 +331,25 @@ spec: is chosen based on the NodePool release payload image. maxLength: 255 type: string + cpuOptions: + description: |- + cpuOptions specifies CPU configuration for EC2 instances. + Supported on C8i, M8i, and R8i instance families. + When omitted, AWS defaults are used (nested virtualization is not enabled). + To revert to default behavior after setting cpuOptions, remove the entire + cpuOptions field rather than clearing individual sub-fields. + minProperties: 1 + properties: + nestedVirtualizationPolicy: + description: |- + nestedVirtualizationPolicy indicates whether to enable nested virtualization on the instance. + Supported on C8i, M8i, and R8i instance families. + When omitted, nested virtualization is not enabled (AWS default behavior). + enum: + - Enabled + - Disabled + type: string + type: object imageType: description: |- imageType specifies the type of image to use for node instances. @@ -466,36 +485,51 @@ spec: type: object resourceTags: description: |- - resourceTags is an optional list of additional tags to apply to AWS node - instances. Changes to this field will be propagated in-place to AWS EC2 instances and their initial EBS volumes. - Volumes created by the storage operator and attached to instances after they are created do not get these tags applied. - - These will be merged with HostedCluster scoped tags, which take precedence in case of conflicts. - These take precedence over tags defined out of band (i.e., tags added manually or by other tools outside of HyperShift) in AWS in case of conflicts. + resourceTags is a list of additional tags to apply to AWS resources created + for the NodePool. Changes to this field will be propagated in-place to AWS + EC2 instances and their initial EBS volumes. Volumes created by the storage + operator and attached to instances after they are created do not get these + tags applied. + These are merged with HostedCluster-level tags. By default, HostedCluster + tags take precedence when both specify the same key. To allow a NodePool + tag to override a specific HostedCluster tag, set overridePolicy to "Allow" + on the HostedCluster tag. + Tags that only exist at the NodePool level (no conflict) are always applied. + These take precedence over tags defined out of band (i.e., tags added + manually or by other tools outside of HyperShift) in AWS in case of + conflicts. See https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html for information on tagging AWS resources. AWS supports a maximum of 50 tags per resource. OpenShift reserves 25 tags for its use, leaving 25 tags available for the user. items: - description: AWSResourceTag is a tag to apply to AWS resources created for the cluster. + description: |- + AWSNodePoolResourceTag is a tag to apply to AWS resources created for a + NodePool. These tags are merged with HostedCluster-level tags. By default, + HostedCluster tags take precedence when both specify the same key. To allow + a NodePool tag to override a specific HostedCluster tag, set overridePolicy + to "Allow" on the HostedCluster tag. properties: key: - description: key is the key of the tag. + description: |- + key is the key of the tag. + Must be between 1 and 128 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ maxLength: 128 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ type: string value: description: |- value is the value of the tag. + Must be between 1 and 256 characters and may only contain letters, digits, + spaces, and the characters _ . : / = + - @ Some AWS service do not support empty values. Since tags are added to resources in many services, the length of the tag value must meet the requirements of all services. maxLength: 256 minLength: 1 - pattern: ^[0-9A-Za-z_.:/=+-@]+$ type: string required: - key @@ -980,7 +1014,8 @@ spec: - Contain only lowercase letters, digits, underscores, or hyphens - End with a lowercase letter or digit (not a hyphen or underscore) - Be 1-63 characters long - GCP reserves the 'goog' prefix for system labels. + GCP reserves the 'goog' prefix for system labels, with the exception of + 'goog-partner-solution' which Google requires for partner attribution tracking. See https://cloud.google.com/compute/docs/labeling-resources for Compute Engine label requirements. maxLength: 63 minLength: 1 @@ -1081,14 +1116,22 @@ spec: description: |- name specify the network attached to the nodes it is a value with the format "[namespace]/[name]" to reference the - multus network attachment definition - maxLength: 255 + multus network attachment definition, where namespace and name consist + only of lowercase alphanumeric characters and hyphens, and start and + end with alphanumeric characters + MaxLength=55: KubeVirt requires Interface.Name to be a DNS label (max 63 chars). + The generated name is "iface{N}_{namespace}-{name}" where N≤20 (MaxItems), + giving a max prefix of "iface20_" (8 chars), leaving 55 chars for namespace/name. + maxLength: 55 type: string required: - name type: object maxItems: 20 type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map attachDefaultNetwork: default: true description: |- diff --git a/hyperfleet-operator/go.mod b/hyperfleet-operator/go.mod index 74c7d844d..bcacd52ec 100644 --- a/hyperfleet-operator/go.mod +++ b/hyperfleet-operator/go.mod @@ -5,6 +5,7 @@ go 1.26.3 replace ( github.com/openshift-online/rosa-hyperfleet-api/api => ../api github.com/openshift-online/rosa-hyperfleet-api/hyperfleet-db => ../hyperfleet-db + github.com/openshift/hypershift/api => github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345 github.com/rrp-bot/rosa-hyperfleet-kube-applier/hyperfleet-dynamo => github.com/rrp-bot/rosa-hyperfleet-kube-applier/hyperfleet-dynamo v0.0.0-20260824144737-4b20672ca9a0 ) @@ -23,13 +24,13 @@ require ( github.com/onsi/gomega v1.43.0 github.com/openshift-online/rosa-hyperfleet-api/api v0.0.0 github.com/openshift-online/rosa-hyperfleet-api/hyperfleet-db v0.0.0 - github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 + github.com/openshift/api v0.0.0-20260805160557-b61243060d5f github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 github.com/prometheus/client_golang v1.24.1 github.com/rrp-bot/rosa-hyperfleet-kube-applier v0.0.0-20260824144737-4b20672ca9a0 github.com/rrp-bot/rosa-hyperfleet-kube-applier/hyperfleet-dynamo v0.0.0 - k8s.io/api v0.36.1 - k8s.io/apimachinery v0.36.1 + k8s.io/api v0.36.2 + k8s.io/apimachinery v0.36.2 k8s.io/client-go v0.36.1 k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 sigs.k8s.io/controller-runtime v0.24.1 @@ -107,7 +108,7 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect k8s.io/apiextensions-apiserver v0.36.0 // indirect k8s.io/klog/v2 v2.140.0 // indirect - k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect + k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect diff --git a/hyperfleet-operator/go.sum b/hyperfleet-operator/go.sum index 0acedfea3..fe9e38611 100644 --- a/hyperfleet-operator/go.sum +++ b/hyperfleet-operator/go.sum @@ -153,10 +153,8 @@ github.com/onsi/ginkgo/v2 v2.32.1 h1:6tlvcDm/3sE8lGJbZ4+d4mO3RLy24/tQWOFzVSQNIfw github.com/onsi/ginkgo/v2 v2.32.1/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= github.com/onsi/gomega v1.43.0 h1:VlG/1FxqNxhSO+lq/OHBNaaqwiBK/mO8JbVkX9Y+FeU= github.com/onsi/gomega v1.43.0/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= -github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 h1:r0S/yoZAI0iWo1JvoIijaIgWGWf/izg4WiV7Wrtz16k= -github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo= -github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 h1:QDSh3vkKYq7Fn9utYGlAJadkTdyaRl9IY7Cr6cNDAow= -github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16/go.mod h1:Z3lkj5pFqY+KTl3Do9gXdEZdKWLnkUTSDShLD1HE0CM= +github.com/openshift/api v0.0.0-20260805160557-b61243060d5f h1:NU7ltJhtFhqAJC+77DcNk6jmIpsJ3a+mebZIceiPW+U= +github.com/openshift/api v0.0.0-20260805160557-b61243060d5f/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -193,6 +191,8 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345 h1:4Hi+KoXlzdHAiKSMnGFF1yfvPFpkb08r0yO6SPlq4vQ= +github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345/go.mod h1:v7kWzwoisePl3ewusWeexcHlkO5MJNs+x9ORRPkqDC4= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -233,18 +233,18 @@ gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWM gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.36.1 h1:XbL/EMj8K2aJpJtePmqUyQMsM0D4QI2pvl7YKJ20FTY= -k8s.io/api v0.36.1/go.mod h1:KOWo4ey3TINlXjeHVuwB3i+tXXnu+UcwFBHlI/9dvEo= +k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY= +k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg= k8s.io/apiextensions-apiserver v0.36.0 h1:Wt7E8J+VBCbj4FjiBfDTK/neXDDjyJVJc7xfuOHImZ0= k8s.io/apiextensions-apiserver v0.36.0/go.mod h1:kGDjH0msuiIB3tgsYRV0kS9GqpMYMUsQ3GHv7TApyug= -k8s.io/apimachinery v0.36.1 h1:G63Gjx2W+q0YD+72Vo8oY0nDnePVwnuzTmmy5ENrVSA= -k8s.io/apimachinery v0.36.1/go.mod h1:ibYOR00vW/I1kzvi5SF0dRuJ52BvKtfvRdOn35GPQ+8= +k8s.io/apimachinery v0.36.2 h1:0PE/W/WNy1UX61NLbXY5TMbJ6UwLL6E6lAPkYrKFxbQ= +k8s.io/apimachinery v0.36.2/go.mod h1:fvf/HOLXq9RId0rnDIbN1OEBvHXdQbLMM8nu0LcBUf4= k8s.io/client-go v0.36.1 h1:FN/K8QIT2CEDt+2WB2HnWrUANZ50AP5GII43/SP2JR0= k8s.io/client-go v0.36.1/go.mod h1:s6rAnCtTGYDQnpNjEhSaISV+2O8jwruZ6m3QOYBFbtU= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= +k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 h1:A7Lby6ekC6nv+6oO38huCMFBRP0Os+tIeq1GkwxOQes= +k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288/go.mod h1:V/QaCUYDa+0QpcHhVVc5l99Uz56wEMEXBSj9oCDkNDY= k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 h1:jVkFFVfXdXP74B/zbO3hM3hpSFD0xvhQ5U686DPurkE= k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3/go.mod h1:M2s5JB1lIYP3jzZdorPLHXIPJzt9vv2muW5a6L9DtNM= sigs.k8s.io/controller-runtime v0.24.1 h1:miPEwrmirImAvgME1L9qebGHrOnGJoVmVdtOU9fRfo4= diff --git a/hyperfleet-operator/internal/controller/cluster_controller.go b/hyperfleet-operator/internal/controller/cluster_controller.go index d7dfb9fb2..8456806a2 100644 --- a/hyperfleet-operator/internal/controller/cluster_controller.go +++ b/hyperfleet-operator/internal/controller/cluster_controller.go @@ -537,6 +537,9 @@ func (r *ClusterReconciler) updateStatusFromDynamo(ctx context.Context, cluster } `json:"history"` } `json:"version"` ControlPlaneEndpoint hypershiftv1beta1.APIEndpoint `json:"controlPlaneEndpoint"` + Platform struct { + AWS *hypershiftv1beta1.AWSPlatformStatus `json:"aws,omitempty"` + } `json:"platform"` } `json:"status"` } if readStatus != nil && readStatus.KubeContent != nil { @@ -560,7 +563,7 @@ func (r *ClusterReconciler) updateStatusFromDynamo(ctx context.Context, cluster if readStatus != nil && readStatus.KubeContent != nil { for _, cond := range hc.Status.Conditions { - if cond.Type == "Available" || cond.Type == "Degraded" { + if cond.Type == "Available" || cond.Type == "Degraded" || cond.Type == string(hypershiftv1beta1.AWSManagedDNSAvailable) { meta.SetStatusCondition(&latest.Status.Conditions, cond) } } @@ -570,6 +573,9 @@ func (r *ClusterReconciler) updateStatusFromDynamo(ctx context.Context, cluster if len(hc.Status.Version.History) > 0 { latest.Status.Version = hc.Status.Version.History[0].Version } + if hc.Status.Platform.AWS != nil && len(hc.Status.Platform.AWS.DNSZones) > 0 { + latest.Status.DNSZones = hc.Status.Platform.AWS.DNSZones + } } if meta.IsStatusConditionTrue(latest.Status.Conditions, "Available") && diff --git a/hyperfleet-operator/internal/controller/cluster_controller_test.go b/hyperfleet-operator/internal/controller/cluster_controller_test.go index 6dc2bc0f6..e3a4106cb 100644 --- a/hyperfleet-operator/internal/controller/cluster_controller_test.go +++ b/hyperfleet-operator/internal/controller/cluster_controller_test.go @@ -167,8 +167,8 @@ var _ = Describe("Cluster Controller", func() { }) Expect(err).NotTo(HaveOccurred()) - // 7 cluster manifests → 7 ApplyDesires + 1 ReadDesire. - Expect(fd.applyCount).To(Equal(7)) + // 8 cluster manifests → 8 ApplyDesires + 1 ReadDesire. + Expect(fd.applyCount).To(Equal(8)) Expect(fd.readCount).To(Equal(1)) }) @@ -222,13 +222,13 @@ var _ = Describe("Cluster Controller", func() { }) Expect(err).NotTo(HaveOccurred()) - // 8 cluster manifests (7 legacy + oidc-signing-key ExternalSecret) - // → 8 ApplyDesires + 1 ReadDesire. - Expect(fd.applyCount).To(Equal(8)) + // 9 cluster manifests (8 base + oidc-signing-key ExternalSecret) + // → 9 ApplyDesires + 1 ReadDesire. + Expect(fd.applyCount).To(Equal(9)) Expect(fd.readCount).To(Equal(1)) }) - It("should switch all 7 desires to Type=Delete in-place, wait for confirmation, then remove finalizer", func() { + It("should switch all 8 desires to Type=Delete in-place, wait for confirmation, then remove finalizer", func() { resource := newTestCluster(clusterName) Expect(k8sClient.Create(ctx, resource)).To(Succeed()) @@ -271,14 +271,14 @@ var _ = Describe("Cluster Controller", func() { // Delete the CR — sets DeletionTimestamp. Expect(k8sClient.Delete(ctx, &updated)).To(Succeed()) - // First deletion reconcile: switches all 7 desires to Type=Delete + // First deletion reconcile: switches all 8 desires to Type=Delete // in-place; no status yet → requeues. result, err := reconciler.Reconcile(ctx, reconcile.Request{ NamespacedName: types.NamespacedName{Namespace: testNS, Name: clusterName}, }) Expect(err).NotTo(HaveOccurred()) deleteApplies := filterDeleteDesires(fd.applies) - Expect(deleteApplies).To(HaveLen(7), "all 7 resources should be switched to Type=Delete") + Expect(deleteApplies).To(HaveLen(8), "all 8 resources should be switched to Type=Delete") Expect(result.RequeueAfter).NotTo(BeZero(), "should requeue while waiting for deletion confirmation") // Placement should still exist (finalizer not removed yet). @@ -301,7 +301,7 @@ var _ = Describe("Cluster Controller", func() { }) Expect(err).NotTo(HaveOccurred()) deleteApplies = filterDeleteDesires(fd.applies) - Expect(deleteApplies).To(HaveLen(14), "7 desires re-upserted on second pass") + Expect(deleteApplies).To(HaveLen(16), "8 desires re-upserted on second pass") Expect(result.RequeueAfter).NotTo(BeZero(), "should requeue while resources still terminating") // Simulate all resources fully deleted (Successful=True). @@ -313,23 +313,23 @@ var _ = Describe("Cluster Controller", func() { }}, } - // Third deletion reconcile: all 7 confirmed deleted → cleans up + // Third deletion reconcile: all 8 confirmed deleted → cleans up // desire specs and ReadDesire, deletes Placement, removes finalizer. _, err = reconciler.Reconcile(ctx, reconcile.Request{ NamespacedName: types.NamespacedName{Namespace: testNS, Name: clusterName}, }) Expect(err).NotTo(HaveOccurred()) deleteApplies = filterDeleteDesires(fd.applies) - Expect(deleteApplies).To(HaveLen(21), "7 desires re-upserted on third pass") + Expect(deleteApplies).To(HaveLen(24), "8 desires re-upserted on third pass") // Verify the Placement was deleted. err = k8sClient.Get(ctx, types.NamespacedName{Namespace: testNS, Name: clusterName + "-placement"}, &p) Expect(err).To(HaveOccurred()) // Verify desire specs were cleaned up once at the end (not on every pass). - // 7 ApplyDesire cleanups + 1 ReadDesire cleanup. + // 8 ApplyDesire cleanups + 1 ReadDesire cleanup. applyCleanups, readCleanups := fd.countSpecCleanups() - Expect(applyCleanups).To(Equal(7), "should clean up all 7 ApplyDesire specs once deletion confirmed") + Expect(applyCleanups).To(Equal(8), "should clean up all 8 ApplyDesire specs once deletion confirmed") Expect(readCleanups).To(Equal(1), "should clean up ReadDesire spec") }) diff --git a/hyperfleet-operator/internal/render/cluster.go b/hyperfleet-operator/internal/render/cluster.go index df4615cf3..f2d77014d 100644 --- a/hyperfleet-operator/internal/render/cluster.go +++ b/hyperfleet-operator/internal/render/cluster.go @@ -36,6 +36,7 @@ func ClusterResources(cluster *hyperfleetv1alpha1.Cluster, oidcSigningKeyExterna awsIAMAuthConfig(clusterID, clusterName, ns, cluster.Spec.CreatorARN), pullSecret(clusterID, ns), apiServingCert(clusterID, clusterName, baseDomain, ns), + ingressServingCert(clusterID, clusterName, baseDomain, ns), hc, sshKey(clusterID, ns), } @@ -252,6 +253,33 @@ func extractUUIDFromIssuerURL(issuerURL string) string { return "" } +func ingressServingCert(clusterID, clusterName, baseDomain, ns string) Resource { + return Resource{ + Group: "cert-manager.io", Version: "v1", Resource: "certificates", + Name: "ingress-serving-cert", Namespace: ns, + Object: &Certificate{ + TypeMeta: metav1.TypeMeta{APIVersion: "cert-manager.io/v1", Kind: "Certificate"}, + ObjectMeta: metav1.ObjectMeta{ + Name: "ingress-serving-cert", + Namespace: ns, + Labels: map[string]string{ + "hyperfleet.io/cluster-id": clusterID, + }, + }, + Spec: CertificateSpec{ + SecretName: "ingress-serving-cert", + IssuerRef: CertificateIssuerRef{ + Name: "letsencrypt-dns01", + Kind: "ClusterIssuer", + }, + DNSNames: []string{ + fmt.Sprintf("*.apps.in.%s.%s", clusterName, baseDomain), + }, + }, + }, + } +} + func hostedCluster(cluster *hyperfleetv1alpha1.Cluster, oidcSigningKeyExternal bool, baseDomain string) (Resource, error) { clusterID := ClusterIDFromNamespace(cluster.Namespace) clusterName := cluster.Name // human-readable @@ -283,6 +311,10 @@ func hostedCluster(cluster *hyperfleetv1alpha1.Cluster, oidcSigningKeyExternal b } else { hcSpec.Configuration.APIServer = apiServerConfiguration().APIServer } + ingressDomain := fmt.Sprintf("apps.in.%s.%s", clusterName, baseDomain) + hcSpec.Configuration.Ingress = &configv1.IngressSpec{ + Domain: ingressDomain, + } // --- Defaults (only set if customer didn't specify) --- if hcSpec.Etcd.ManagementType == "" { @@ -317,7 +349,13 @@ func hostedCluster(cluster *hyperfleetv1alpha1.Cluster, oidcSigningKeyExternal b // --- Platform overrides --- if hcSpec.Platform.AWS != nil { hcSpec.Platform.AWS.EndpointAccess = hypershiftv1beta1.PublicAndPrivate - hcSpec.Platform.AWS.ResourceTags = appendSystemTags(hcSpec.Platform.AWS.ResourceTags, clusterID) + hcSpec.Platform.AWS.ResourceTags = appendClusterSystemTags(hcSpec.Platform.AWS.ResourceTags, clusterID) + hcSpec.Platform.AWS.ManagedDNS = &hypershiftv1beta1.AWSManagedDNSSpec{ + IngressDomainPrefix: "in", + Delegation: hypershiftv1beta1.AWSManagedDNSDelegationSpec{ + NSDelegation: hypershiftv1beta1.NSDelegationExternalDNS, + }, + } } // References the Secret materialized by oidcSigningKeySecret's ExternalSecret. @@ -343,7 +381,9 @@ func hostedCluster(cluster *hyperfleetv1alpha1.Cluster, oidcSigningKeyExternal b }, Annotations: map[string]string{ hypershiftv1beta1.PodSecurityAdmissionLabelOverrideAnnotation: "privileged", - hypershiftv1beta1.ControlPlaneOperatorImageAnnotation: "quay.io/cbusse_openshift/control-plane-operator:4.23-iam-auth", + hypershiftv1beta1.ControlPlaneOperatorImageAnnotation: "quay.io/cbusse_openshift/control-plane-operator:managed-ingress-dns-5afe3c5731", + hypershiftv1beta1.SkipReleaseImageValidation: "true", + hypershiftv1beta1.CleanupCloudResourcesAnnotation: "true", "hypershift.openshift.io/aws-iam-authenticator": "true", }, }, @@ -415,18 +455,25 @@ func defaultEtcdSpec() hypershiftv1beta1.EtcdSpec { } } -func appendSystemTags(existing []hypershiftv1beta1.AWSResourceTag, clusterID string) []hypershiftv1beta1.AWSResourceTag { - tags := []hypershiftv1beta1.AWSResourceTag{ +func appendClusterSystemTags(existing []hypershiftv1beta1.AWSClusterResourceTag, clusterID string) []hypershiftv1beta1.AWSClusterResourceTag { + tags := []hypershiftv1beta1.AWSClusterResourceTag{ {Key: "red-hat-managed", Value: "true"}, } if clusterID != "" { - tags = append(tags, hypershiftv1beta1.AWSResourceTag{ + tags = append(tags, hypershiftv1beta1.AWSClusterResourceTag{ Key: fmt.Sprintf("kubernetes.io/cluster/%s", clusterID), Value: "owned", }) } return append(tags, existing...) } +func appendNodePoolSystemTags(existing []hypershiftv1beta1.AWSNodePoolResourceTag) []hypershiftv1beta1.AWSNodePoolResourceTag { + tags := []hypershiftv1beta1.AWSNodePoolResourceTag{ + {Key: "red-hat-managed", Value: "true"}, + } + return append(tags, existing...) +} + func mustParseCIDR(s string) ipnet.IPNet { parsed, err := ipnet.ParseCIDR(s) if err != nil { diff --git a/hyperfleet-operator/internal/render/cluster_test.go b/hyperfleet-operator/internal/render/cluster_test.go index 8e66cc18e..cc6b2605d 100644 --- a/hyperfleet-operator/internal/render/cluster_test.go +++ b/hyperfleet-operator/internal/render/cluster_test.go @@ -67,8 +67,8 @@ func TestClusterResourcesCount(t *testing.T) { if err != nil { t.Fatalf("ClusterResources: %v", err) } - if got := len(resources); got != 7 { - t.Errorf("expected 7 resources, got %d", got) + if got := len(resources); got != 8 { + t.Errorf("expected 8 resources, got %d", got) } } @@ -87,6 +87,7 @@ func TestClusterResourcesTypes(t *testing.T) { {"configmaps", "aws-iam-auth-config"}, {"externalsecrets", "pull-secret"}, {"certificates", "api-serving-cert"}, + {"certificates", "ingress-serving-cert"}, {"hostedclusters", "my-cluster"}, {"secrets", "ssh-key"}, } @@ -109,8 +110,8 @@ func TestClusterResourcesWithOidcConfig(t *testing.T) { if err != nil { t.Fatalf("ClusterResources: %v", err) } - if got := len(resources); got != 8 { - t.Fatalf("expected 8 resources, got %d", got) + if got := len(resources); got != 9 { + t.Fatalf("expected 9 resources, got %d", got) } last := resources[len(resources)-1] diff --git a/hyperfleet-operator/internal/render/nodepool.go b/hyperfleet-operator/internal/render/nodepool.go index 08537e8bd..513239b97 100644 --- a/hyperfleet-operator/internal/render/nodepool.go +++ b/hyperfleet-operator/internal/render/nodepool.go @@ -53,7 +53,7 @@ func NodePoolResource(nodePool *hyperfleetv1alpha1.NodePool, cluster *hyperfleet npSpec.Platform.AWS.RootVolume.Type = "gp3" } } - npSpec.Platform.AWS.ResourceTags = appendSystemTags(npSpec.Platform.AWS.ResourceTags, "") + npSpec.Platform.AWS.ResourceTags = appendNodePoolSystemTags(npSpec.Platform.AWS.ResourceTags) } return Resource{ diff --git a/platform-api/go.mod b/platform-api/go.mod index f9281c96c..8f6153ac3 100644 --- a/platform-api/go.mod +++ b/platform-api/go.mod @@ -23,15 +23,15 @@ require ( github.com/openshift-online/rosa-hyperfleet-api/api v0.0.0 github.com/openshift-online/rosa-hyperfleet-api/hack/api-codegen v0.0.0-00010101000000-000000000000 github.com/openshift-online/rosa-hyperfleet-api/hyperfleet-db v0.0.0 - github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 + github.com/openshift/api v0.0.0-20260805160557-b61243060d5f github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 github.com/prometheus/client_golang v1.24.1 github.com/redis/go-redis/v9 v9.22.0 github.com/spf13/cobra v1.10.2 github.com/stretchr/testify v1.12.1 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.36.0 - k8s.io/apimachinery v0.36.0 + k8s.io/api v0.36.2 + k8s.io/apimachinery v0.36.2 k8s.io/client-go v0.36.0 sigs.k8s.io/controller-runtime v0.24.1 ) @@ -119,3 +119,5 @@ require ( sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) + +replace github.com/openshift/hypershift/api => github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345 diff --git a/platform-api/go.sum b/platform-api/go.sum index 5248b1549..6afc76356 100644 --- a/platform-api/go.sum +++ b/platform-api/go.sum @@ -168,10 +168,8 @@ github.com/onsi/ginkgo/v2 v2.32.1 h1:6tlvcDm/3sE8lGJbZ4+d4mO3RLy24/tQWOFzVSQNIfw github.com/onsi/ginkgo/v2 v2.32.1/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= github.com/onsi/gomega v1.43.0 h1:VlG/1FxqNxhSO+lq/OHBNaaqwiBK/mO8JbVkX9Y+FeU= github.com/onsi/gomega v1.43.0/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= -github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 h1:r0S/yoZAI0iWo1JvoIijaIgWGWf/izg4WiV7Wrtz16k= -github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo= -github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 h1:QDSh3vkKYq7Fn9utYGlAJadkTdyaRl9IY7Cr6cNDAow= -github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16/go.mod h1:Z3lkj5pFqY+KTl3Do9gXdEZdKWLnkUTSDShLD1HE0CM= +github.com/openshift/api v0.0.0-20260805160557-b61243060d5f h1:NU7ltJhtFhqAJC+77DcNk6jmIpsJ3a+mebZIceiPW+U= +github.com/openshift/api v0.0.0-20260805160557-b61243060d5f/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -210,6 +208,8 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345 h1:4Hi+KoXlzdHAiKSMnGFF1yfvPFpkb08r0yO6SPlq4vQ= +github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345/go.mod h1:v7kWzwoisePl3ewusWeexcHlkO5MJNs+x9ORRPkqDC4= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/gopher-lua v1.1.2 h1:yF/FjE3hD65tBbt0VXLE13HWS9h34fdzJmrWRXwobGA= @@ -261,12 +261,12 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.36.0 h1:SgqDhZzHdOtMk40xVSvCXkP9ME0H05hPM3p9AB1kL80= -k8s.io/api v0.36.0/go.mod h1:m1LVrGPNYax5NBHdO+QuAedXyuzTt4RryI/qnmNvs34= +k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY= +k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg= k8s.io/apiextensions-apiserver v0.36.0 h1:Wt7E8J+VBCbj4FjiBfDTK/neXDDjyJVJc7xfuOHImZ0= k8s.io/apiextensions-apiserver v0.36.0/go.mod h1:kGDjH0msuiIB3tgsYRV0kS9GqpMYMUsQ3GHv7TApyug= -k8s.io/apimachinery v0.36.0 h1:jZyPzhd5Z+3h9vJLt0z9XdzW9VzNzWAUw+P1xZ9PXtQ= -k8s.io/apimachinery v0.36.0/go.mod h1:FklypaRJt6n5wUIwWXIP6GJlIpUizTgfo1T/As+Tyxc= +k8s.io/apimachinery v0.36.2 h1:0PE/W/WNy1UX61NLbXY5TMbJ6UwLL6E6lAPkYrKFxbQ= +k8s.io/apimachinery v0.36.2/go.mod h1:fvf/HOLXq9RId0rnDIbN1OEBvHXdQbLMM8nu0LcBUf4= k8s.io/client-go v0.36.0 h1:pOYi7C4RHChYjMiHpZSpSbIM6ZxVbRXBy7CuiIwqA3c= k8s.io/client-go v0.36.0/go.mod h1:ZKKcpwF0aLYfkHFCjillCKaTK/yBkEDHTDXCFY6AS9Y= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= diff --git a/test/go.mod b/test/go.mod index cf112ffe9..163c4e28b 100644 --- a/test/go.mod +++ b/test/go.mod @@ -57,7 +57,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 // indirect + github.com/openshift/api v0.0.0-20260805160557-b61243060d5f // indirect github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect @@ -73,10 +73,10 @@ require ( google.golang.org/protobuf v1.36.12 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/api v0.36.0 // indirect + k8s.io/api v0.36.2 // indirect k8s.io/client-go v0.36.0 // indirect k8s.io/klog/v2 v2.140.0 // indirect - k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect + k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 // indirect k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect @@ -88,3 +88,5 @@ replace ( github.com/openshift-online/rosa-hyperfleet-api/api => ../api github.com/openshift-online/rosa-hyperfleet-api/clientset => ../clientset ) + +replace github.com/openshift/hypershift/api => github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345 diff --git a/test/go.sum b/test/go.sum index 6e3c25b28..c7200b42f 100644 --- a/test/go.sum +++ b/test/go.sum @@ -121,10 +121,8 @@ github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= -github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 h1:r0S/yoZAI0iWo1JvoIijaIgWGWf/izg4WiV7Wrtz16k= -github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo= -github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 h1:QDSh3vkKYq7Fn9utYGlAJadkTdyaRl9IY7Cr6cNDAow= -github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16/go.mod h1:Z3lkj5pFqY+KTl3Do9gXdEZdKWLnkUTSDShLD1HE0CM= +github.com/openshift/api v0.0.0-20260805160557-b61243060d5f h1:NU7ltJhtFhqAJC+77DcNk6jmIpsJ3a+mebZIceiPW+U= +github.com/openshift/api v0.0.0-20260805160557-b61243060d5f/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -146,6 +144,8 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345 h1:4Hi+KoXlzdHAiKSMnGFF1yfvPFpkb08r0yO6SPlq4vQ= +github.com/typeid/hypershift/api v0.0.0-20260916080119-50a03de4e345/go.mod h1:v7kWzwoisePl3ewusWeexcHlkO5MJNs+x9ORRPkqDC4= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= @@ -178,16 +178,16 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.36.0 h1:SgqDhZzHdOtMk40xVSvCXkP9ME0H05hPM3p9AB1kL80= -k8s.io/api v0.36.0/go.mod h1:m1LVrGPNYax5NBHdO+QuAedXyuzTt4RryI/qnmNvs34= +k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY= +k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg= k8s.io/apimachinery v0.36.3 h1:PkzMRBRG8joFD8EhCuQAtNPvJlxb82FwplP26HIzvAM= k8s.io/apimachinery v0.36.3/go.mod h1:cTSjBWgPe/6CQyBKzY/hDIRWCQQQeK0mfLbml0UYFHE= k8s.io/client-go v0.36.0 h1:pOYi7C4RHChYjMiHpZSpSbIM6ZxVbRXBy7CuiIwqA3c= k8s.io/client-go v0.36.0/go.mod h1:ZKKcpwF0aLYfkHFCjillCKaTK/yBkEDHTDXCFY6AS9Y= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= +k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288 h1:A7Lby6ekC6nv+6oO38huCMFBRP0Os+tIeq1GkwxOQes= +k8s.io/kube-openapi v0.0.0-20260519202549-bbf5c5577288/go.mod h1:V/QaCUYDa+0QpcHhVVc5l99Uz56wEMEXBSj9oCDkNDY= k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 h1:jVkFFVfXdXP74B/zbO3hM3hpSFD0xvhQ5U686DPurkE= k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3/go.mod h1:M2s5JB1lIYP3jzZdorPLHXIPJzt9vv2muW5a6L9DtNM= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=