diff --git a/api/hypershift/v1beta1/hosted_controlplane.go b/api/hypershift/v1beta1/hosted_controlplane.go index cb618ee4b09a..9d91e15ce1fe 100644 --- a/api/hypershift/v1beta1/hosted_controlplane.go +++ b/api/hypershift/v1beta1/hosted_controlplane.go @@ -354,6 +354,15 @@ type HostedControlPlaneStatus struct { // +kubebuilder:validation:MaxLength=255 OAuthCallbackURLTemplate string `json:"oauthCallbackURLTemplate,omitempty"` + // consoleURL is the URL of the OpenShift web console for this hosted cluster. + // This is populated from the console.config.openshift.io/cluster resource + // in the guest cluster once the console operator has reconciled. + // +optional + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=4096 + // +kubebuilder:validation:XValidation:rule="isURL(self)",message="consoleURL must be a valid URL" + ConsoleURL string `json:"consoleURL,omitempty"` + // controlPlaneVersion tracks the rollout status of the control plane // components running on the management cluster, independently from // the data-plane version reported in the version field. diff --git a/api/hypershift/v1beta1/hostedcluster_conditions.go b/api/hypershift/v1beta1/hostedcluster_conditions.go index d34661d773ea..6e820226af6b 100644 --- a/api/hypershift/v1beta1/hostedcluster_conditions.go +++ b/api/hypershift/v1beta1/hostedcluster_conditions.go @@ -191,6 +191,22 @@ const ( // A failure here often means a software bug or a non-stable cluster. ReconciliationSucceeded ConditionType = "ReconciliationSucceeded" + // ConfigOperatorReconciliationSucceeded indicates if the HostedCluster Config + // Operator (HCCO) reconciliation succeeded. The HCCO is responsible for + // reconciling resources inside the hosted cluster (e.g. global configuration, + // CRDs, RBAC, and connectivity checks). + // A failure here often means a software bug, a non-stable cluster, or + // connectivity issues between the control plane and the hosted cluster. + ConfigOperatorReconciliationSucceeded ConditionType = "ConfigOperatorReconciliationSucceeded" + + // ValidHostedClusterStatus indicates whether status information propagated + // from the hosted cluster (e.g. ConsoleURL from the console operator) is + // valid and was accepted. A False value means the hosted cluster reported + // data that could not be propagated — for example, a ConsoleURL that + // exceeds the maximum allowed length. This condition is set by HCCO and + // bubbled up to the HostedCluster. + ValidHostedClusterStatus ConditionType = "ValidHostedClusterStatus" + // EtcdRecoveryActive indicates that the Etcd cluster is failing and the // recovery job was triggered. EtcdRecoveryActive ConditionType = "EtcdRecoveryActive" @@ -324,6 +340,8 @@ const ( ControlPlaneConnectionNoWorkerNodesAvailableReason = "NoWorkerNodesAvailable" + InvalidHostedClusterStatusReason = "InvalidHostedClusterStatus" + ControlPlaneComponentsNotAvailable = "ComponentsNotAvailable" AutoNodeNotConfiguredReason = "AutoNodeNotConfigured" diff --git a/api/hypershift/v1beta1/hostedcluster_types.go b/api/hypershift/v1beta1/hostedcluster_types.go index ce0ecaf81ee5..8ecdf3e63cb2 100644 --- a/api/hypershift/v1beta1/hostedcluster_types.go +++ b/api/hypershift/v1beta1/hostedcluster_types.go @@ -2302,6 +2302,15 @@ type HostedClusterStatus struct { // +kubebuilder:validation:MaxLength=1024 OAuthCallbackURLTemplate string `json:"oauthCallbackURLTemplate,omitempty"` + // consoleURL is the URL of the OpenShift web console for this hosted cluster. + // This is populated from the console.config.openshift.io/cluster resource + // in the guest cluster once the console operator has reconciled. + // +optional + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=4096 + // +kubebuilder:validation:XValidation:rule="isURL(self)",message="consoleURL must be a valid URL" + ConsoleURL string `json:"consoleURL,omitempty"` + // payloadArch represents the CPU architecture type of the HostedCluster.Spec.Release.Image. The valid values are: // Multi, ARM64, AMD64, S390X, or PPC64LE. // +kubebuilder:validation:Enum=Multi;ARM64;AMD64;PPC64LE;S390X diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml index 6a43dd36a5b8..958495f0a856 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml @@ -6524,6 +6524,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml index dba29960a1b8..34ff0b802e71 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml @@ -6663,6 +6663,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml index ae33d6d3e07d..490bcf85e445 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml @@ -6507,6 +6507,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml index c20cf7ab2b3e..cee91a3f3a95 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml @@ -6527,6 +6527,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml index 7e35088d6ff8..406e0949cf2b 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml @@ -7005,6 +7005,17 @@ spec: x-kubernetes-list-type: map type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml index 9693ed970d74..20c37db912d9 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml @@ -7145,6 +7145,17 @@ spec: x-kubernetes-list-type: map type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml index ad2f5eb3c432..5151b8753f4c 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml @@ -6961,6 +6961,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml index e925ed7ee0a9..b8693dc33273 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml @@ -6927,6 +6927,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml index 8c514b6f9470..b6f8c3dc82e7 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml @@ -6572,6 +6572,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml index 0d88e73b6802..4039f1fb0f0b 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml @@ -6529,6 +6529,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml index 03bf685635d1..dd75da0eb517 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml @@ -6525,6 +6525,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml index cc37823e4884..306626042071 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml @@ -6583,6 +6583,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml index 078863df10ed..d03866f2b2f9 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml @@ -7058,6 +7058,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml index a761964daf44..138d784f79c7 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml @@ -6326,6 +6326,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml index eaec5504e031..a3f1ab266390 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml @@ -6467,6 +6467,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml index 29801153bfd3..98da97baaf49 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml @@ -6309,6 +6309,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml index babd4ac02c0b..442ada8eead8 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml @@ -6329,6 +6329,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml index c01534ee08f4..529637b3e52e 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml @@ -6807,6 +6807,17 @@ spec: x-kubernetes-list-type: map type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml index e5deab3ce474..46636295bdc8 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml @@ -6947,6 +6947,17 @@ spec: x-kubernetes-list-type: map type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml index 28f733262692..e55135ab9827 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml @@ -6763,6 +6763,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml index c91707459fdc..0071753c39e3 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml @@ -6729,6 +6729,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml index 8edd8df4ca2a..b34885751272 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml @@ -6374,6 +6374,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml index c86527fffe00..90525e266e93 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml @@ -6331,6 +6331,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml index ce0bd35a480b..d7b75ae85489 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml @@ -6327,6 +6327,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml index 5b233d53ff9f..4a3e0821e22e 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml @@ -6385,6 +6385,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml index da3ccbc41d00..71d1c4c09cb6 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml @@ -6860,6 +6860,17 @@ spec: type: object type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/client/applyconfiguration/hypershift/v1beta1/hostedclusterstatus.go b/client/applyconfiguration/hypershift/v1beta1/hostedclusterstatus.go index 3f0658004684..3125ccd2bfb3 100644 --- a/client/applyconfiguration/hypershift/v1beta1/hostedclusterstatus.go +++ b/client/applyconfiguration/hypershift/v1beta1/hostedclusterstatus.go @@ -35,6 +35,7 @@ type HostedClusterStatusApplyConfiguration struct { IgnitionEndpoint *string `json:"ignitionEndpoint,omitempty"` ControlPlaneEndpoint *APIEndpointApplyConfiguration `json:"controlPlaneEndpoint,omitempty"` OAuthCallbackURLTemplate *string `json:"oauthCallbackURLTemplate,omitempty"` + ConsoleURL *string `json:"consoleURL,omitempty"` PayloadArch *hypershiftv1beta1.PayloadArchType `json:"payloadArch,omitempty"` Platform *PlatformStatusApplyConfiguration `json:"platform,omitempty"` AutoNode *AutoNodeStatusApplyConfiguration `json:"autoNode,omitempty"` @@ -126,6 +127,14 @@ func (b *HostedClusterStatusApplyConfiguration) WithOAuthCallbackURLTemplate(val return b } +// WithConsoleURL sets the ConsoleURL field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ConsoleURL field is set to the value of the last call. +func (b *HostedClusterStatusApplyConfiguration) WithConsoleURL(value string) *HostedClusterStatusApplyConfiguration { + b.ConsoleURL = &value + return b +} + // WithPayloadArch sets the PayloadArch field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the PayloadArch field is set to the value of the last call. diff --git a/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanestatus.go b/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanestatus.go index eb7967bf4494..606d1bcdb5ed 100644 --- a/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanestatus.go +++ b/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanestatus.go @@ -32,6 +32,7 @@ type HostedControlPlaneStatusApplyConfiguration struct { ExternalManagedControlPlane *bool `json:"externalManagedControlPlane,omitempty"` ControlPlaneEndpoint *APIEndpointApplyConfiguration `json:"controlPlaneEndpoint,omitempty"` OAuthCallbackURLTemplate *string `json:"oauthCallbackURLTemplate,omitempty"` + ConsoleURL *string `json:"consoleURL,omitempty"` ControlPlaneVersion *ControlPlaneVersionStatusApplyConfiguration `json:"controlPlaneVersion,omitempty"` VersionStatus *ClusterVersionStatusApplyConfiguration `json:"versionStatus,omitempty"` Version *string `json:"version,omitempty"` @@ -106,6 +107,14 @@ func (b *HostedControlPlaneStatusApplyConfiguration) WithOAuthCallbackURLTemplat return b } +// WithConsoleURL sets the ConsoleURL field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ConsoleURL field is set to the value of the last call. +func (b *HostedControlPlaneStatusApplyConfiguration) WithConsoleURL(value string) *HostedControlPlaneStatusApplyConfiguration { + b.ConsoleURL = &value + return b +} + // WithControlPlaneVersion sets the ControlPlaneVersion field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the ControlPlaneVersion field is set to the value of the last call. diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml index 8f4696f02dfa..3861b5e9aa27 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml @@ -8591,6 +8591,17 @@ spec: x-kubernetes-list-type: map type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml index 1e7000c992ea..7410d57daf5a 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml @@ -7182,6 +7182,17 @@ spec: x-kubernetes-list-type: map type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml index 449e067ff34f..b0d50dafa98b 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml @@ -8502,6 +8502,17 @@ spec: x-kubernetes-list-type: map type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml index 1d428efff530..24481666591a 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml @@ -8395,6 +8395,17 @@ spec: x-kubernetes-list-type: map type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml index 27ccd2cd2da2..d50a6e519bc7 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml @@ -6984,6 +6984,17 @@ spec: x-kubernetes-list-type: map type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml index 9b19e7197c89..676b71b7a82a 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml @@ -8306,6 +8306,17 @@ spec: x-kubernetes-list-type: map type: object type: object + consoleURL: + description: |- + consoleURL is the URL of the OpenShift web console for this hosted cluster. + This is populated from the console.config.openshift.io/cluster resource + in the guest cluster once the console operator has reconciled. + maxLength: 4096 + minLength: 1 + type: string + x-kubernetes-validations: + - message: consoleURL must be a valid URL + rule: isURL(self) controlPlaneEndpoint: description: |- controlPlaneEndpoint contains the endpoint information by which diff --git a/control-plane-operator/hostedclusterconfigoperator/cmd.go b/control-plane-operator/hostedclusterconfigoperator/cmd.go index 15d22efcaa54..8170b0e002af 100644 --- a/control-plane-operator/hostedclusterconfigoperator/cmd.go +++ b/control-plane-operator/hostedclusterconfigoperator/cmd.go @@ -71,7 +71,6 @@ var controllerFuncs = map[string]operator.ControllerSetupFunc{ nodecount.ControllerName: nodecount.Setup, "machine": machine.Setup, "drainer": drainer.Setup, - hcpstatus.ControllerName: hcpstatus.Setup, spotremediation.ControllerName: spotremediation.Setup, reencryption.ControllerName: reencryption.Setup, } @@ -168,13 +167,14 @@ func newHostedClusterConfigOperator() *HostedClusterConfigOperator { } func allControllers() []string { - controllers := make([]string, 0, len(controllerFuncs)) + controllers := make([]string, 0, len(controllerFuncs)+1) for name := range controllerFuncs { if name == nodecount.ControllerName && os.Getenv("ENABLE_SIZE_TAGGING") != "1" { continue } controllers = append(controllers, name) } + controllers = append(controllers, hcpstatus.ControllerName) return controllers } @@ -240,6 +240,10 @@ func (o *HostedClusterConfigOperator) Run(ctx context.Context) error { } mgr := operator.Mgr(ctx, cfg, cpConfig, o.Namespace, o.HostedControlPlaneName) + hcpCapabilities, err := operator.GetHCPCapabilities(ctx, cpConfig, o.Namespace, o.HostedControlPlaneName) + if err != nil { + return fmt.Errorf("failed to get HCP capabilities: %w", err) + } mgr.GetLogger().Info("Starting hosted-cluster-config-operator", "version", supportedversion.String()) cpCluster, err := cluster.New(cpConfig, func(opt *cluster.Options) { opt.Cache = cache.Options{ @@ -306,6 +310,10 @@ func (o *HostedClusterConfigOperator) Run(ctx context.Context) error { } for _, controllerName := range o.Controllers { + if controllerName == hcpstatus.ControllerName { + controllersToRun[hcpstatus.ControllerName] = hcpstatus.Setup(hcpCapabilities) + continue + } if setup, registered := controllerFuncs[controllerName]; !registered { return fmt.Errorf("requested to run unknown controller %q", controllerName) } else { diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/hcpstatus/hcpstatus.go b/control-plane-operator/hostedclusterconfigoperator/controllers/hcpstatus/hcpstatus.go index fbb43c09f449..afc216ea8d4d 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/hcpstatus/hcpstatus.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/hcpstatus/hcpstatus.go @@ -8,11 +8,13 @@ import ( hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1" "github.com/openshift/hypershift/control-plane-operator/hostedclusterconfigoperator/operator" + "github.com/openshift/hypershift/support/capabilities" "github.com/openshift/hypershift/support/releaseinfo" configv1 "github.com/openshift/api/config/v1" "k8s.io/apimachinery/pkg/api/equality" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -27,36 +29,47 @@ import ( const ControllerName = "hcpstatus" -func Setup(ctx context.Context, opts *operator.HostedClusterConfigOperatorConfig) error { - r := &hcpStatusReconciler{ - mgtClusterClient: opts.CPCluster.GetClient(), - hostedClusterClient: opts.Manager.GetClient(), - releaseProvider: opts.ReleaseProvider, - } - c, err := controller.New(ControllerName, opts.Manager, controller.Options{Reconciler: r}) - if err != nil { - return fmt.Errorf("failed to construct controller: %w", err) - } - if err := c.Watch(source.Kind(opts.CPCluster.GetCache(), &hyperv1.HostedControlPlane{}, &handler.TypedEnqueueRequestForObject[*hyperv1.HostedControlPlane]{})); err != nil { - return fmt.Errorf("failed to watch HCP: %w", err) - } +func Setup(hcpCapabilities *hyperv1.Capabilities) func(ctx context.Context, opts *operator.HostedClusterConfigOperatorConfig) error { + return func(ctx context.Context, opts *operator.HostedClusterConfigOperatorConfig) error { + r := &hcpStatusReconciler{ + mgtClusterClient: opts.CPCluster.GetClient(), + hostedClusterClient: opts.Manager.GetClient(), + releaseProvider: opts.ReleaseProvider, + } + c, err := controller.New(ControllerName, opts.Manager, controller.Options{Reconciler: r}) + if err != nil { + return fmt.Errorf("failed to construct controller: %w", err) + } + if err := c.Watch(source.Kind(opts.CPCluster.GetCache(), &hyperv1.HostedControlPlane{}, &handler.TypedEnqueueRequestForObject[*hyperv1.HostedControlPlane]{})); err != nil { + return fmt.Errorf("failed to watch HCP: %w", err) + } - clusterVersionMapper := func(context.Context, crclient.Object) []reconcile.Request { - return []reconcile.Request{{NamespacedName: types.NamespacedName{Namespace: opts.Namespace, Name: opts.HCPName}}} - } - if err := c.Watch(source.Kind[crclient.Object](opts.Manager.GetCache(), &configv1.ClusterVersion{}, handler.EnqueueRequestsFromMapFunc(clusterVersionMapper))); err != nil { - return fmt.Errorf("failed to watch clusterversion: %w", err) - } + clusterVersionMapper := func(context.Context, crclient.Object) []reconcile.Request { + return []reconcile.Request{{NamespacedName: types.NamespacedName{Namespace: opts.Namespace, Name: opts.HCPName}}} + } + if err := c.Watch(source.Kind[crclient.Object](opts.Manager.GetCache(), &configv1.ClusterVersion{}, handler.EnqueueRequestsFromMapFunc(clusterVersionMapper))); err != nil { + return fmt.Errorf("failed to watch clusterversion: %w", err) + } - clusterAuthenticationMapper := func(context.Context, crclient.Object) []reconcile.Request { - return []reconcile.Request{{NamespacedName: types.NamespacedName{Namespace: opts.Namespace, Name: opts.HCPName}}} - } + clusterAuthenticationMapper := func(context.Context, crclient.Object) []reconcile.Request { + return []reconcile.Request{{NamespacedName: types.NamespacedName{Namespace: opts.Namespace, Name: opts.HCPName}}} + } - if err := c.Watch(source.Kind[crclient.Object](opts.Manager.GetCache(), &configv1.Authentication{}, handler.EnqueueRequestsFromMapFunc(clusterAuthenticationMapper))); err != nil { - return fmt.Errorf("failed to watch authentication: %w", err) - } + if err := c.Watch(source.Kind[crclient.Object](opts.Manager.GetCache(), &configv1.Authentication{}, handler.EnqueueRequestsFromMapFunc(clusterAuthenticationMapper))); err != nil { + return fmt.Errorf("failed to watch authentication: %w", err) + } - return nil + if capabilities.IsConsoleCapabilityEnabled(hcpCapabilities) { + consoleMapper := func(context.Context, crclient.Object) []reconcile.Request { + return []reconcile.Request{{NamespacedName: types.NamespacedName{Namespace: opts.Namespace, Name: opts.HCPName}}} + } + if err := c.Watch(source.Kind[crclient.Object](opts.Manager.GetCache(), &configv1.Console{}, handler.EnqueueRequestsFromMapFunc(consoleMapper))); err != nil { + return fmt.Errorf("failed to watch console: %w", err) + } + } + + return nil + } } type hcpStatusReconciler struct { @@ -235,6 +248,54 @@ func (h *hcpStatusReconciler) reconcile(ctx context.Context, hcp *hyperv1.Hosted meta.SetStatusCondition(&hcp.Status.Conditions, hcpCVOCondition) } + if !capabilities.IsConsoleCapabilityEnabled(hcp.Spec.Capabilities) { + meta.SetStatusCondition(&hcp.Status.Conditions, metav1.Condition{ + Type: string(hyperv1.ValidHostedClusterStatus), + Status: metav1.ConditionTrue, + Reason: hyperv1.AsExpectedReason, + ObservedGeneration: hcp.Generation, + }) + } else { + var console configv1.Console + if err := h.hostedClusterClient.Get(ctx, crclient.ObjectKey{Name: "cluster"}, &console); err != nil { + if apierrors.IsNotFound(err) { + hcp.Status.ConsoleURL = "" + meta.SetStatusCondition(&hcp.Status.Conditions, metav1.Condition{ + Type: string(hyperv1.ValidHostedClusterStatus), + Status: metav1.ConditionFalse, + Reason: hyperv1.InvalidHostedClusterStatusReason, + Message: "Console resource not found in the hosted cluster", + ObservedGeneration: hcp.Generation, + }) + } else { + // Log and continue — a transient Console fetch failure should not + // block Authentication and ConfigurationStatus updates below. + // ConsoleURL stays unchanged until the next successful reconcile. + log.Error(err, "Failed to get Console resource, skipping ConsoleURL update") + } + } else { + const maxConsoleURLLength = 4096 + if len(console.Status.ConsoleURL) > maxConsoleURLLength { + log.Info("Ignoring oversized ConsoleURL from hosted cluster", "length", len(console.Status.ConsoleURL), "max", maxConsoleURLLength) + meta.SetStatusCondition(&hcp.Status.Conditions, metav1.Condition{ + Type: string(hyperv1.ValidHostedClusterStatus), + Status: metav1.ConditionFalse, + Reason: hyperv1.InvalidHostedClusterStatusReason, + Message: fmt.Sprintf("ConsoleURL from hosted cluster exceeds maximum length (%d > %d); value was not propagated", len(console.Status.ConsoleURL), maxConsoleURLLength), + ObservedGeneration: hcp.Generation, + }) + } else { + hcp.Status.ConsoleURL = console.Status.ConsoleURL + meta.SetStatusCondition(&hcp.Status.Conditions, metav1.Condition{ + Type: string(hyperv1.ValidHostedClusterStatus), + Status: metav1.ConditionTrue, + Reason: hyperv1.AsExpectedReason, + ObservedGeneration: hcp.Generation, + }) + } + } + } + var authentication configv1.Authentication if err = h.hostedClusterClient.Get(ctx, crclient.ObjectKey{Name: "cluster"}, &authentication); err != nil { return fmt.Errorf("failed to get Authentication resource \"cluster\": %w", err) diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/hcpstatus/hcpstatus_test.go b/control-plane-operator/hostedclusterconfigoperator/controllers/hcpstatus/hcpstatus_test.go index 73655f694287..f6b09cd50561 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/hcpstatus/hcpstatus_test.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/hcpstatus/hcpstatus_test.go @@ -1,7 +1,10 @@ package hcpstatus import ( + "context" "encoding/json" + "fmt" + "reflect" "testing" . "github.com/onsi/gomega" @@ -211,6 +214,175 @@ func TestHCPStatusReconciler(t *testing.T) { } } +func TestReconcileConsoleURL(t *testing.T) { + t.Parallel() + + baseObjects := func(extra ...crclient.Object) []crclient.Object { + objs := []crclient.Object{ + &configv1.ClusterVersion{ObjectMeta: metav1.ObjectMeta{Name: "version"}}, + &configv1.Authentication{ + ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, + }, + } + return append(objs, extra...) + } + + t.Run("When Console resource exists, it should set ConsoleURL on HCP status", func(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + hcp := &hyperv1.HostedControlPlane{ + ObjectMeta: metav1.ObjectMeta{Name: "test-hcp", Namespace: "test-ns"}, + Spec: hyperv1.HostedControlPlaneSpec{Capabilities: &hyperv1.Capabilities{}}, + } + + hostedClusterClient := fake.NewClientBuilder(). + WithScheme(api.Scheme). + WithObjects(baseObjects(&configv1.Console{ + ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, + Status: configv1.ConsoleStatus{ConsoleURL: "https://console.example.com"}, + })...). + Build() + + reconciler := &hcpStatusReconciler{ + hostedClusterClient: hostedClusterClient, + } + + err := reconciler.reconcile(t.Context(), hcp) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(hcp.Status.ConsoleURL).To(Equal("https://console.example.com")) + + statusCond := meta.FindStatusCondition(hcp.Status.Conditions, string(hyperv1.ValidHostedClusterStatus)) + g.Expect(statusCond).NotTo(BeNil(), "ValidHostedClusterStatus condition should be set") + g.Expect(statusCond.Status).To(Equal(metav1.ConditionTrue)) + g.Expect(statusCond.Reason).To(Equal(hyperv1.AsExpectedReason)) + }) + + t.Run("When Console resource is not found, it should clear ConsoleURL without error", func(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + hcp := &hyperv1.HostedControlPlane{ + ObjectMeta: metav1.ObjectMeta{Name: "test-hcp", Namespace: "test-ns"}, + Spec: hyperv1.HostedControlPlaneSpec{Capabilities: &hyperv1.Capabilities{}}, + Status: hyperv1.HostedControlPlaneStatus{ConsoleURL: "https://old.example.com"}, + } + + hostedClusterClient := fake.NewClientBuilder(). + WithScheme(api.Scheme). + WithObjects(baseObjects()...). + Build() + + reconciler := &hcpStatusReconciler{ + hostedClusterClient: hostedClusterClient, + } + + err := reconciler.reconcile(t.Context(), hcp) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(hcp.Status.ConsoleURL).To(BeEmpty()) + statusCond := meta.FindStatusCondition(hcp.Status.Conditions, string(hyperv1.ValidHostedClusterStatus)) + g.Expect(statusCond).NotTo(BeNil(), "ValidHostedClusterStatus condition should be set even when Console is not found") + g.Expect(statusCond.Status).To(Equal(metav1.ConditionFalse)) + g.Expect(statusCond.Message).To(ContainSubstring("Console resource not found")) + }) + + t.Run("When Console resource fetch returns a generic error, it should log and continue without blocking other updates", func(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + hcp := &hyperv1.HostedControlPlane{ + ObjectMeta: metav1.ObjectMeta{Name: "test-hcp", Namespace: "test-ns"}, + Spec: hyperv1.HostedControlPlaneSpec{Capabilities: &hyperv1.Capabilities{}}, + Status: hyperv1.HostedControlPlaneStatus{ConsoleURL: "https://previous.example.com"}, + } + + hostedClusterClient := &erroringClient{ + Client: fake.NewClientBuilder().WithScheme(api.Scheme).WithObjects(baseObjects()...).Build(), + errorOn: "Console", + returnErr: fmt.Errorf("connection refused"), + } + + reconciler := &hcpStatusReconciler{ + hostedClusterClient: hostedClusterClient, + } + + err := reconciler.reconcile(t.Context(), hcp) + g.Expect(err).NotTo(HaveOccurred(), "transient Console error should not fail the reconcile") + g.Expect(hcp.Status.ConsoleURL).To(Equal("https://previous.example.com"), + "ConsoleURL should remain unchanged when Console fetch fails") + g.Expect(hcp.Status.Configuration).NotTo(BeNil(), + "Authentication/Configuration should still be populated despite Console error") + }) + + t.Run("When Console capability is disabled, it should not update ConsoleURL even if Console resource exists", func(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + hcp := &hyperv1.HostedControlPlane{ + ObjectMeta: metav1.ObjectMeta{Name: "test-hcp", Namespace: "test-ns"}, + Spec: hyperv1.HostedControlPlaneSpec{Capabilities: &hyperv1.Capabilities{ + Disabled: []hyperv1.OptionalCapability{hyperv1.ConsoleCapability}, + }}, + Status: hyperv1.HostedControlPlaneStatus{ConsoleURL: "https://existing.example.com"}, + } + + hostedClusterClient := fake.NewClientBuilder(). + WithScheme(api.Scheme). + WithObjects(baseObjects(&configv1.Console{ + ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, + Status: configv1.ConsoleStatus{ConsoleURL: "https://different.example.com"}, + })...). + Build() + + reconciler := &hcpStatusReconciler{ + hostedClusterClient: hostedClusterClient, + } + + err := reconciler.reconcile(t.Context(), hcp) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(hcp.Status.ConsoleURL).To(Equal("https://existing.example.com"), + "ConsoleURL should remain unchanged when Console capability is disabled") + statusCond := meta.FindStatusCondition(hcp.Status.Conditions, string(hyperv1.ValidHostedClusterStatus)) + g.Expect(statusCond).NotTo(BeNil(), "ValidHostedClusterStatus condition should be set even when Console capability is disabled") + g.Expect(statusCond.Status).To(Equal(metav1.ConditionTrue)) + }) + + t.Run("When ConsoleURL exceeds MaxLength, it should not update ConsoleURL", func(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + hcp := &hyperv1.HostedControlPlane{ + ObjectMeta: metav1.ObjectMeta{Name: "test-hcp", Namespace: "test-ns"}, + Spec: hyperv1.HostedControlPlaneSpec{Capabilities: &hyperv1.Capabilities{}}, + Status: hyperv1.HostedControlPlaneStatus{ConsoleURL: "https://previous.example.com"}, + } + + longURL := "https://console." + string(make([]byte, 4097)) + hostedClusterClient := fake.NewClientBuilder(). + WithScheme(api.Scheme). + WithObjects(baseObjects(&configv1.Console{ + ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, + Status: configv1.ConsoleStatus{ConsoleURL: longURL}, + })...). + Build() + + reconciler := &hcpStatusReconciler{ + hostedClusterClient: hostedClusterClient, + } + + err := reconciler.reconcile(t.Context(), hcp) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(hcp.Status.ConsoleURL).To(Equal("https://previous.example.com"), + "ConsoleURL should remain unchanged when value exceeds MaxLength") + + statusCond := meta.FindStatusCondition(hcp.Status.Conditions, string(hyperv1.ValidHostedClusterStatus)) + g.Expect(statusCond).NotTo(BeNil(), "ValidHostedClusterStatus condition should be set") + g.Expect(statusCond.Status).To(Equal(metav1.ConditionFalse)) + g.Expect(statusCond.Reason).To(Equal(hyperv1.InvalidHostedClusterStatusReason)) + g.Expect(statusCond.Message).To(ContainSubstring("ConsoleURL")) + }) +} + func TestBuildStatusPatch(t *testing.T) { t.Parallel() @@ -539,3 +711,18 @@ func TestBuildStatusPatch(t *testing.T) { )) }) } + +// erroringClient wraps a crclient.Client and returns a specific error when +// Get is called for an object whose kind name contains the errorOn string. +type erroringClient struct { + crclient.Client + errorOn string + returnErr error +} + +func (e *erroringClient) Get(ctx context.Context, key crclient.ObjectKey, obj crclient.Object, opts ...crclient.GetOption) error { + if reflect.TypeOf(obj).Elem().Name() == e.errorOn { + return e.returnErr + } + return e.Client.Get(ctx, key, obj, opts...) +} diff --git a/control-plane-operator/hostedclusterconfigoperator/operator/config.go b/control-plane-operator/hostedclusterconfigoperator/operator/config.go index 076633d2d894..f8c16d89c3a0 100644 --- a/control-plane-operator/hostedclusterconfigoperator/operator/config.go +++ b/control-plane-operator/hostedclusterconfigoperator/operator/config.go @@ -146,6 +146,10 @@ func Mgr(ctx context.Context, cfg, cpConfig *rest.Config, namespace string, hcpN byObject[&operatorv1.IngressController{}] = allSelector } + if capabilities.IsConsoleCapabilityEnabled(hcp.Spec.Capabilities) { + byObject[&configv1.Console{}] = allSelector + } + leaseDuration := time.Second * 60 renewDeadline := time.Second * 40 retryPeriod := time.Second * 15 @@ -194,6 +198,19 @@ func Mgr(ctx context.Context, cfg, cpConfig *rest.Config, namespace string, hcpN return mgr } +// GetHCPCapabilities reads the HostedControlPlane and returns its capabilities. +func GetHCPCapabilities(ctx context.Context, cpConfig *rest.Config, namespace, hcpName string) (*hyperv1.Capabilities, error) { + ct, err := client.New(cpConfig, client.Options{Scheme: hyperapi.Scheme}) + if err != nil { + return nil, fmt.Errorf("failed to create client: %w", err) + } + hcp := resourcemanifests.HostedControlPlane(namespace, hcpName) + if err := ct.Get(ctx, client.ObjectKeyFromObject(hcp), hcp); err != nil { + return nil, fmt.Errorf("failed to get HCP: %w", err) + } + return hcp.Spec.Capabilities, nil +} + func CfgFromFile(path string) *rest.Config { cfg, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( &clientcmd.ClientConfigLoadingRules{ExplicitPath: path}, diff --git a/docs/content/reference/aggregated-docs.md b/docs/content/reference/aggregated-docs.md index 3d478c247ad4..f9f691ef837d 100644 --- a/docs/content/reference/aggregated-docs.md +++ b/docs/content/reference/aggregated-docs.md @@ -36553,6 +36553,14 @@ A failure here may require external user intervention to resolve.
supported by the underlying management cluster. A failure here is unlikely to resolve without the changing user input. +"ValidHostedClusterStatus"
ValidHostedClusterStatus indicates whether status information propagated +from the hosted cluster (e.g. ConsoleURL from the console operator) is +valid and was accepted. A False value means the hosted cluster reported +data that could not be propagated — for example, a ConsoleURL that +exceeds the maximum allowed length. This condition is set by HCCO and +bubbled up to the HostedCluster.
+"ValidHostedControlPlaneConfiguration"
ValidHostedControlPlaneConfiguration bubbles up the same condition from HCP. It signals if the hostedControlPlane input is valid and supported by the underlying management cluster. @@ -40144,6 +40152,20 @@ This is populated after the infrastructure is ready.
consoleURL
+
+string
+
+consoleURL is the URL of the OpenShift web console for this hosted cluster. +This is populated from the console.config.openshift.io/cluster resource +in the guest cluster once the console operator has reconciled.
+payloadArch
@@ -40840,6 +40862,20 @@ This is populated after the infrastructure is ready.
consoleURL
+
+string
+
+consoleURL is the URL of the OpenShift web console for this hosted cluster. +This is populated from the console.config.openshift.io/cluster resource +in the guest cluster once the console operator has reconciled.
+controlPlaneVersion,omitzero
diff --git a/docs/content/reference/api.md b/docs/content/reference/api.md
index a8bdb5209460..18bc253ef8ab 100644
--- a/docs/content/reference/api.md
+++ b/docs/content/reference/api.md
@@ -6102,6 +6102,14 @@ A failure here may require external user intervention to resolve.
supported by the underlying management cluster.
A failure here is unlikely to resolve without the changing user input.
"ValidHostedClusterStatus"
ValidHostedClusterStatus indicates whether status information propagated +from the hosted cluster (e.g. ConsoleURL from the console operator) is +valid and was accepted. A False value means the hosted cluster reported +data that could not be propagated — for example, a ConsoleURL that +exceeds the maximum allowed length. This condition is set by HCCO and +bubbled up to the HostedCluster.
+"ValidHostedControlPlaneConfiguration"
ValidHostedControlPlaneConfiguration bubbles up the same condition from HCP. It signals if the hostedControlPlane input is valid and supported by the underlying management cluster. @@ -9693,6 +9701,20 @@ This is populated after the infrastructure is ready.
consoleURL
+
+string
+
+consoleURL is the URL of the OpenShift web console for this hosted cluster. +This is populated from the console.config.openshift.io/cluster resource +in the guest cluster once the console operator has reconciled.
+payloadArch
@@ -10389,6 +10411,20 @@ This is populated after the infrastructure is ready.
consoleURL
+
+string
+
+consoleURL is the URL of the OpenShift web console for this hosted cluster. +This is populated from the console.config.openshift.io/cluster resource +in the guest cluster once the console operator has reconciled.
+controlPlaneVersion,omitzero
diff --git a/hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go b/hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
index 803d803df0a9..2d798c41a351 100644
--- a/hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
+++ b/hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
@@ -831,6 +831,8 @@ func (r *HostedClusterReconciler) reconcile(ctx context.Context, req ctrl.Reques
hyperv1.DataPlaneConnectionAvailable,
hyperv1.ControlPlaneConnectionAvailable,
hyperv1.EtcdBackupSucceeded,
+ hyperv1.ConfigOperatorReconciliationSucceeded,
+ hyperv1.ValidHostedClusterStatus,
}
for _, conditionType := range hcpConditions {
@@ -1143,6 +1145,7 @@ func (r *HostedClusterReconciler) reconcile(ctx context.Context, req ctrl.Reques
hcluster.Status.ControlPlaneEndpoint.Port = 443
}
hcluster.Status.OAuthCallbackURLTemplate = hcp.Status.OAuthCallbackURLTemplate
+ hcluster.Status.ConsoleURL = hcp.Status.ConsoleURL
}
}
diff --git a/support/capabilities/hosted_control_plane_capabilities.go b/support/capabilities/hosted_control_plane_capabilities.go
index a5e34a6124d6..a7f539ba8f01 100644
--- a/support/capabilities/hosted_control_plane_capabilities.go
+++ b/support/capabilities/hosted_control_plane_capabilities.go
@@ -37,6 +37,19 @@ func IsIngressCapabilityEnabled(capabilities *hyperv1.Capabilities) bool {
return true
}
+// IsConsoleCapabilityEnabled returns true if the Console capability is enabled, or false if disabled.
+func IsConsoleCapabilityEnabled(capabilities *hyperv1.Capabilities) bool {
+ if capabilities == nil {
+ return true
+ }
+ for _, disabledCap := range capabilities.Disabled {
+ if disabledCap == hyperv1.ConsoleCapability {
+ return false
+ }
+ }
+ return true
+}
+
// HasDisabledCapabilities returns true if any capabilities are disabled; otherwise, it returns false.
func HasDisabledCapabilities(capabilities *hyperv1.Capabilities) bool {
if capabilities == nil {
diff --git a/support/capabilities/hosted_control_plane_capabilities_test.go b/support/capabilities/hosted_control_plane_capabilities_test.go
index f31ddbb90cd3..9d5053dc52a2 100644
--- a/support/capabilities/hosted_control_plane_capabilities_test.go
+++ b/support/capabilities/hosted_control_plane_capabilities_test.go
@@ -148,6 +148,53 @@ func TestCalculateEnabledCapabilities(t *testing.T) {
}
}
+func TestIsConsoleCapabilityEnabled(t *testing.T) {
+ tests := []struct {
+ name string
+ capabilities *hyperv1.Capabilities
+ expectResult bool
+ }{
+ {
+ name: "When capabilities is nil, it should return true",
+ capabilities: nil,
+ expectResult: true,
+ },
+ {
+ name: "When Console is not in the disabled list, it should return true",
+ capabilities: &hyperv1.Capabilities{
+ Disabled: []hyperv1.OptionalCapability{hyperv1.NodeTuningCapability},
+ },
+ expectResult: true,
+ },
+ {
+ name: "When Console is explicitly disabled, it should return false",
+ capabilities: &hyperv1.Capabilities{
+ Disabled: []hyperv1.OptionalCapability{hyperv1.ConsoleCapability},
+ },
+ expectResult: false,
+ },
+ {
+ name: "When Console is enabled and not disabled, it should return true",
+ capabilities: &hyperv1.Capabilities{
+ Enabled: []hyperv1.OptionalCapability{hyperv1.ConsoleCapability},
+ },
+ expectResult: true,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ result := IsConsoleCapabilityEnabled(test.capabilities)
+ if test.expectResult && !result {
+ t.Fatal("expected Console capability to be enabled, but it wasn't")
+ }
+ if !test.expectResult && result {
+ t.Fatal("expected Console capability to be disabled, but it wasn't")
+ }
+ })
+ }
+}
+
func TestHasDisabledCapabilities(t *testing.T) {
tests := []struct {
name string
diff --git a/support/conditions/conditions.go b/support/conditions/conditions.go
index 4378888fcb94..7c77bdf9ffd5 100644
--- a/support/conditions/conditions.go
+++ b/support/conditions/conditions.go
@@ -11,24 +11,26 @@ import (
func ExpectedHCConditions(hostedCluster *hyperv1.HostedCluster) map[hyperv1.ConditionType]metav1.ConditionStatus {
conditions := map[hyperv1.ConditionType]metav1.ConditionStatus{
- hyperv1.HostedClusterAvailable: metav1.ConditionTrue,
- hyperv1.InfrastructureReady: metav1.ConditionTrue,
- hyperv1.KubeAPIServerAvailable: metav1.ConditionTrue,
- hyperv1.IgnitionEndpointAvailable: metav1.ConditionTrue,
- hyperv1.EtcdAvailable: metav1.ConditionTrue,
- hyperv1.ValidReleaseInfo: metav1.ConditionTrue,
- hyperv1.ValidHostedClusterConfiguration: metav1.ConditionTrue,
- hyperv1.SupportedHostedCluster: metav1.ConditionTrue,
- hyperv1.ClusterVersionSucceeding: metav1.ConditionTrue,
- hyperv1.ClusterVersionAvailable: metav1.ConditionTrue,
- hyperv1.ClusterVersionReleaseAccepted: metav1.ConditionTrue,
- hyperv1.ReconciliationActive: metav1.ConditionTrue,
- hyperv1.ReconciliationSucceeded: metav1.ConditionTrue,
- hyperv1.ValidHostedControlPlaneConfiguration: metav1.ConditionTrue,
- hyperv1.ValidReleaseImage: metav1.ConditionTrue,
- hyperv1.PlatformCredentialsFound: metav1.ConditionTrue,
- hyperv1.DataPlaneConnectionAvailable: metav1.ConditionTrue,
- hyperv1.ControlPlaneConnectionAvailable: metav1.ConditionTrue,
+ hyperv1.HostedClusterAvailable: metav1.ConditionTrue,
+ hyperv1.InfrastructureReady: metav1.ConditionTrue,
+ hyperv1.KubeAPIServerAvailable: metav1.ConditionTrue,
+ hyperv1.IgnitionEndpointAvailable: metav1.ConditionTrue,
+ hyperv1.EtcdAvailable: metav1.ConditionTrue,
+ hyperv1.ValidReleaseInfo: metav1.ConditionTrue,
+ hyperv1.ValidHostedClusterConfiguration: metav1.ConditionTrue,
+ hyperv1.SupportedHostedCluster: metav1.ConditionTrue,
+ hyperv1.ClusterVersionSucceeding: metav1.ConditionTrue,
+ hyperv1.ClusterVersionAvailable: metav1.ConditionTrue,
+ hyperv1.ClusterVersionReleaseAccepted: metav1.ConditionTrue,
+ hyperv1.ReconciliationActive: metav1.ConditionTrue,
+ hyperv1.ReconciliationSucceeded: metav1.ConditionTrue,
+ hyperv1.ConfigOperatorReconciliationSucceeded: metav1.ConditionTrue,
+ hyperv1.ValidHostedControlPlaneConfiguration: metav1.ConditionTrue,
+ hyperv1.ValidHostedClusterStatus: metav1.ConditionTrue,
+ hyperv1.ValidReleaseImage: metav1.ConditionTrue,
+ hyperv1.PlatformCredentialsFound: metav1.ConditionTrue,
+ hyperv1.DataPlaneConnectionAvailable: metav1.ConditionTrue,
+ hyperv1.ControlPlaneConnectionAvailable: metav1.ConditionTrue,
hyperv1.HostedClusterProgressing: metav1.ConditionFalse,
hyperv1.HostedClusterDegraded: metav1.ConditionFalse,
diff --git a/test/e2e/util/util.go b/test/e2e/util/util.go
index 1881dce3fbc5..9e8a85548787 100644
--- a/test/e2e/util/util.go
+++ b/test/e2e/util/util.go
@@ -3001,6 +3001,25 @@ func ValidateHostedClusterConditions(t *testing.T, ctx context.Context, client c
delete(expectedConditions, hyperv1.ControlPlaneConnectionAvailable)
}
+ if IsLessThan(Version422) {
+ delete(expectedConditions, hyperv1.ConfigOperatorReconciliationSucceeded)
+ }
+
+ // Exclude ConfigOperatorReconciliationSucceeded during upgrade tests as the condition
+ // may not be present in all builds during the upgrade window.
+ if upgradeContext != nil {
+ delete(expectedConditions, hyperv1.ConfigOperatorReconciliationSucceeded)
+ }
+
+ if IsLessThan(Version422) {
+ delete(expectedConditions, hyperv1.ValidHostedClusterStatus)
+ }
+ // Exclude ValidHostedClusterStatus during upgrade tests as the old HCCO
+ // won't set this condition, causing the HC controller to synthesize Unknown.
+ if upgradeContext != nil {
+ delete(expectedConditions, hyperv1.ValidHostedClusterStatus)
+ }
+
var predicates []Predicate[*hyperv1.HostedCluster]
for conditionType, conditionStatus := range expectedConditions {
predicates = append(predicates, ConditionPredicate[*hyperv1.HostedCluster](Condition{
diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hosted_controlplane.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hosted_controlplane.go
index cb618ee4b09a..9d91e15ce1fe 100644
--- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hosted_controlplane.go
+++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hosted_controlplane.go
@@ -354,6 +354,15 @@ type HostedControlPlaneStatus struct {
// +kubebuilder:validation:MaxLength=255
OAuthCallbackURLTemplate string `json:"oauthCallbackURLTemplate,omitempty"`
+ // consoleURL is the URL of the OpenShift web console for this hosted cluster.
+ // This is populated from the console.config.openshift.io/cluster resource
+ // in the guest cluster once the console operator has reconciled.
+ // +optional
+ // +kubebuilder:validation:MinLength=1
+ // +kubebuilder:validation:MaxLength=4096
+ // +kubebuilder:validation:XValidation:rule="isURL(self)",message="consoleURL must be a valid URL"
+ ConsoleURL string `json:"consoleURL,omitempty"`
+
// controlPlaneVersion tracks the rollout status of the control plane
// components running on the management cluster, independently from
// the data-plane version reported in the version field.
diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go
index d34661d773ea..6e820226af6b 100644
--- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go
+++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_conditions.go
@@ -191,6 +191,22 @@ const (
// A failure here often means a software bug or a non-stable cluster.
ReconciliationSucceeded ConditionType = "ReconciliationSucceeded"
+ // ConfigOperatorReconciliationSucceeded indicates if the HostedCluster Config
+ // Operator (HCCO) reconciliation succeeded. The HCCO is responsible for
+ // reconciling resources inside the hosted cluster (e.g. global configuration,
+ // CRDs, RBAC, and connectivity checks).
+ // A failure here often means a software bug, a non-stable cluster, or
+ // connectivity issues between the control plane and the hosted cluster.
+ ConfigOperatorReconciliationSucceeded ConditionType = "ConfigOperatorReconciliationSucceeded"
+
+ // ValidHostedClusterStatus indicates whether status information propagated
+ // from the hosted cluster (e.g. ConsoleURL from the console operator) is
+ // valid and was accepted. A False value means the hosted cluster reported
+ // data that could not be propagated — for example, a ConsoleURL that
+ // exceeds the maximum allowed length. This condition is set by HCCO and
+ // bubbled up to the HostedCluster.
+ ValidHostedClusterStatus ConditionType = "ValidHostedClusterStatus"
+
// EtcdRecoveryActive indicates that the Etcd cluster is failing and the
// recovery job was triggered.
EtcdRecoveryActive ConditionType = "EtcdRecoveryActive"
@@ -324,6 +340,8 @@ const (
ControlPlaneConnectionNoWorkerNodesAvailableReason = "NoWorkerNodesAvailable"
+ InvalidHostedClusterStatusReason = "InvalidHostedClusterStatus"
+
ControlPlaneComponentsNotAvailable = "ComponentsNotAvailable"
AutoNodeNotConfiguredReason = "AutoNodeNotConfigured"
diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go
index ce0ecaf81ee5..8ecdf3e63cb2 100644
--- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go
+++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go
@@ -2302,6 +2302,15 @@ type HostedClusterStatus struct {
// +kubebuilder:validation:MaxLength=1024
OAuthCallbackURLTemplate string `json:"oauthCallbackURLTemplate,omitempty"`
+ // consoleURL is the URL of the OpenShift web console for this hosted cluster.
+ // This is populated from the console.config.openshift.io/cluster resource
+ // in the guest cluster once the console operator has reconciled.
+ // +optional
+ // +kubebuilder:validation:MinLength=1
+ // +kubebuilder:validation:MaxLength=4096
+ // +kubebuilder:validation:XValidation:rule="isURL(self)",message="consoleURL must be a valid URL"
+ ConsoleURL string `json:"consoleURL,omitempty"`
+
// payloadArch represents the CPU architecture type of the HostedCluster.Spec.Release.Image. The valid values are:
// Multi, ARM64, AMD64, S390X, or PPC64LE.
// +kubebuilder:validation:Enum=Multi;ARM64;AMD64;PPC64LE;S390X