diff --git a/api/.golangci.yml b/api/.golangci.yml index 6a6b91242230..5a49711b4b23 100644 --- a/api/.golangci.yml +++ b/api/.golangci.yml @@ -120,6 +120,10 @@ linters: - kubeapilinter path: hypershift/v1beta1/hosted_controlplane.go text: 'nobools: field HostedControlPlaneStatus.Initialized should not use a bool. Use a string type with meaningful constant values as an enum.' + - linters: + - kubeapilinter + path: hypershift/v1beta1/hosted_controlplane.go + text: 'nobools: field HostedControlPlaneInitializationStatus.ControlPlaneInitialized pointer should not use a bool. Use a string type with meaningful constant values as an enum.' - linters: - kubeapilinter path: hypershift/v1beta1/hosted_controlplane.go diff --git a/api/hypershift/v1beta1/hosted_controlplane.go b/api/hypershift/v1beta1/hosted_controlplane.go index 8486514f0a18..cfc63ec4be22 100644 --- a/api/hypershift/v1beta1/hosted_controlplane.go +++ b/api/hypershift/v1beta1/hosted_controlplane.go @@ -419,6 +419,26 @@ type HostedControlPlaneStatus struct { // configuration contains the cluster configuration status of the HostedCluster // +optional Configuration *ConfigurationStatus `json:"configuration,omitempty"` + + // initialization contains fields that track the status of the initialization of the HostedControlPlane. + // This satisfies the CAPI v1beta2 ControlPlane provider contract: + // https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + // +optional + Initialization HostedControlPlaneInitializationStatus `json:"initialization,omitzero"` +} + +// HostedControlPlaneInitializationStatus provides observations of the HostedControlPlane initialization process. +// This satisfies the CAPI v1beta2 ControlPlane provider contract: +// https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1361-L1379 +// +kubebuilder:validation:MinProperties=1 +type HostedControlPlaneInitializationStatus struct { + // controlPlaneInitialized is true when the control plane is functional enough to accept requests. + // Once this condition is marked true, its value is never changed. See the Ready condition for an + // indication of the current readiness of the cluster's control plane. + // This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + // +optional + // +default=false + ControlPlaneInitialized *bool `json:"controlPlaneInitialized,omitempty"` } // APIEndpoint represents a reachable Kubernetes API endpoint. diff --git a/api/hypershift/v1beta1/zz_generated.deepcopy.go b/api/hypershift/v1beta1/zz_generated.deepcopy.go index 454f86378499..b9e2e2546e76 100644 --- a/api/hypershift/v1beta1/zz_generated.deepcopy.go +++ b/api/hypershift/v1beta1/zz_generated.deepcopy.go @@ -2500,6 +2500,26 @@ func (in *HostedControlPlane) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HostedControlPlaneInitializationStatus) DeepCopyInto(out *HostedControlPlaneInitializationStatus) { + *out = *in + if in.ControlPlaneInitialized != nil { + in, out := &in.ControlPlaneInitialized, &out.ControlPlaneInitialized + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostedControlPlaneInitializationStatus. +func (in *HostedControlPlaneInitializationStatus) DeepCopy() *HostedControlPlaneInitializationStatus { + if in == nil { + return nil + } + out := new(HostedControlPlaneInitializationStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HostedControlPlaneList) DeepCopyInto(out *HostedControlPlaneList) { *out = *in @@ -2697,6 +2717,7 @@ func (in *HostedControlPlaneStatus) DeepCopyInto(out *HostedControlPlaneStatus) *out = new(ConfigurationStatus) (*in).DeepCopyInto(*out) } + in.Initialization.DeepCopyInto(&out.Initialization) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostedControlPlaneStatus. 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 7faf853bd178..11869d3fd5ad 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 @@ -6746,6 +6746,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- 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 927f2b9ffc23..6b93ee2982d7 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 @@ -6729,6 +6729,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- 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 ad6e7742c0ec..0d299a8b05c7 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 @@ -6749,6 +6749,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- 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 1b9da7de5255..78b34729216c 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 @@ -7226,6 +7226,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- 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 3cd3503473be..1a772a81e2a9 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 @@ -7366,6 +7366,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- 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 9d7a73cb3bf0..0aa0b956f691 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 @@ -7192,6 +7192,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- 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 1527b355549f..e35cffdbe686 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 @@ -7175,6 +7175,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- 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 36a11500968d..1cf8c9d0ea04 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 @@ -6794,6 +6794,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- 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 5ea38844b584..9ae07cbe4cac 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 @@ -6751,6 +6751,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- 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 9de4ad90ead5..736ab6e3fcbf 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 @@ -6758,6 +6758,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- 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 db3f3840a8c2..b56c1afe2f35 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 @@ -6805,6 +6805,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- 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 c3c0b64fcf23..97c22c290562 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 @@ -7280,6 +7280,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/TLSAdherence.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/TLSAdherence.yaml index e52cbe485e19..dd70f04299b8 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/TLSAdherence.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/TLSAdherence.yaml @@ -6769,6 +6769,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- diff --git a/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplaneinitializationstatus.go b/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplaneinitializationstatus.go new file mode 100644 index 000000000000..3df3d3039414 --- /dev/null +++ b/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplaneinitializationstatus.go @@ -0,0 +1,38 @@ +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1beta1 + +// HostedControlPlaneInitializationStatusApplyConfiguration represents a declarative configuration of the HostedControlPlaneInitializationStatus type for use +// with apply. +type HostedControlPlaneInitializationStatusApplyConfiguration struct { + ControlPlaneInitialized *bool `json:"controlPlaneInitialized,omitempty"` +} + +// HostedControlPlaneInitializationStatusApplyConfiguration constructs a declarative configuration of the HostedControlPlaneInitializationStatus type for use with +// apply. +func HostedControlPlaneInitializationStatus() *HostedControlPlaneInitializationStatusApplyConfiguration { + return &HostedControlPlaneInitializationStatusApplyConfiguration{} +} + +// WithControlPlaneInitialized sets the ControlPlaneInitialized 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 ControlPlaneInitialized field is set to the value of the last call. +func (b *HostedControlPlaneInitializationStatusApplyConfiguration) WithControlPlaneInitialized(value bool) *HostedControlPlaneInitializationStatusApplyConfiguration { + b.ControlPlaneInitialized = &value + return b +} diff --git a/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanestatus.go b/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanestatus.go index 3921f0dd7d99..090775246ba1 100644 --- a/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanestatus.go +++ b/client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanestatus.go @@ -26,24 +26,25 @@ import ( // HostedControlPlaneStatusApplyConfiguration represents a declarative configuration of the HostedControlPlaneStatus type for use // with apply. type HostedControlPlaneStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - Ready *bool `json:"ready,omitempty"` - Initialized *bool `json:"initialized,omitempty"` - ExternalManagedControlPlane *bool `json:"externalManagedControlPlane,omitempty"` - ControlPlaneEndpoint *APIEndpointApplyConfiguration `json:"controlPlaneEndpoint,omitempty"` - OAuthCallbackURLTemplate *string `json:"oauthCallbackURLTemplate,omitempty"` - ControlPlaneVersion *ControlPlaneVersionStatusApplyConfiguration `json:"controlPlaneVersion,omitempty"` - VersionStatus *ClusterVersionStatusApplyConfiguration `json:"versionStatus,omitempty"` - Version *string `json:"version,omitempty"` - ReleaseImage *string `json:"releaseImage,omitempty"` - LastReleaseImageTransitionTime *metav1.Time `json:"lastReleaseImageTransitionTime,omitempty"` - KubeConfig *KubeconfigSecretRefApplyConfiguration `json:"kubeConfig,omitempty"` - CustomKubeconfig *KubeconfigSecretRefApplyConfiguration `json:"customKubeconfig,omitempty"` - KubeadminPassword *corev1.LocalObjectReference `json:"kubeadminPassword,omitempty"` - Platform *PlatformStatusApplyConfiguration `json:"platform,omitempty"` - NodeCount *int `json:"nodeCount,omitempty"` - AutoNode *AutoNodeStatusApplyConfiguration `json:"autoNode,omitempty"` - Configuration *ConfigurationStatusApplyConfiguration `json:"configuration,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + Ready *bool `json:"ready,omitempty"` + Initialized *bool `json:"initialized,omitempty"` + ExternalManagedControlPlane *bool `json:"externalManagedControlPlane,omitempty"` + ControlPlaneEndpoint *APIEndpointApplyConfiguration `json:"controlPlaneEndpoint,omitempty"` + OAuthCallbackURLTemplate *string `json:"oauthCallbackURLTemplate,omitempty"` + ControlPlaneVersion *ControlPlaneVersionStatusApplyConfiguration `json:"controlPlaneVersion,omitempty"` + VersionStatus *ClusterVersionStatusApplyConfiguration `json:"versionStatus,omitempty"` + Version *string `json:"version,omitempty"` + ReleaseImage *string `json:"releaseImage,omitempty"` + LastReleaseImageTransitionTime *metav1.Time `json:"lastReleaseImageTransitionTime,omitempty"` + KubeConfig *KubeconfigSecretRefApplyConfiguration `json:"kubeConfig,omitempty"` + CustomKubeconfig *KubeconfigSecretRefApplyConfiguration `json:"customKubeconfig,omitempty"` + KubeadminPassword *corev1.LocalObjectReference `json:"kubeadminPassword,omitempty"` + Platform *PlatformStatusApplyConfiguration `json:"platform,omitempty"` + NodeCount *int `json:"nodeCount,omitempty"` + AutoNode *AutoNodeStatusApplyConfiguration `json:"autoNode,omitempty"` + Configuration *ConfigurationStatusApplyConfiguration `json:"configuration,omitempty"` + Initialization *HostedControlPlaneInitializationStatusApplyConfiguration `json:"initialization,omitempty"` } // HostedControlPlaneStatusApplyConfiguration constructs a declarative configuration of the HostedControlPlaneStatus type for use with @@ -200,3 +201,11 @@ func (b *HostedControlPlaneStatusApplyConfiguration) WithConfiguration(value *Co b.Configuration = value return b } + +// WithInitialization sets the Initialization 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 Initialization field is set to the value of the last call. +func (b *HostedControlPlaneStatusApplyConfiguration) WithInitialization(value *HostedControlPlaneInitializationStatusApplyConfiguration) *HostedControlPlaneStatusApplyConfiguration { + b.Initialization = value + return b +} diff --git a/client/applyconfiguration/utils.go b/client/applyconfiguration/utils.go index 5464e88f8024..231d2ff71112 100644 --- a/client/applyconfiguration/utils.go +++ b/client/applyconfiguration/utils.go @@ -241,6 +241,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &hypershiftv1beta1.HostedClusterStatusApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("HostedControlPlane"): return &hypershiftv1beta1.HostedControlPlaneApplyConfiguration{} + case v1beta1.SchemeGroupVersion.WithKind("HostedControlPlaneInitializationStatus"): + return &hypershiftv1beta1.HostedControlPlaneInitializationStatusApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("HostedControlPlaneSpec"): return &hypershiftv1beta1.HostedControlPlaneSpecApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("HostedControlPlaneStatus"): diff --git a/cmd/cluster/core/dump.go b/cmd/cluster/core/dump.go index 5c5536954787..d7a5e7148c52 100644 --- a/cmd/cluster/core/dump.go +++ b/cmd/cluster/core/dump.go @@ -56,7 +56,7 @@ import ( capikubevirt "sigs.k8s.io/cluster-api-provider-kubevirt/api/v1alpha1" capiopenstackv1alpha1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha1" capiopenstackv1beta1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" karpenterv1 "sigs.k8s.io/karpenter/pkg/apis/v1" secretsstorev1 "sigs.k8s.io/secrets-store-csi-driver/apis/v1" 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 798d4f0664f8..d41d1d84459d 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 @@ -8743,6 +8743,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- 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 5fd583a45ffa..1724b36a9183 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 @@ -7403,6 +7403,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- 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 25068f5cf7f6..7b965b426a44 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 @@ -8603,6 +8603,22 @@ spec: is managed by an external service. https://github.com/kubernetes-sigs/cluster-api/blob/65e5385bffd71bf4aad3cf34a537f11b217c7fab/controllers/machine_controller.go#L468 type: boolean + initialization: + description: |- + initialization contains fields that track the status of the initialization of the HostedControlPlane. + This satisfies the CAPI v1beta2 ControlPlane provider contract: + https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + minProperties: 1 + properties: + controlPlaneInitialized: + default: false + description: |- + controlPlaneInitialized is true when the control plane is functional enough to accept requests. + Once this condition is marked true, its value is never changed. See the Ready condition for an + indication of the current readiness of the cluster's control plane. + This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + type: boolean + type: object initialized: default: false description: |- diff --git a/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go b/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go index 5861a1fda10d..69a848bbec04 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go +++ b/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go @@ -236,7 +236,6 @@ func (r *HostedControlPlaneReconciler) SetupWithManager(mgr ctrl.Manager, create } func (r *HostedControlPlaneReconciler) registerComponents(hcp *hyperv1.HostedControlPlane) { - r.components = append(r.components, pkioperatorv2.NewComponent(r.CertRotationScale), etcdv2.NewComponent(), @@ -679,6 +678,11 @@ func (r *HostedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R hostedControlPlane.Status.Initialized = true + // Set status.initialization.controlPlaneInitialized for CAPI 1.11 v1beta2 contract. + // CAPI reads this field from the ControlPlane provider object to determine if the + // control plane is initialized (ControlPlaneInitialized condition on the CAPI Cluster). + hostedControlPlane.Status.Initialization.ControlPlaneInitialized = ptr.To(true) + meta.SetStatusCondition(&hostedControlPlane.Status.Conditions, util.GenerateReconciliationActiveCondition(hostedControlPlane.Spec.PausedUntil, hostedControlPlane.Generation)) // Always update status based on the current state of the world. if err := r.Client.Status().Patch(ctx, hostedControlPlane, client.MergeFromWithOptions(originalHostedControlPlane, client.MergeFromWithOptimisticLock{})); err != nil { diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/kas/kubeconfig.go b/control-plane-operator/controllers/hostedcontrolplane/v2/kas/kubeconfig.go index 91baf82a8bea..c42acf71c166 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/kas/kubeconfig.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/kas/kubeconfig.go @@ -18,7 +18,7 @@ import ( clientcmd "k8s.io/client-go/tools/clientcmd" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" ) diff --git a/control-plane-operator/hostedclusterconfigoperator/api/scheme.go b/control-plane-operator/hostedclusterconfigoperator/api/scheme.go index e45e1efcc4a9..dd7fd922de5e 100644 --- a/control-plane-operator/hostedclusterconfigoperator/api/scheme.go +++ b/control-plane-operator/hostedclusterconfigoperator/api/scheme.go @@ -26,7 +26,7 @@ import ( clientgoscheme "k8s.io/client-go/kubernetes/scheme" apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" snapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v6/apis/volumesnapshot/v1" operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps_test.go b/control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps_test.go index e544a4533136..7e9ee0528ee8 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps_test.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps_test.go @@ -16,7 +16,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" ) @@ -82,7 +82,7 @@ func TestReconcileGlobalPullSecret(t *testing.T) { Labels: map[string]string{"machineset": "test"}, }, Status: capiv1.MachineStatus{ - NodeRef: &corev1.ObjectReference{Name: "test-node-1"}, + NodeRef: capiv1.MachineNodeReference{Name: "test-node-1"}, }, }, }, @@ -156,7 +156,7 @@ func TestReconcileGlobalPullSecret(t *testing.T) { Labels: map[string]string{"machineset": "test"}, }, Status: capiv1.MachineStatus{ - NodeRef: &corev1.ObjectReference{Name: "test-node-1"}, + NodeRef: capiv1.MachineNodeReference{Name: "test-node-1"}, }, }, }, @@ -273,7 +273,7 @@ func TestReconcileGlobalPullSecret(t *testing.T) { Labels: map[string]string{"machineset": "test"}, }, Status: capiv1.MachineStatus{ - NodeRef: &corev1.ObjectReference{Name: "test-node-1"}, + NodeRef: capiv1.MachineNodeReference{Name: "test-node-1"}, }, }, }, @@ -325,7 +325,7 @@ func TestReconcileGlobalPullSecret(t *testing.T) { Labels: map[string]string{"machineset": "inplace"}, }, Status: capiv1.MachineStatus{ - NodeRef: &corev1.ObjectReference{Name: "inplace-node-1"}, + NodeRef: capiv1.MachineNodeReference{Name: "inplace-node-1"}, }, }, }, diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader.go b/control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader.go index b633420098a0..1b8b7df013a2 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader.go @@ -21,7 +21,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/utils/ptr" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -690,7 +690,7 @@ func getNodesForMachineSet(ctx context.Context, c client.Reader, hostedClusterCl var nodes []*corev1.Node nodeToMachine := make(map[string]*capiv1.Machine) for i, machine := range machineSetOwnedMachines { - if machine.Status.NodeRef != nil { + if machine.Status.NodeRef.IsDefined() { node := &corev1.Node{} if err := hostedClusterClient.Get(ctx, client.ObjectKey{Name: machine.Status.NodeRef.Name}, node); err != nil { return nil, nil, fmt.Errorf("error getting node: %w", err) diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader_test.go b/control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader_test.go index b5f9ec3f116c..e7dd0869558c 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader_test.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader_test.go @@ -23,7 +23,7 @@ import ( "k8s.io/client-go/kubernetes/scheme" "k8s.io/utils/ptr" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/client/interceptor" @@ -66,7 +66,7 @@ func TestGetNodesForMachineSet(t *testing.T) { Labels: selector, }, Status: capiv1.MachineStatus{ - NodeRef: &corev1.ObjectReference{ + NodeRef: capiv1.MachineNodeReference{ Name: "test", }, }, @@ -85,7 +85,7 @@ func TestGetNodesForMachineSet(t *testing.T) { Labels: selector, }, Status: capiv1.MachineStatus{ - NodeRef: &corev1.ObjectReference{ + NodeRef: capiv1.MachineNodeReference{ Name: "otherOwner", }, }, @@ -106,7 +106,7 @@ func TestGetNodesForMachineSet(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - NodeRef: &corev1.ObjectReference{ + NodeRef: capiv1.MachineNodeReference{ Name: "otherSelector", }, }, @@ -877,7 +877,7 @@ func TestReconcileInPlaceUpgradeAnnotatesMachineWithNodePoolVersion(t *testing.T }, }, Status: capiv1.MachineStatus{ - NodeRef: &corev1.ObjectReference{Name: "test-node"}, + NodeRef: capiv1.MachineNodeReference{Name: "test-node"}, }, } @@ -897,7 +897,7 @@ func TestReconcileInPlaceUpgradeAnnotatesMachineWithNodePoolVersion(t *testing.T }, }, Status: capiv1.MachineStatus{ - NodeRef: &corev1.ObjectReference{Name: "upgrading-node"}, + NodeRef: capiv1.MachineNodeReference{Name: "upgrading-node"}, }, } @@ -1043,7 +1043,7 @@ func TestReconcileInPlaceUpgradeDegradedNodeErrorMessage(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - NodeRef: &corev1.ObjectReference{Name: tc.nodeName}, + NodeRef: capiv1.MachineNodeReference{Name: tc.nodeName}, }, } @@ -1186,7 +1186,7 @@ func TestReconcileReturnsRequeueAfterDuringUpgrade(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - NodeRef: &corev1.ObjectReference{Name: "test-node"}, + NodeRef: capiv1.MachineNodeReference{Name: "test-node"}, }, } diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/setup.go b/control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/setup.go index 4be8a2dd110c..7db84b423a93 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/setup.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/setup.go @@ -8,7 +8,7 @@ import ( corev1 "k8s.io/api/core/v1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/handler" diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go b/control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go index 281d87dee56a..121cc1668ff5 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go @@ -18,7 +18,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/utils/ptr" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine_test.go b/control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine_test.go index f9518457229b..878f4a39d369 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine_test.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine_test.go @@ -17,7 +17,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -98,7 +98,7 @@ func TestReconcileDefaultIngressEndpoints(t *testing.T) { TypeMeta: machineTypeMeta, ObjectMeta: worker1Meta, Spec: capiv1.MachineSpec{ - InfrastructureRef: corev1.ObjectReference{ + InfrastructureRef: capiv1.ContractVersionedObjectReference{ Name: vmWorker1Meta.Name, }, }, @@ -120,7 +120,7 @@ func TestReconcileDefaultIngressEndpoints(t *testing.T) { TypeMeta: machineTypeMeta, ObjectMeta: worker2Meta, Spec: capiv1.MachineSpec{ - InfrastructureRef: corev1.ObjectReference{ + InfrastructureRef: capiv1.ContractVersionedObjectReference{ Name: vmWorker2Meta.Name, }, }, @@ -388,7 +388,7 @@ func TestReconcileDefaultIngressEndpoints(t *testing.T) { TypeMeta: machineTypeMeta, ObjectMeta: worker1Meta, Spec: capiv1.MachineSpec{ - InfrastructureRef: corev1.ObjectReference{ + InfrastructureRef: capiv1.ContractVersionedObjectReference{ Name: vmWorker1Meta.Name, }, }, @@ -406,7 +406,7 @@ func TestReconcileDefaultIngressEndpoints(t *testing.T) { TypeMeta: machineTypeMeta, ObjectMeta: worker2Meta, Spec: capiv1.MachineSpec{ - InfrastructureRef: corev1.ObjectReference{ + InfrastructureRef: capiv1.ContractVersionedObjectReference{ Name: vmWorker2Meta.Name, }, }, @@ -465,7 +465,7 @@ func TestReconcileDefaultIngressEndpoints(t *testing.T) { }, { name: "With Failing machine with internal addresses and passthrow service should mark endpointslices as not ready/not serving", - machines: pairOfDualStackMachines(capiv1.MachinePhaseRunning, capiv1.MachinePhaseFailed), + machines: pairOfDualStackMachines(capiv1.MachinePhaseRunning, capiv1.MachinePhaseDeleting), virtualMachines: pairOfVirtualMachines, services: []corev1.Service{defaultIngressService}, expectedServices: []corev1.Service{defaultIngressService}, diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/machine/setup.go b/control-plane-operator/hostedclusterconfigoperator/controllers/machine/setup.go index 03a6fd056368..74bb1d0a09ad 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/machine/setup.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/machine/setup.go @@ -14,7 +14,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/rest" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/node/node.go b/control-plane-operator/hostedclusterconfigoperator/controllers/node/node.go index 0b5890570824..fa127dba0b26 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/node/node.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/node/node.go @@ -15,7 +15,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/node/node_test.go b/control-plane-operator/hostedclusterconfigoperator/controllers/node/node_test.go index 0578ec66c16f..2a8c1e7fd4b5 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/node/node_test.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/node/node_test.go @@ -11,7 +11,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/scheme" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client/fake" ) diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation/spotremediation.go b/control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation/spotremediation.go index fd096d21af1b..55a22c4fab43 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation/spotremediation.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation/spotremediation.go @@ -9,7 +9,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation/spotremediation_test.go b/control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation/spotremediation_test.go index 84c4f58dbe7a..6e569faa4f57 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation/spotremediation_test.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation/spotremediation_test.go @@ -12,7 +12,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" diff --git a/docs/content/reference/aggregated-docs.md b/docs/content/reference/aggregated-docs.md index d70c1b359e8d..f6f3e64d2acd 100644 --- a/docs/content/reference/aggregated-docs.md +++ b/docs/content/reference/aggregated-docs.md @@ -45315,6 +45315,41 @@ are ephemeral and may be deleted by retention policies.

+###HostedControlPlaneInitializationStatus { #hypershift.openshift.io/v1beta1.HostedControlPlaneInitializationStatus } +

+(Appears on: +HostedControlPlaneStatus) +

+

+

HostedControlPlaneInitializationStatus provides observations of the HostedControlPlane initialization process. +This satisfies the CAPI v1beta2 ControlPlane provider contract: +https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1361-L1379

+

+ + + + + + + + + + + + + +
FieldDescription
+controlPlaneInitialized
+ +bool + +
+(Optional) +

controlPlaneInitialized is true when the control plane is functional enough to accept requests. +Once this condition is marked true, its value is never changed. See the Ready condition for an +indication of the current readiness of the cluster’s control plane. +This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379

+
###HostedControlPlaneSpec { #hypershift.openshift.io/v1beta1.HostedControlPlaneSpec }

HostedControlPlaneSpec defines the desired state of HostedControlPlane

@@ -46101,6 +46136,22 @@ ConfigurationStatus

configuration contains the cluster configuration status of the HostedCluster

+ + +initialization,omitzero
+ + +HostedControlPlaneInitializationStatus + + + + +(Optional) +

initialization contains fields that track the status of the initialization of the HostedControlPlane. +This satisfies the CAPI v1beta2 ControlPlane provider contract: +https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379

+ + ###IBMCloudKMSAuthSpec { #hypershift.openshift.io/v1beta1.IBMCloudKMSAuthSpec } diff --git a/docs/content/reference/api.md b/docs/content/reference/api.md index fb4fb96c1b20..62080699471e 100644 --- a/docs/content/reference/api.md +++ b/docs/content/reference/api.md @@ -9630,6 +9630,41 @@ are ephemeral and may be deleted by retention policies.

+###HostedControlPlaneInitializationStatus { #hypershift.openshift.io/v1beta1.HostedControlPlaneInitializationStatus } +

+(Appears on: +HostedControlPlaneStatus) +

+

+

HostedControlPlaneInitializationStatus provides observations of the HostedControlPlane initialization process. +This satisfies the CAPI v1beta2 ControlPlane provider contract: +https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1361-L1379

+

+ + + + + + + + + + + + + +
FieldDescription
+controlPlaneInitialized
+ +bool + +
+(Optional) +

controlPlaneInitialized is true when the control plane is functional enough to accept requests. +Once this condition is marked true, its value is never changed. See the Ready condition for an +indication of the current readiness of the cluster’s control plane. +This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379

+
###HostedControlPlaneSpec { #hypershift.openshift.io/v1beta1.HostedControlPlaneSpec }

HostedControlPlaneSpec defines the desired state of HostedControlPlane

@@ -10416,6 +10451,22 @@ ConfigurationStatus

configuration contains the cluster configuration status of the HostedCluster

+ + +initialization,omitzero
+ + +HostedControlPlaneInitializationStatus + + + + +(Optional) +

initialization contains fields that track the status of the initialization of the HostedControlPlane. +This satisfies the CAPI v1beta2 ControlPlane provider contract: +https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379

+ + ###IBMCloudKMSAuthSpec { #hypershift.openshift.io/v1beta1.IBMCloudKMSAuthSpec } diff --git a/hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go b/hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go index f7c2deac532f..381bfd6fc297 100644 --- a/hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go +++ b/hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go @@ -100,7 +100,7 @@ import ( "k8s.io/utils/clock" "k8s.io/utils/ptr" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" @@ -1866,6 +1866,17 @@ func (r *HostedClusterReconciler) reconcile(ctx context.Context, req ctrl.Reques if err != nil { return ctrl.Result{}, fmt.Errorf("failed to reconcile capi cluster: %w", err) } + // Patch InfrastructureProvisioned on the CAPI Cluster status once infrastructure + // is confirmed ready. This is done via a dedicated Status patch (not in + // reconcileCAPICluster) to keep spec and status concerns separate. + // Gate on HCP.InfrastructureReady to match CAPI 1.10 timing where CAPA set + // AWSCluster.status.ready only after infrastructure was verified, preventing + // premature control plane convergence that breaks e2e timing assumptions. + if hcp != nil && meta.IsStatusConditionTrue(hcp.Status.Conditions, string(hyperv1.InfrastructureReady)) { + if err := patchInfrastructureInitializationProvisioned(ctx, r.Client, capiCluster); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to patch CAPI cluster InfrastructureProvisioned: %w", err) + } + } } // Reconcile the monitoring dashboard if configured @@ -2943,11 +2954,36 @@ func reconcilecontrolPlaneOperatorIngressOperatorRoleBinding(binding *rbacv1.Rol return nil } +// patchInfrastructureInitializationProvisioned sets InfrastructureProvisioned=True on +// the CAPI Cluster status via a dedicated Status patch. For externally managed infra +// (ManagedByAnnotation="external"), CAPI skips InfrastructureCluster reconciliation so +// it cannot determine infra readiness itself. HyperShift fulfills this part of the CAPI +// contract here, gated on HCP.InfrastructureReady=True. +func patchInfrastructureInitializationProvisioned(ctx context.Context, c client.Client, capiCluster *capiv1.Cluster) error { + if ptr.Deref(capiCluster.Status.Initialization.InfrastructureProvisioned, false) { + return nil + } + original := capiCluster.DeepCopy() + capiCluster.Status.Initialization.InfrastructureProvisioned = ptr.To(true) + return c.Status().Patch(ctx, capiCluster, client.MergeFrom(original)) +} + func reconcileCAPICluster(cluster *capiv1.Cluster, hcluster *hyperv1.HostedCluster, hcp *hyperv1.HostedControlPlane, infraCR client.Object) error { + // Note: InfrastructureProvisioned is NOT set here. It is managed by + // patchInfrastructureInitializationProvisioned which does a dedicated Status + // patch gated on HCP.InfrastructureReady=True. This preserves CAPI 1.10 + // timing semantics and keeps this function focused on spec-only changes. + // Note: ControlPlaneInitialized is intentionally NOT set here. CAPI's cluster + // controller will set it naturally when HCP.Status.Initialized=True (via v1beta1 + // contract reading status.initialized). This preserves CAPI 1.10 timing where + // machines were only created after the guest cluster bootstrap RBAC was set up by + // HCCO. Setting it unconditionally caused machines to boot before HCCO had finished + // configuring the guest cluster, resulting in bootstrap authentication failures. + // We only create this resource once and then let CAPI own it if !cluster.CreationTimestamp.IsZero() { // make sure cluster is not paused. - cluster.Spec.Paused = false + cluster.Spec.Paused = ptr.To(false) return nil } infraCRGVK, err := apiutil.GVKForObject(infraCR, api.Scheme) @@ -2960,17 +2996,15 @@ func reconcileCAPICluster(cluster *capiv1.Cluster, hcluster *hyperv1.HostedClust } cluster.Spec = capiv1.ClusterSpec{ ControlPlaneEndpoint: capiv1.APIEndpoint{}, - ControlPlaneRef: &corev1.ObjectReference{ - APIVersion: "hypershift.openshift.io/v1beta1", - Kind: "HostedControlPlane", - Namespace: hcp.Namespace, - Name: hcp.Name, + ControlPlaneRef: capiv1.ContractVersionedObjectReference{ + APIGroup: "hypershift.openshift.io", + Kind: "HostedControlPlane", + Name: hcp.Name, }, - InfrastructureRef: &corev1.ObjectReference{ - APIVersion: infraCRGVK.GroupVersion().String(), - Kind: infraCRGVK.Kind, - Namespace: infraCR.GetNamespace(), - Name: infraCR.GetName(), + InfrastructureRef: capiv1.ContractVersionedObjectReference{ + APIGroup: infraCRGVK.Group, + Kind: infraCRGVK.Kind, + Name: infraCR.GetName(), }, } @@ -2992,8 +3026,8 @@ func pauseCAPICluster(ctx context.Context, c client.Client, hc *hyperv1.HostedCl return nil } - if capiCluster.Spec.Paused != paused { - capiCluster.Spec.Paused = paused + if ptr.Deref(capiCluster.Spec.Paused, false) != paused { + capiCluster.Spec.Paused = ptr.To(paused) if err := c.Update(ctx, capiCluster); err != nil { return fmt.Errorf("failed to update CAPI Cluster: %w", err) } @@ -3006,7 +3040,7 @@ func reconcileCAPIManagerClusterRole(role *rbacv1.ClusterRole) error { { APIGroups: []string{"apiextensions.k8s.io"}, Resources: []string{"customresourcedefinitions"}, - Verbs: []string{"get", "list", "watch"}, + Verbs: []string{"get", "list", "patch", "watch"}, }, } return nil diff --git a/hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go b/hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go index a2bb4c590828..e7d68ea087fb 100644 --- a/hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go +++ b/hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go @@ -64,7 +64,7 @@ import ( capiaws "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" capibmv1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2" - "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" crclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -1361,12 +1361,12 @@ func TestReconcileCAPICluster(t *testing.T) { t.Parallel() testCases := []struct { name string - capiCluster *v1beta1.Cluster + capiCluster *capiv1.Cluster hostedCluster *hyperv1.HostedCluster hostedControlPlane *hyperv1.HostedControlPlane infraCR crclient.Object - expectedCAPICluster *v1beta1.Cluster + expectedCAPICluster *capiv1.Cluster }{ { name: "IBM Cloud cluster", @@ -1401,7 +1401,7 @@ func TestReconcileCAPICluster(t *testing.T) { Namespace: "master-cluster1", }, }, - expectedCAPICluster: &v1beta1.Cluster{ + expectedCAPICluster: &capiv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ k8sutil.HostedClusterAnnotation: "master/cluster1", @@ -1409,21 +1409,20 @@ func TestReconcileCAPICluster(t *testing.T) { Namespace: "master-cluster1", Name: "cluster1", }, - Spec: v1beta1.ClusterSpec{ - ControlPlaneEndpoint: v1beta1.APIEndpoint{}, - ControlPlaneRef: &corev1.ObjectReference{ - APIVersion: "hypershift.openshift.io/v1beta1", - Kind: "HostedControlPlane", - Namespace: "master-cluster1", - Name: "cluster1", + Spec: capiv1.ClusterSpec{ + ControlPlaneEndpoint: capiv1.APIEndpoint{}, + ControlPlaneRef: capiv1.ContractVersionedObjectReference{ + APIGroup: "hypershift.openshift.io", + Kind: "HostedControlPlane", + Name: "cluster1", }, - InfrastructureRef: &corev1.ObjectReference{ - APIVersion: capibmv1.GroupVersion.String(), - Kind: "IBMVPCCluster", - Namespace: "master-cluster1", - Name: "cluster1", + InfrastructureRef: capiv1.ContractVersionedObjectReference{ + APIGroup: capibmv1.GroupVersion.Group, + Kind: "IBMVPCCluster", + Name: "cluster1", }, }, + Status: capiv1.ClusterStatus{Initialization: capiv1.ClusterInitializationStatus{}}, }, }, { @@ -1459,7 +1458,7 @@ func TestReconcileCAPICluster(t *testing.T) { Namespace: "master-cluster1", }, }, - expectedCAPICluster: &v1beta1.Cluster{ + expectedCAPICluster: &capiv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ k8sutil.HostedClusterAnnotation: "master/cluster1", @@ -1467,21 +1466,20 @@ func TestReconcileCAPICluster(t *testing.T) { Namespace: "master-cluster1", Name: "cluster1", }, - Spec: v1beta1.ClusterSpec{ - ControlPlaneEndpoint: v1beta1.APIEndpoint{}, - ControlPlaneRef: &corev1.ObjectReference{ - APIVersion: "hypershift.openshift.io/v1beta1", - Kind: "HostedControlPlane", - Namespace: "master-cluster1", - Name: "cluster1", + Spec: capiv1.ClusterSpec{ + ControlPlaneEndpoint: capiv1.APIEndpoint{}, + ControlPlaneRef: capiv1.ContractVersionedObjectReference{ + APIGroup: "hypershift.openshift.io", + Kind: "HostedControlPlane", + Name: "cluster1", }, - InfrastructureRef: &corev1.ObjectReference{ - APIVersion: capiaws.GroupVersion.String(), - Kind: "AWSCluster", - Namespace: "master-cluster1", - Name: "cluster1", + InfrastructureRef: capiv1.ContractVersionedObjectReference{ + APIGroup: capiaws.GroupVersion.Group, + Kind: "AWSCluster", + Name: "cluster1", }, }, + Status: capiv1.ClusterStatus{Initialization: capiv1.ClusterInitializationStatus{}}, }, }, } @@ -3019,7 +3017,7 @@ func TestPauseCAPICluster(t *testing.T) { inputHostedCluster *hyperv1.HostedCluster inputObjects []crclient.Object paused bool - expectedCAPICluster *v1beta1.Cluster + expectedCAPICluster *capiv1.Cluster }{ { name: "When CAPI cluster exists and is paused, it should unpause when paused=false", @@ -3033,24 +3031,24 @@ func TestPauseCAPICluster(t *testing.T) { }, }, inputObjects: []crclient.Object{ - &v1beta1.Cluster{ + &capiv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ Namespace: controlPlaneNamespace, Name: fakeInfraID, }, - Spec: v1beta1.ClusterSpec{ - Paused: true, + Spec: capiv1.ClusterSpec{ + Paused: ptr.To(true), }, }, }, paused: false, - expectedCAPICluster: &v1beta1.Cluster{ + expectedCAPICluster: &capiv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ Namespace: controlPlaneNamespace, Name: fakeInfraID, }, - Spec: v1beta1.ClusterSpec{ - Paused: false, + Spec: capiv1.ClusterSpec{ + Paused: ptr.To(false), }, }, }, @@ -3066,24 +3064,24 @@ func TestPauseCAPICluster(t *testing.T) { }, }, inputObjects: []crclient.Object{ - &v1beta1.Cluster{ + &capiv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ Namespace: controlPlaneNamespace, Name: fakeInfraID, }, - Spec: v1beta1.ClusterSpec{ - Paused: false, + Spec: capiv1.ClusterSpec{ + Paused: ptr.To(false), }, }, }, paused: true, - expectedCAPICluster: &v1beta1.Cluster{ + expectedCAPICluster: &capiv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ Namespace: controlPlaneNamespace, Name: fakeInfraID, }, - Spec: v1beta1.ClusterSpec{ - Paused: true, + Spec: capiv1.ClusterSpec{ + Paused: ptr.To(true), }, }, }, @@ -3121,24 +3119,24 @@ func TestPauseCAPICluster(t *testing.T) { }, }, inputObjects: []crclient.Object{ - &v1beta1.Cluster{ + &capiv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ Namespace: controlPlaneNamespace, Name: fakeInfraID, }, - Spec: v1beta1.ClusterSpec{ - Paused: true, + Spec: capiv1.ClusterSpec{ + Paused: ptr.To(true), }, }, }, paused: true, - expectedCAPICluster: &v1beta1.Cluster{ + expectedCAPICluster: &capiv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ Namespace: controlPlaneNamespace, Name: fakeInfraID, }, - Spec: v1beta1.ClusterSpec{ - Paused: true, + Spec: capiv1.ClusterSpec{ + Paused: ptr.To(true), }, }, }, diff --git a/hypershift-operator/controllers/hostedcluster/hostedcluster_webhook.go b/hypershift-operator/controllers/hostedcluster/hostedcluster_webhook.go index 3b32c6adc86c..21a667f3ff37 100644 --- a/hypershift-operator/controllers/hostedcluster/hostedcluster_webhook.go +++ b/hypershift-operator/controllers/hostedcluster/hostedcluster_webhook.go @@ -25,8 +25,7 @@ import ( "github.com/go-logr/logr" ) -type hostedClusterDefaulter struct { -} +type hostedClusterDefaulter struct{} type nodePoolDefaulter struct { client client.Client diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent.go b/hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent.go index 6f116cd98131..f4c669f4a15f 100644 --- a/hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent.go +++ b/hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent.go @@ -21,7 +21,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -35,8 +35,8 @@ type Agent struct{} func (p Agent) ReconcileCAPIInfraCR(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, - controlPlaneNamespace string, apiEndpoint hyperv1.APIEndpoint) (client.Object, error) { - + controlPlaneNamespace string, apiEndpoint hyperv1.APIEndpoint, +) (client.Object, error) { // Ensure we create the agentCluster only after ignition endpoint exists // so AgentClusterInstall is only created with the right ign to boot machines. // https://bugzilla.redhat.com/show_bug.cgi?id=2097895 @@ -135,8 +135,8 @@ func (p Agent) CAPIProviderDeploymentSpec(hcluster *hyperv1.HostedCluster, _ *hy // TODO add a new method to Platform interface? func (p Agent) ReconcileCredentials(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, - controlPlaneNamespace string) error { - + controlPlaneNamespace string, +) error { roleBinding := &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Namespace: hcluster.Spec.Platform.Agent.AgentNamespace, @@ -166,7 +166,8 @@ func (p Agent) ReconcileCredentials(ctx context.Context, c client.Client, create func (Agent) ReconcileSecretEncryption(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, - controlPlaneNamespace string) error { + controlPlaneNamespace string, +) error { return nil } @@ -194,9 +195,10 @@ func reconcileAgentCluster(agentCluster *agentv1.AgentCluster, ignEndpoint, cont caSecret := ignitionserver.IgnitionCACertSecret(controlPlaneNamespace) agentCluster.Spec.IgnitionEndpoint = &agentv1.IgnitionEndpoint{ Url: "https://" + ignEndpoint + "/ignition", - CaCertificateReference: &agentv1.CaCertificateReference{Name: caSecret.Name, Namespace: caSecret.Namespace}} + CaCertificateReference: &agentv1.CaCertificateReference{Name: caSecret.Name, Namespace: caSecret.Namespace}, + } - agentCluster.Spec.ControlPlaneEndpoint = capiv1.APIEndpoint{ + agentCluster.Spec.ControlPlaneEndpoint = capiv1beta1.APIEndpoint{ Host: apiEndpoint.Host, Port: apiEndpoint.Port, } @@ -206,7 +208,8 @@ func reconcileAgentCluster(agentCluster *agentv1.AgentCluster, ignEndpoint, cont func (Agent) DeleteCredentials(ctx context.Context, c client.Client, hc *hyperv1.HostedCluster, - controlPlaneNamespace string) error { + controlPlaneNamespace string, +) error { if _, err := k8sutil.DeleteIfNeeded(ctx, c, &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("%s-%s", CredentialsRBACPrefix, controlPlaneNamespace), Namespace: hc.Spec.Platform.Agent.AgentNamespace}}); err != nil { return fmt.Errorf("failed to clean up CAPI provider rolebinding: %w", err) } diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent_test.go b/hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent_test.go index cbf448d50a75..784fdaf133d9 100644 --- a/hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent_test.go +++ b/hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent_test.go @@ -19,7 +19,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -173,7 +173,7 @@ func TestReconcileCAPIInfraCR(t *testing.T) { Url: "https://" + ignitionEndpoint + "/ignition", CaCertificateReference: &agentv1.CaCertificateReference{Name: caSecret.Name, Namespace: caSecret.Namespace}, }, - ControlPlaneEndpoint: capiv1.APIEndpoint{ + ControlPlaneEndpoint: capiv1beta1.APIEndpoint{ Port: APIEndpoint.Port, Host: APIEndpoint.Host, }, diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/aws/aws.go b/hypershift-operator/controllers/hostedcluster/internal/platform/aws/aws.go index ac588320f15e..b4ea13ca0f69 100644 --- a/hypershift-operator/controllers/hostedcluster/internal/platform/aws/aws.go +++ b/hypershift-operator/controllers/hostedcluster/internal/platform/aws/aws.go @@ -22,7 +22,8 @@ import ( "k8s.io/utils/ptr" capiaws "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -119,7 +120,7 @@ func (p AWS) CAPIProviderDeploymentSpec(hcluster *hyperv1.HostedCluster, hcp *hy featureGates = append(featureGates, "ROSA=false") } - defaultMode := int32(0640) + defaultMode := int32(0o640) deploymentSpec := &appsv1.DeploymentSpec{ Replicas: ptr.To[int32](1), Template: corev1.PodTemplateSpec{ @@ -211,7 +212,8 @@ func (p AWS) CAPIProviderDeploymentSpec(hcluster *hyperv1.HostedCluster, hcp *hy Value: "true", }, }, - Args: []string{"--namespace", "$(MY_NAMESPACE)", + Args: []string{ + "--namespace", "$(MY_NAMESPACE)", "--v=4", "--leader-elect=true", fmt.Sprintf("--feature-gates=%s", strings.Join(featureGates, ",")), @@ -288,7 +290,8 @@ func buildAWSWebIdentityCredentials(roleArn, region string) (string, error) { func (p AWS) ReconcileCredentials(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, - controlPlaneNamespace string) error { + controlPlaneNamespace string, +) error { // TODO (alberto): consider moving this reconciliation logic down to the CPO. // this is not trivial as the CPO deployment itself needs the secret with the ControlPlaneOperatorARN var errs []error @@ -340,7 +343,8 @@ func (p AWS) ReconcileCredentials(ctx context.Context, c client.Client, createOr func (AWS) ReconcileSecretEncryption(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, - controlPlaneNamespace string) error { + controlPlaneNamespace string, +) error { return nil } @@ -425,7 +429,7 @@ func reconcileAWSCluster(awsCluster *capiaws.AWSCluster, hcluster *hyperv1.Hoste // Set the values for upper level controller awsCluster.Status.Ready = true - awsCluster.Spec.ControlPlaneEndpoint = capiv1.APIEndpoint{ + awsCluster.Spec.ControlPlaneEndpoint = capiv1beta1.APIEndpoint{ Host: apiEndpoint.Host, Port: apiEndpoint.Port, } diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go b/hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go index 6d633c16e840..2e5e2faa1a0f 100644 --- a/hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go +++ b/hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go @@ -27,7 +27,8 @@ import ( "k8s.io/utils/ptr" capiazure "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/blang/semver" @@ -97,7 +98,7 @@ func (a Azure) CAPIProviderDeploymentSpec(hcluster *hyperv1.HostedCluster, _ *hy if override, ok := hcluster.Annotations[hyperv1.ClusterAPIAzureProviderImage]; ok { image = override } - defaultMode := int32(0640) + defaultMode := int32(0o640) deploymentSpec := &appsv1.DeploymentSpec{ Replicas: ptr.To[int32](1), Template: corev1.PodTemplateSpec{ @@ -376,7 +377,7 @@ func reconcileAzureCluster(azureCluster *capiazure.AzureCluster, hcluster *hyper azureCluster.Spec.NetworkSpec.NodeOutboundLB.Name = hcluster.Spec.InfraID azureCluster.Spec.NetworkSpec.NodeOutboundLB.BackendPool.Name = hcluster.Spec.InfraID - azureCluster.Spec.ControlPlaneEndpoint = capiv1.APIEndpoint{ + azureCluster.Spec.ControlPlaneEndpoint = capiv1beta1.APIEndpoint{ Host: apiEndpoint.Host, Port: apiEndpoint.Port, } diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/gcp/gcp.go b/hypershift-operator/controllers/hostedcluster/internal/platform/gcp/gcp.go index 683566e2254a..66ee4e7b9278 100644 --- a/hypershift-operator/controllers/hostedcluster/internal/platform/gcp/gcp.go +++ b/hypershift-operator/controllers/hostedcluster/internal/platform/gcp/gcp.go @@ -36,7 +36,8 @@ import ( "k8s.io/utils/ptr" capigcp "sigs.k8s.io/cluster-api-provider-gcp/api/v1beta1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/blang/semver" @@ -162,7 +163,7 @@ func (p GCP) reconcileGCPCluster(gcpCluster *capigcp.GCPCluster, hcluster *hyper } // Set control plane endpoint (following AWS pattern) - gcpCluster.Spec.ControlPlaneEndpoint = capiv1.APIEndpoint{ + gcpCluster.Spec.ControlPlaneEndpoint = capiv1beta1.APIEndpoint{ Host: apiEndpoint.Host, Port: apiEndpoint.Port, } @@ -273,7 +274,7 @@ func (p GCP) CAPIProviderDeploymentSpec(hcluster *hyperv1.HostedCluster, _ *hype // buildVolumes creates all volumes needed for CAPG deployment including // credentials and webhook certificates. func (p GCP) buildVolumes(_ *hyperv1.HostedCluster) []corev1.Volume { - defaultMode := int32(0640) + defaultMode := int32(0o640) return []corev1.Volume{ { Name: "capi-webhooks-tls", diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud/ibmcloud.go b/hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud/ibmcloud.go index 55f4ec11ee43..12aa812b0cb0 100644 --- a/hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud/ibmcloud.go +++ b/hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud/ibmcloud.go @@ -15,7 +15,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" capiibmv1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -24,7 +25,8 @@ type IBMCloud struct{} func (p IBMCloud) ReconcileCAPIInfraCR(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, controlPlaneNamespace string, - apiEndpoint hyperv1.APIEndpoint) (client.Object, error) { + apiEndpoint hyperv1.APIEndpoint, +) (client.Object, error) { // TODO: will adjust reconcile for non-upi platforms when CAPI components ready if hcluster.Spec.Platform.IBMCloud != nil && (hcluster.Spec.Platform.IBMCloud.ProviderType == configv1.IBMCloudProviderTypeUPI || hcluster.Spec.Platform.IBMCloud.ProviderType == configv1.IBMCloudProviderTypeClassic || hcluster.Spec.Platform.IBMCloud.ProviderType == configv1.IBMCloudProviderTypeVPC) { @@ -44,7 +46,7 @@ func (p IBMCloud) ReconcileCAPIInfraCR(ctx context.Context, c client.Client, cre // Set the values for upper level controller ibmCluster.Status.Ready = true - ibmCluster.Spec.ControlPlaneEndpoint = capiv1.APIEndpoint{ + ibmCluster.Spec.ControlPlaneEndpoint = capiv1beta1.APIEndpoint{ Host: apiEndpoint.Host, Port: apiEndpoint.Port, } @@ -62,13 +64,15 @@ func (p IBMCloud) CAPIProviderDeploymentSpec(hcluster *hyperv1.HostedCluster, _ func (p IBMCloud) ReconcileCredentials(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, - controlPlaneNamespace string) error { + controlPlaneNamespace string, +) error { return nil } func (IBMCloud) ReconcileSecretEncryption(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, - controlPlaneNamespace string) error { + controlPlaneNamespace string, +) error { if hcluster.Spec.SecretEncryption.KMS.IBMCloud == nil { return fmt.Errorf("ibm kms metadata nil") } diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud/ibmcloud_test.go b/hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud/ibmcloud_test.go index 7d841db0b5fc..7ae8eff9c9f7 100644 --- a/hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud/ibmcloud_test.go +++ b/hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud/ibmcloud_test.go @@ -13,7 +13,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" capiibmv1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -121,7 +122,7 @@ func TestReconcileCAPIInfraCR(t *testing.T) { Ready: true, }, Spec: capiibmv1.IBMVPCClusterSpec{ - ControlPlaneEndpoint: capiv1.APIEndpoint{ + ControlPlaneEndpoint: capiv1beta1.APIEndpoint{ Port: fakeAPIEndpoint.Port, Host: fakeAPIEndpoint.Host, }, diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt.go b/hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt.go index a536ac1df6a2..c2d0777e75fa 100644 --- a/hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt.go +++ b/hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt.go @@ -18,7 +18,7 @@ import ( "k8s.io/utils/ptr" capikubevirt "sigs.k8s.io/cluster-api-provider-kubevirt/api/v1alpha1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" cdicore "kubevirt.io/containerized-data-importer-api/pkg/apis/core" diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt_test.go b/hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt_test.go index c104a4c84fb3..1afafe4c0363 100644 --- a/hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt_test.go +++ b/hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt_test.go @@ -11,7 +11,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" capikubevirt "sigs.k8s.io/cluster-api-provider-kubevirt/api/v1alpha1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack.go b/hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack.go index 523b81a6f342..d57552209570 100644 --- a/hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack.go +++ b/hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack.go @@ -20,7 +20,7 @@ import ( "k8s.io/utils/ptr" capo "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/blang/semver" @@ -51,7 +51,8 @@ func New(capiProviderImage string, orcImage string, payloadVersion *semver.Versi } func (a OpenStack) ReconcileCAPIInfraCR(ctx context.Context, client client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, - controlPlaneNamespace string, apiEndpoint hyperv1.APIEndpoint) (client.Object, error) { + controlPlaneNamespace string, apiEndpoint hyperv1.APIEndpoint, +) (client.Object, error) { openStackCluster := &capo.OpenStackCluster{ ObjectMeta: metav1.ObjectMeta{ Name: hcluster.Name, @@ -87,7 +88,7 @@ func reconcileOpenStackClusterSpec(hcluster *hyperv1.HostedCluster, openStackClu openStackPlatform := hcluster.Spec.Platform.OpenStack - openStackClusterSpec.ControlPlaneEndpoint = &capiv1.APIEndpoint{ + openStackClusterSpec.ControlPlaneEndpoint = &capiv1beta1.APIEndpoint{ Host: apiEndpoint.Host, Port: apiEndpoint.Port, } @@ -190,7 +191,7 @@ func (a OpenStack) CAPIProviderDeploymentSpec(hcluster *hyperv1.HostedCluster, _ orcImage = override } allowPrivilegeEscalation := false - defaultMode := int32(0640) + defaultMode := int32(0o640) deploymentSpec := appsv1.DeploymentSpec{ Replicas: ptr.To[int32](1), Template: corev1.PodTemplateSpec{ @@ -277,7 +278,8 @@ func (a OpenStack) CAPIProviderDeploymentSpec(hcluster *hyperv1.HostedCluster, _ }, }, }}, - }}, + }, + }, } // Add the ORC manager container if the payload version is 4.19 or later diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack_test.go b/hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack_test.go index 7196d200d50d..8be33d578ec4 100644 --- a/hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack_test.go +++ b/hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack_test.go @@ -15,7 +15,7 @@ import ( "k8s.io/utils/ptr" capo "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1" "github.com/blang/semver" "github.com/google/go-cmp/cmp" @@ -54,9 +54,11 @@ func TestReconcileOpenStackCluster(t *testing.T) { AllocationPools: []hyperv1.AllocationPool{{ Start: "10.0.0.1", End: "10.0.0.10", - }}}}, + }}, + }}, NetworkMTU: ptr.To(1500), - }}, + }, + }, }, }, expectedOpenStackClusterSpec: capo.OpenStackClusterSpec{ @@ -64,16 +66,18 @@ func TestReconcileOpenStackCluster(t *testing.T) { Name: "openstack-credentials", CloudName: "openstack", }, - ManagedSubnets: []capo.SubnetSpec{{ - CIDR: "10.0.0.0/24", - DNSNameservers: []string{"1.1.1.1"}, - AllocationPools: []capo.AllocationPool{{ - Start: "10.0.0.1", - End: "10.0.0.10", - }}}, + ManagedSubnets: []capo.SubnetSpec{ + { + CIDR: "10.0.0.0/24", + DNSNameservers: []string{"1.1.1.1"}, + AllocationPools: []capo.AllocationPool{{ + Start: "10.0.0.1", + End: "10.0.0.10", + }}, + }, }, NetworkMTU: ptr.To(1500), - ControlPlaneEndpoint: &capiv1.APIEndpoint{ + ControlPlaneEndpoint: &capiv1beta1.APIEndpoint{ Host: "api-endpoint", Port: 6443, }, @@ -108,7 +112,10 @@ func TestReconcileOpenStackCluster(t *testing.T) { Subnets: []hyperv1.SubnetParam{ {ID: ptr.To(subnetID)}, }, - }}}}, + }, + }, + }, + }, expectedOpenStackClusterSpec: capo.OpenStackClusterSpec{ IdentityRef: capo.OpenStackIdentityReference{ Name: "openstack-credentials", @@ -119,7 +126,7 @@ func TestReconcileOpenStackCluster(t *testing.T) { }, Subnets: []capo.SubnetParam{{ID: ptr.To(subnetID)}}, Network: &capo.NetworkParam{ID: ptr.To(networkID)}, - ControlPlaneEndpoint: &capiv1.APIEndpoint{ + ControlPlaneEndpoint: &capiv1beta1.APIEndpoint{ Host: "api-endpoint", Port: 6443, }, @@ -149,7 +156,8 @@ func TestReconcileOpenStackCluster(t *testing.T) { Filter: &hyperv1.NetworkFilter{ FilterByNeutronTags: hyperv1.FilterByNeutronTags{ Tags: []hyperv1.NeutronTag{"test"}, - }}, + }, + }, }, Subnets: []hyperv1.SubnetParam{ {Filter: &hyperv1.SubnetFilter{ @@ -159,7 +167,10 @@ func TestReconcileOpenStackCluster(t *testing.T) { }}, }, Tags: []string{"hcp-id=123"}, - }}}}, + }, + }, + }, + }, expectedOpenStackClusterSpec: capo.OpenStackClusterSpec{ IdentityRef: capo.OpenStackIdentityReference{ Name: "openstack-credentials", @@ -176,9 +187,10 @@ func TestReconcileOpenStackCluster(t *testing.T) { Filter: &capo.NetworkFilter{ FilterByNeutronTags: capo.FilterByNeutronTags{ Tags: []capo.NeutronTag{"test"}, - }}, + }, + }, }, - ControlPlaneEndpoint: &capiv1.APIEndpoint{ + ControlPlaneEndpoint: &capiv1beta1.APIEndpoint{ Host: "api-endpoint", Port: 6443, }, @@ -204,7 +216,8 @@ func TestReconcileOpenStackCluster(t *testing.T) { Filter: &hyperv1.NetworkFilter{ FilterByNeutronTags: hyperv1.FilterByNeutronTags{ Tags: []hyperv1.NeutronTag{"test"}, - }}, + }, + }, }, Subnets: []hyperv1.SubnetParam{ {Filter: &hyperv1.SubnetFilter{ @@ -213,7 +226,10 @@ func TestReconcileOpenStackCluster(t *testing.T) { }, }}, }, - }}}}, + }, + }, + }, + }, expectedOpenStackClusterSpec: capo.OpenStackClusterSpec{ IdentityRef: capo.OpenStackIdentityReference{ Name: "openstack-credentials", @@ -278,7 +294,7 @@ func TestCAPIProviderDeploymentSpec(t *testing.T) { Name: "capi-webhooks-tls", VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - DefaultMode: ptr.To[int32](0640), + DefaultMode: ptr.To[int32](0o640), SecretName: "capi-webhooks-tls", }, }, @@ -287,7 +303,7 @@ func TestCAPIProviderDeploymentSpec(t *testing.T) { Name: "svc-kubeconfig", VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - DefaultMode: ptr.To[int32](0640), + DefaultMode: ptr.To[int32](0o640), SecretName: "service-network-admin-kubeconfig", }, }, @@ -386,7 +402,7 @@ func TestCAPIProviderDeploymentSpec(t *testing.T) { Name: "capi-webhooks-tls", VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - DefaultMode: ptr.To[int32](0640), + DefaultMode: ptr.To[int32](0o640), SecretName: "capi-webhooks-tls", }, }, @@ -395,7 +411,7 @@ func TestCAPIProviderDeploymentSpec(t *testing.T) { Name: "svc-kubeconfig", VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - DefaultMode: ptr.To[int32](0640), + DefaultMode: ptr.To[int32](0o640), SecretName: "service-network-admin-kubeconfig", }, }, diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/powervs/powervs.go b/hypershift-operator/controllers/hostedcluster/internal/platform/powervs/powervs.go index c0f1215b731b..0f71137ebf39 100644 --- a/hypershift-operator/controllers/hostedcluster/internal/platform/powervs/powervs.go +++ b/hypershift-operator/controllers/hostedcluster/internal/platform/powervs/powervs.go @@ -18,7 +18,8 @@ import ( "k8s.io/utils/ptr" capiibmv1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -33,14 +34,15 @@ type PowerVS struct { } func (p PowerVS) DeleteCredentials(ctx context.Context, c client.Client, hcluster *hyperv1.HostedCluster, controlPlaneNamespace string) error { - //TODO(mkumatag): implement me + // TODO(mkumatag): implement me return nil } func (p PowerVS) ReconcileCAPIInfraCR(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, controlPlaneNamespace string, - apiEndpoint hyperv1.APIEndpoint) (client.Object, error) { + apiEndpoint hyperv1.APIEndpoint, +) (client.Object, error) { ibmCluster := &capiibmv1.IBMPowerVSCluster{ ObjectMeta: metav1.ObjectMeta{ Namespace: controlPlaneNamespace, @@ -57,7 +59,7 @@ func (p PowerVS) ReconcileCAPIInfraCR(ctx context.Context, c client.Client, crea // Set the values for upper level controller ibmCluster.Status.Ready = true - ibmCluster.Spec.ControlPlaneEndpoint = capiv1.APIEndpoint{ + ibmCluster.Spec.ControlPlaneEndpoint = capiv1beta1.APIEndpoint{ Host: apiEndpoint.Host, Port: apiEndpoint.Port, } @@ -146,7 +148,8 @@ func (p PowerVS) CAPIProviderDeploymentSpec(hcluster *hyperv1.HostedCluster, _ * }, }, Command: []string{"/bin/cluster-api-provider-ibmcloud-controller-manager"}, - Args: []string{"--namespace", "$(MY_NAMESPACE)", + Args: []string{ + "--namespace", "$(MY_NAMESPACE)", "--v=4", "--leader-elect=true", "--provider-id-fmt=v2", @@ -184,7 +187,8 @@ func (p PowerVS) CAPIProviderDeploymentSpec(hcluster *hyperv1.HostedCluster, _ * func (p PowerVS) ReconcileCredentials(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, - controlPlaneNamespace string) error { + controlPlaneNamespace string, +) error { // Reconcile the platform provider cloud controller credentials secret by resolving // the reference from the HostedCluster and syncing the secret in the control // plane namespace. @@ -365,7 +369,8 @@ func (p PowerVS) ReconcileCredentials(ctx context.Context, c client.Client, crea func (PowerVS) ReconcileSecretEncryption(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, - controlPlaneNamespace string) error { + controlPlaneNamespace string, +) error { return nil } diff --git a/hypershift-operator/controllers/manifests/controlplaneoperator/manifests.go b/hypershift-operator/controllers/manifests/controlplaneoperator/manifests.go index f4e618338103..bf60e6108a9f 100644 --- a/hypershift-operator/controllers/manifests/controlplaneoperator/manifests.go +++ b/hypershift-operator/controllers/manifests/controlplaneoperator/manifests.go @@ -8,7 +8,7 @@ import ( rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" prometheusoperatorv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" ) diff --git a/hypershift-operator/controllers/nodepool/aws.go b/hypershift-operator/controllers/nodepool/aws.go index df5223ff2a9f..b1b6db3c6f8d 100644 --- a/hypershift-operator/controllers/nodepool/aws.go +++ b/hypershift-operator/controllers/nodepool/aws.go @@ -13,7 +13,7 @@ import ( "k8s.io/utils/ptr" capiaws "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" diff --git a/hypershift-operator/controllers/nodepool/aws_test.go b/hypershift-operator/controllers/nodepool/aws_test.go index 9bec3976807f..5bd5fd1a4746 100644 --- a/hypershift-operator/controllers/nodepool/aws_test.go +++ b/hypershift-operator/controllers/nodepool/aws_test.go @@ -23,7 +23,7 @@ import ( "k8s.io/utils/ptr" capiaws "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -517,7 +517,7 @@ func TestAWSMachineTemplate(t *testing.T) { md := &capiv1.MachineDeployment{ ObjectMeta: metav1.ObjectMeta{Name: tc.nodePool.GetName(), Namespace: namespace}, Spec: capiv1.MachineDeploymentSpec{Template: capiv1.MachineTemplateSpec{Spec: capiv1.MachineSpec{ - InfrastructureRef: corev1.ObjectReference{Name: tc.existingTemplate.Name}, + InfrastructureRef: capiv1.ContractVersionedObjectReference{Name: tc.existingTemplate.Name}, }}}, } existingObjs = append(existingObjs, md) @@ -525,7 +525,7 @@ func TestAWSMachineTemplate(t *testing.T) { ms := &capiv1.MachineSet{ ObjectMeta: metav1.ObjectMeta{Name: tc.nodePool.GetName(), Namespace: namespace}, Spec: capiv1.MachineSetSpec{Template: capiv1.MachineTemplateSpec{Spec: capiv1.MachineSpec{ - InfrastructureRef: corev1.ObjectReference{Name: tc.existingTemplate.Name}, + InfrastructureRef: capiv1.ContractVersionedObjectReference{Name: tc.existingTemplate.Name}, }}}, } existingObjs = append(existingObjs, ms) diff --git a/hypershift-operator/controllers/nodepool/azure_test.go b/hypershift-operator/controllers/nodepool/azure_test.go index 471ac81a4988..3979f48110d3 100644 --- a/hypershift-operator/controllers/nodepool/azure_test.go +++ b/hypershift-operator/controllers/nodepool/azure_test.go @@ -15,7 +15,7 @@ import ( "k8s.io/utils/ptr" capiazure "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" - clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + clusterv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1" "github.com/coreos/stream-metadata-go/stream" "github.com/coreos/stream-metadata-go/stream/rhcos" @@ -52,7 +52,7 @@ func TestAzureMachineTemplateSpec(t *testing.T) { }, expectedAzureMachineTemplateSpec: &capiazure.AzureMachineTemplateSpec{ Template: capiazure.AzureMachineTemplateResource{ - ObjectMeta: clusterv1.ObjectMeta{Labels: nil, Annotations: nil}, + ObjectMeta: clusterv1beta1.ObjectMeta{Labels: nil, Annotations: nil}, Spec: capiazure.AzureMachineSpec{ ProviderID: nil, VMSize: "Standard_D2_v2", @@ -126,7 +126,7 @@ func TestAzureMachineTemplateSpec(t *testing.T) { }, expectedAzureMachineTemplateSpec: &capiazure.AzureMachineTemplateSpec{ Template: capiazure.AzureMachineTemplateResource{ - ObjectMeta: clusterv1.ObjectMeta{Labels: nil, Annotations: nil}, + ObjectMeta: clusterv1beta1.ObjectMeta{Labels: nil, Annotations: nil}, Spec: capiazure.AzureMachineSpec{ ProviderID: nil, VMSize: "Standard_D2_v2", @@ -205,7 +205,7 @@ func TestAzureMachineTemplateSpec(t *testing.T) { }, expectedAzureMachineTemplateSpec: &capiazure.AzureMachineTemplateSpec{ Template: capiazure.AzureMachineTemplateResource{ - ObjectMeta: clusterv1.ObjectMeta{Labels: nil, Annotations: nil}, + ObjectMeta: clusterv1beta1.ObjectMeta{Labels: nil, Annotations: nil}, Spec: capiazure.AzureMachineSpec{ ProviderID: nil, VMSize: "Standard_D2_v2", @@ -295,7 +295,7 @@ func TestAzureMachineTemplateSpec(t *testing.T) { }, expectedAzureMachineTemplateSpec: &capiazure.AzureMachineTemplateSpec{ Template: capiazure.AzureMachineTemplateResource{ - ObjectMeta: clusterv1.ObjectMeta{Labels: nil, Annotations: nil}, + ObjectMeta: clusterv1beta1.ObjectMeta{Labels: nil, Annotations: nil}, Spec: capiazure.AzureMachineSpec{ ProviderID: nil, VMSize: "Standard_D2_v2", @@ -391,7 +391,7 @@ func TestAzureMachineTemplateSpec(t *testing.T) { }, expectedAzureMachineTemplateSpec: &capiazure.AzureMachineTemplateSpec{ Template: capiazure.AzureMachineTemplateResource{ - ObjectMeta: clusterv1.ObjectMeta{Labels: nil, Annotations: nil}, + ObjectMeta: clusterv1beta1.ObjectMeta{Labels: nil, Annotations: nil}, Spec: capiazure.AzureMachineSpec{ ProviderID: nil, VMSize: "Standard_D2_v2", diff --git a/hypershift-operator/controllers/nodepool/capi.go b/hypershift-operator/controllers/nodepool/capi.go index 248c7fc468b0..d9cea0256b77 100644 --- a/hypershift-operator/controllers/nodepool/capi.go +++ b/hypershift-operator/controllers/nodepool/capi.go @@ -29,7 +29,7 @@ import ( capigcp "sigs.k8s.io/cluster-api-provider-gcp/api/v1beta1" capikubevirt "sigs.k8s.io/cluster-api-provider-kubevirt/api/v1alpha1" capiopenstackv1beta1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/apiutil" @@ -245,9 +245,15 @@ func (c *CAPI) cleanupMachineTemplates(ctx context.Context, log logr.Logger, nod ref := filtered[0].Spec.Template.Spec.InfrastructureRef machineTemplates := new(unstructured.UnstructuredList) - machineTemplates.SetAPIVersion(ref.APIVersion) + // v1beta2 ContractVersionedObjectReference has no APIVersion; reconstruct from scheme. + versions := api.Scheme.VersionsForGroupKind(schema.GroupKind{Group: ref.APIGroup, Kind: ref.Kind}) + if len(versions) == 0 { + return fmt.Errorf("no versions registered for GroupKind %s/%s", ref.APIGroup, ref.Kind) + } + apiVersion := schema.GroupVersion{Group: ref.APIGroup, Version: versions[0].Version}.String() + machineTemplates.SetAPIVersion(apiVersion) machineTemplates.SetKind(ref.Kind) - if err := c.Client.List(ctx, machineTemplates, client.InNamespace(ref.Namespace)); err != nil { + if err := c.Client.List(ctx, machineTemplates, client.InNamespace(controlPlaneNamespace)); err != nil { return fmt.Errorf("failed to list MachineTemplates: %w", err) } @@ -440,15 +446,16 @@ func (c *CAPI) reconcileMachineDeployment(ctx context.Context, log logr.Logger, Bootstrap: capiv1.Bootstrap{ DataSecretName: machineDeployment.Spec.Template.Spec.Bootstrap.DataSecretName, }, - InfrastructureRef: corev1.ObjectReference{ - Kind: gvk.Kind, - APIVersion: gvk.GroupVersion().String(), - Namespace: machineTemplateCR.GetNamespace(), - Name: machineDeployment.Spec.Template.Spec.InfrastructureRef.Name, + InfrastructureRef: capiv1.ContractVersionedObjectReference{ + Kind: gvk.Kind, + APIGroup: gvk.Group, + Name: machineDeployment.Spec.Template.Spec.InfrastructureRef.Name, + }, + Version: machineDeployment.Spec.Template.Spec.Version, + Deletion: capiv1.MachineDeletionSpec{ + NodeDrainTimeoutSeconds: durationToSeconds(nodePool.Spec.NodeDrainTimeout), + NodeVolumeDetachTimeoutSeconds: durationToSeconds(nodePool.Spec.NodeVolumeDetachTimeout), }, - Version: machineDeployment.Spec.Template.Spec.Version, - NodeDrainTimeout: nodePool.Spec.NodeDrainTimeout, - NodeVolumeDetachTimeout: nodePool.Spec.NodeVolumeDetachTimeout, }, } @@ -463,10 +470,9 @@ func (c *CAPI) reconcileMachineDeployment(ctx context.Context, log logr.Logger, return err } - machineDeployment.Spec.Strategy = &capiv1.MachineDeploymentStrategy{} - machineDeployment.Spec.Strategy.Type = capiv1.MachineDeploymentStrategyType(nodePool.Spec.Management.Replace.Strategy) + machineDeployment.Spec.Rollout.Strategy.Type = capiv1.MachineDeploymentRolloutStrategyType(nodePool.Spec.Management.Replace.Strategy) if nodePool.Spec.Management.Replace.RollingUpdate != nil { - machineDeployment.Spec.Strategy.RollingUpdate = &capiv1.MachineRollingUpdateDeployment{ + machineDeployment.Spec.Rollout.Strategy.RollingUpdate = capiv1.MachineDeploymentRolloutStrategyRollingUpdate{ MaxUnavailable: nodePool.Spec.Management.Replace.RollingUpdate.MaxUnavailable, MaxSurge: nodePool.Spec.Management.Replace.RollingUpdate.MaxSurge, } @@ -499,13 +505,13 @@ func setMachineDeploymentFailureDomain(nodePool *hyperv1.NodePool, machineDeploy // The CAPI provider for OpenStack uses the FailureDomain field to set the availability zone. if nodePool.Spec.Platform.Type == hyperv1.OpenStackPlatform && nodePool.Spec.Platform.OpenStack != nil { if nodePool.Spec.Platform.OpenStack.AvailabilityZone != "" { - machineDeployment.Spec.Template.Spec.FailureDomain = ptr.To(nodePool.Spec.Platform.OpenStack.AvailabilityZone) + machineDeployment.Spec.Template.Spec.FailureDomain = nodePool.Spec.Platform.OpenStack.AvailabilityZone } } // The CAPI provider for GCP uses the FailureDomain field to set the zone. if nodePool.Spec.Platform.Type == hyperv1.GCPPlatform && nodePool.Spec.Platform.GCP != nil { if nodePool.Spec.Platform.GCP.Zone != "" { - machineDeployment.Spec.Template.Spec.FailureDomain = ptr.To(nodePool.Spec.Platform.GCP.Zone) + machineDeployment.Spec.Template.Spec.FailureDomain = nodePool.Spec.Platform.GCP.Zone } } } @@ -575,7 +581,7 @@ func (c *CAPI) propagateVersionAndTemplate(log logr.Logger, machineDeployment *c "current", machineDeployment.Spec.Template.Spec.Bootstrap.DataSecretName, "target", userDataSecret.Name) - if targetVersion != ptr.Deref(machineDeployment.Spec.Template.Spec.Version, "") { + if targetVersion != machineDeployment.Spec.Template.Spec.Version { log.Info("Starting version update: Propagating new version to the MachineDeployment", "releaseImage", nodePool.Spec.Release.Image, "target", targetVersion) } @@ -584,7 +590,7 @@ func (c *CAPI) propagateVersionAndTemplate(log logr.Logger, machineDeployment *c log.Info("Starting config update: Propagating new config to the MachineDeployment", "current", nodePool.Annotations[nodePoolAnnotationCurrentConfig], "target", targetConfigHash) } - machineDeployment.Spec.Template.Spec.Version = &targetVersion + machineDeployment.Spec.Template.Spec.Version = targetVersion machineDeployment.Spec.Template.Spec.Bootstrap.DataSecretName = ptr.To(userDataSecret.Name) isUpdating = true } @@ -632,18 +638,21 @@ func (c *CAPI) reconcileMachineDeploymentStatus(log logr.Logger, machineDeployme } } - nodePool.Status.Replicas = machineDeployment.Status.AvailableReplicas - for _, cond := range machineDeployment.Status.Conditions { - if cond.Type == capiv1.ReadyCondition { + nodePool.Status.Replicas = availableReplicasFromMachineDeployment(machineDeployment) + for _, c := range machineDeployment.Status.Conditions { + // In CAPI v1beta2 "Ready" was replaced by "MachinesReady" (True when all machines are ready). + // https://github.com/kubernetes-sigs/cluster-api/issues/3486. + if c.Type == capiv1.MachinesReadyCondition { reason := hyperv1.AsExpectedReason - if cond.Reason != "" { - reason = cond.Reason + if c.Reason != "" { + reason = c.Reason } + SetStatusCondition(&nodePool.Status.Conditions, hyperv1.NodePoolCondition{ Type: hyperv1.NodePoolReadyConditionType, - Status: cond.Status, + Status: corev1.ConditionStatus(c.Status), ObservedGeneration: nodePool.Generation, - Message: cond.Message, + Message: c.Message, Reason: reason, }) break @@ -660,6 +669,16 @@ func taintsToJSON(taints []hyperv1.Taint) (string, error) { return string(taintsInJSON), nil } +// durationToSeconds converts a *metav1.Duration to *int32 seconds. +// CAPI v1beta2 uses integer seconds for timeouts instead of metav1.Duration. +func durationToSeconds(d *metav1.Duration) *int32 { + if d == nil { + return nil + } + s := int32(d.Seconds()) + return &s +} + func (c *CAPI) reconcileMachineHealthCheck(ctx context.Context, mhc *capiv1.MachineHealthCheck, ) error { @@ -723,6 +742,8 @@ func (c *CAPI) reconcileMachineHealthCheck(ctx context.Context, } resourcesName := generateName(capiClusterName, nodePool.Spec.ClusterName, nodePool.GetName()) + timeoutSec := int32(timeOut.Seconds()) + startupSec := int32(nodeStartupTimeout.Seconds()) mhc.Spec = capiv1.MachineHealthCheckSpec{ ClusterName: capiClusterName, Selector: metav1.LabelSelector{ @@ -730,25 +751,25 @@ func (c *CAPI) reconcileMachineHealthCheck(ctx context.Context, resourcesName: resourcesName, }, }, - UnhealthyConditions: []capiv1.UnhealthyCondition{ - { - Type: corev1.NodeReady, - Status: corev1.ConditionFalse, - Timeout: metav1.Duration{ - Duration: timeOut, + Checks: capiv1.MachineHealthCheckChecks{ + NodeStartupTimeoutSeconds: &startupSec, + UnhealthyNodeConditions: []capiv1.UnhealthyNodeCondition{ + { + Type: corev1.NodeReady, + Status: corev1.ConditionFalse, + TimeoutSeconds: &timeoutSec, }, - }, - { - Type: corev1.NodeReady, - Status: corev1.ConditionUnknown, - Timeout: metav1.Duration{ - Duration: timeOut, + { + Type: corev1.NodeReady, + Status: corev1.ConditionUnknown, + TimeoutSeconds: &timeoutSec, }, }, }, - MaxUnhealthy: &maxUnhealthy, - NodeStartupTimeout: &metav1.Duration{ - Duration: nodeStartupTimeout, + Remediation: capiv1.MachineHealthCheckRemediation{ + TriggerIf: capiv1.MachineHealthCheckRemediationTriggerIf{ + UnhealthyLessThanOrEqualTo: &maxUnhealthy, + }, }, } return nil @@ -923,17 +944,18 @@ func (c *CAPI) reconcileMachineSet(ctx context.Context, // Keep current user data for later check. DataSecretName: machineSet.Spec.Template.Spec.Bootstrap.DataSecretName, }, - InfrastructureRef: corev1.ObjectReference{ - Kind: gvk.Kind, - APIVersion: gvk.GroupVersion().String(), - Namespace: machineTemplateCR.GetNamespace(), - // Keep current version for later check. + InfrastructureRef: capiv1.ContractVersionedObjectReference{ + Kind: gvk.Kind, + APIGroup: gvk.Group, + // Keep current template name for later check. Name: machineSet.Spec.Template.Spec.InfrastructureRef.Name, }, // Keep current version for later check. - Version: machineSet.Spec.Template.Spec.Version, - NodeDrainTimeout: nodePool.Spec.NodeDrainTimeout, - NodeVolumeDetachTimeout: nodePool.Spec.NodeVolumeDetachTimeout, + Version: machineSet.Spec.Template.Spec.Version, + Deletion: capiv1.MachineDeletionSpec{ + NodeDrainTimeoutSeconds: durationToSeconds(nodePool.Spec.NodeDrainTimeout), + NodeVolumeDetachTimeoutSeconds: durationToSeconds(nodePool.Spec.NodeVolumeDetachTimeout), + }, }, } @@ -967,7 +989,7 @@ func (c *CAPI) reconcileMachineSet(ctx context.Context, "target", userDataSecret.Name) // TODO (alberto): possibly compare with NodePool here instead so we don't rely on impl details to drive decisions. - if targetVersion != ptr.Deref(machineSet.Spec.Template.Spec.Version, "") { + if targetVersion != machineSet.Spec.Template.Spec.Version { log.Info("Starting version upgrade: Propagating new version to the MachineSet", "releaseImage", nodePool.Spec.Release.Image, "target", targetVersion) } @@ -976,7 +998,7 @@ func (c *CAPI) reconcileMachineSet(ctx context.Context, log.Info("Starting config upgrade: Propagating new config to the MachineSet", "current", nodePool.Annotations[nodePoolAnnotationCurrentConfig], "target", targetConfigHash) } - machineSet.Spec.Template.Spec.Version = &targetVersion + machineSet.Spec.Template.Spec.Version = targetVersion machineSet.Spec.Template.Spec.Bootstrap.DataSecretName = ptr.To(userDataSecret.Name) // Signal in-place upgrade request. @@ -1032,11 +1054,11 @@ func (c *CAPI) reconcileMachineSet(ctx context.Context, } // Bubble up AvailableReplicas and Ready condition from MachineSet. - nodePool.Status.Replicas = machineSet.Status.AvailableReplicas + nodePool.Status.Replicas = availableReplicasFromMachineSet(machineSet) for _, c := range machineSet.Status.Conditions { - // This condition should aggregate and summarize readiness from underlying MachineSets and Machines + // In CAPI v1beta2 "Ready" was replaced by "MachinesReady" (True when all machines are ready). // https://github.com/kubernetes-sigs/cluster-api/issues/3486. - if c.Type == capiv1.ReadyCondition { + if c.Type == capiv1.MachinesReadyCondition { // this is so api server does not complain // invalid value: \"\": status.conditions.reason in body should be at least 1 chars long" reason := hyperv1.AsExpectedReason @@ -1046,7 +1068,7 @@ func (c *CAPI) reconcileMachineSet(ctx context.Context, SetStatusCondition(&nodePool.Status.Conditions, hyperv1.NodePoolCondition{ Type: hyperv1.NodePoolReadyConditionType, - Status: c.Status, + Status: corev1.ConditionStatus(c.Status), ObservedGeneration: nodePool.Generation, Message: c.Message, Reason: reason, @@ -1170,6 +1192,8 @@ func (c *CAPI) reconcileSpotMachineHealthCheck(_ context.Context, mhc *capiv1.Ma timeOut := 8 * time.Minute nodeStartupTimeout := 20 * time.Minute + timeoutSec := int32(timeOut.Seconds()) + startupSec := int32(nodeStartupTimeout.Seconds()) mhc.Spec = capiv1.MachineHealthCheckSpec{ ClusterName: c.capiClusterName, Selector: metav1.LabelSelector{ @@ -1177,25 +1201,25 @@ func (c *CAPI) reconcileSpotMachineHealthCheck(_ context.Context, mhc *capiv1.Ma interruptibleInstanceLabel: "", }, }, - UnhealthyConditions: []capiv1.UnhealthyCondition{ - { - Type: corev1.NodeReady, - Status: corev1.ConditionFalse, - Timeout: metav1.Duration{ - Duration: timeOut, + Checks: capiv1.MachineHealthCheckChecks{ + NodeStartupTimeoutSeconds: &startupSec, + UnhealthyNodeConditions: []capiv1.UnhealthyNodeCondition{ + { + Type: corev1.NodeReady, + Status: corev1.ConditionFalse, + TimeoutSeconds: &timeoutSec, }, - }, - { - Type: corev1.NodeReady, - Status: corev1.ConditionUnknown, - Timeout: metav1.Duration{ - Duration: timeOut, + { + Type: corev1.NodeReady, + Status: corev1.ConditionUnknown, + TimeoutSeconds: &timeoutSec, }, }, }, - MaxUnhealthy: &maxUnhealthy, - NodeStartupTimeout: &metav1.Duration{ - Duration: nodeStartupTimeout, + Remediation: capiv1.MachineHealthCheckRemediation{ + TriggerIf: capiv1.MachineHealthCheckRemediationTriggerIf{ + UnhealthyLessThanOrEqualTo: &maxUnhealthy, + }, }, } diff --git a/hypershift-operator/controllers/nodepool/capi_test.go b/hypershift-operator/controllers/nodepool/capi_test.go index 1fe35dc09f60..472cf0d029b1 100644 --- a/hypershift-operator/controllers/nodepool/capi_test.go +++ b/hypershift-operator/controllers/nodepool/capi_test.go @@ -26,8 +26,7 @@ import ( capiaws "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" capiazure "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" capikubevirt "sigs.k8s.io/cluster-api-provider-kubevirt/api/v1alpha1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" - "sigs.k8s.io/cluster-api/util/conversion" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/apiutil" @@ -815,11 +814,10 @@ func TestCleanupMachineTemplates(t *testing.T) { Spec: capiv1.MachineSetSpec{ Template: capiv1.MachineTemplateSpec{ Spec: capiv1.MachineSpec{ - InfrastructureRef: corev1.ObjectReference{ - Kind: gvk.Kind, - APIVersion: gvk.GroupVersion().String(), - Name: template1.Name, - Namespace: template1.Namespace, + InfrastructureRef: capiv1.ContractVersionedObjectReference{ + Kind: gvk.Kind, + APIGroup: gvk.Group, + Name: template1.Name, }, }, }, @@ -1100,6 +1098,8 @@ func TestReconcileMachineHealthCheck(t *testing.T) { healthcheck := func(opts ...func(*capiv1.MachineHealthCheck)) *capiv1.MachineHealthCheck { mhc := &capiv1.MachineHealthCheck{ObjectMeta: metav1.ObjectMeta{Namespace: "ns-cluster", Name: "nodepool"}} resName := generateName("cluster", "cluster", "nodepool") + timeoutSeconds := int32(480) + nodeStartupTimeoutSeconds := int32(1200) mhc.Spec = capiv1.MachineHealthCheckSpec{ ClusterName: "cluster", Selector: metav1.LabelSelector{ @@ -1107,25 +1107,25 @@ func TestReconcileMachineHealthCheck(t *testing.T) { resName: resName, }, }, - UnhealthyConditions: []capiv1.UnhealthyCondition{ - { - Type: corev1.NodeReady, - Status: corev1.ConditionFalse, - Timeout: metav1.Duration{ - Duration: time.Duration(8 * time.Minute), + Checks: capiv1.MachineHealthCheckChecks{ + UnhealthyNodeConditions: []capiv1.UnhealthyNodeCondition{ + { + Type: corev1.NodeReady, + Status: corev1.ConditionFalse, + TimeoutSeconds: &timeoutSeconds, }, - }, - { - Type: corev1.NodeReady, - Status: corev1.ConditionUnknown, - Timeout: metav1.Duration{ - Duration: time.Duration(8 * time.Minute), + { + Type: corev1.NodeReady, + Status: corev1.ConditionUnknown, + TimeoutSeconds: &timeoutSeconds, }, }, + NodeStartupTimeoutSeconds: &nodeStartupTimeoutSeconds, }, - MaxUnhealthy: &defaultMaxUnhealthy, - NodeStartupTimeout: &metav1.Duration{ - Duration: 20 * time.Minute, + Remediation: capiv1.MachineHealthCheckRemediation{ + TriggerIf: capiv1.MachineHealthCheckRemediationTriggerIf{ + UnhealthyLessThanOrEqualTo: &defaultMaxUnhealthy, + }, }, } for _, o := range opts { @@ -1157,8 +1157,9 @@ func TestReconcileMachineHealthCheck(t *testing.T) { } withTimeout := func(d time.Duration) func(*capiv1.MachineHealthCheck) { return func(mhc *capiv1.MachineHealthCheck) { - for i := range mhc.Spec.UnhealthyConditions { - mhc.Spec.UnhealthyConditions[i].Timeout = metav1.Duration{Duration: d} + s := int32(d.Seconds()) + for i := range mhc.Spec.Checks.UnhealthyNodeConditions { + mhc.Spec.Checks.UnhealthyNodeConditions[i].TimeoutSeconds = &s } } } @@ -1174,7 +1175,8 @@ func TestReconcileMachineHealthCheck(t *testing.T) { } withNodeStartupTimeout := func(d time.Duration) func(*capiv1.MachineHealthCheck) { return func(mhc *capiv1.MachineHealthCheck) { - mhc.Spec.NodeStartupTimeout = &metav1.Duration{Duration: d} + s := int32(d.Seconds()) + mhc.Spec.Checks.NodeStartupTimeoutSeconds = &s } } @@ -1345,10 +1347,9 @@ func TestCAPIReconcile(t *testing.T) { Spec: capiv1.MachineSetSpec{ Template: capiv1.MachineTemplateSpec{ Spec: capiv1.MachineSpec{ - InfrastructureRef: corev1.ObjectReference{ - Kind: "AWSMachineTemplate", - APIVersion: "infrastructure.cluster.x-k8s.io/v1beta2", - Namespace: "test-namespace-test-cluster", + InfrastructureRef: capiv1.ContractVersionedObjectReference{ + Kind: "AWSMachineTemplate", + APIGroup: "infrastructure.cluster.x-k8s.io", // This is the generated name by machineTemplateBuilders. // So reconciliation doesn't create a new AWSMachineTemplate but reconcile this one. Name: awsMachineTemplateName, @@ -1441,10 +1442,9 @@ func TestCAPIReconcile(t *testing.T) { Spec: capiv1.MachineSetSpec{ Template: capiv1.MachineTemplateSpec{ Spec: capiv1.MachineSpec{ - InfrastructureRef: corev1.ObjectReference{ - Kind: "AWSMachineTemplate", - APIVersion: "infrastructure.cluster.x-k8s.io/v1beta2", - Namespace: "test-namespace-test-cluster", + InfrastructureRef: capiv1.ContractVersionedObjectReference{ + Kind: "AWSMachineTemplate", + APIGroup: "infrastructure.cluster.x-k8s.io", // This is the generated name by machineTemplateBuilders. // So reconciliation doesn't create a new AWSMachineTemplate but reconcile this one. Name: awsMachineTemplateName, @@ -1548,10 +1548,9 @@ func TestCAPIReconcile(t *testing.T) { Spec: capiv1.MachineSetSpec{ Template: capiv1.MachineTemplateSpec{ Spec: capiv1.MachineSpec{ - InfrastructureRef: corev1.ObjectReference{ - Kind: "AWSMachineTemplate", - APIVersion: "infrastructure.cluster.x-k8s.io/v1beta2", - Namespace: "test-namespace-test-cluster", + InfrastructureRef: capiv1.ContractVersionedObjectReference{ + Kind: "AWSMachineTemplate", + APIGroup: "infrastructure.cluster.x-k8s.io", // This is the generated name by machineTemplateBuilders. // So reconciliation doesn't create a new AWSMachineTemplate but reconcile this one. Name: awsMachineTemplateName, @@ -1662,11 +1661,10 @@ func TestCAPIReconcile(t *testing.T) { Spec: capiv1.MachineSetSpec{ Template: capiv1.MachineTemplateSpec{ Spec: capiv1.MachineSpec{ - InfrastructureRef: corev1.ObjectReference{ - Kind: "AWSMachineTemplate", - APIVersion: "infrastructure.cluster.x-k8s.io/v1beta2", - Namespace: "test-namespace-test-cluster", - Name: awsMachineTemplateName, + InfrastructureRef: capiv1.ContractVersionedObjectReference{ + Kind: "AWSMachineTemplate", + APIGroup: "infrastructure.cluster.x-k8s.io", + Name: awsMachineTemplateName, }, }, }, @@ -1765,9 +1763,9 @@ func TestCAPIReconcile(t *testing.T) { g.Expect(md.Annotations).To(HaveKeyWithValue(nodePoolAnnotation, "test-namespace/test-nodepool")) // Check MachineDeployment spec. - g.Expect(md.Spec.Strategy.Type).To(Equal(capiv1.MachineDeploymentStrategyType("RollingUpdate"))) - g.Expect(md.Spec.Strategy.RollingUpdate.MaxUnavailable.IntValue()).To(Equal(0)) - g.Expect(md.Spec.Strategy.RollingUpdate.MaxSurge.IntValue()).To(Equal(1)) + g.Expect(md.Spec.Rollout.Strategy.Type).To(Equal(capiv1.MachineDeploymentRolloutStrategyType("RollingUpdate"))) + g.Expect(md.Spec.Rollout.Strategy.RollingUpdate.MaxUnavailable.IntValue()).To(Equal(0)) + g.Expect(md.Spec.Rollout.Strategy.RollingUpdate.MaxSurge.IntValue()).To(Equal(1)) // Check MachineDeployment labels. g.Expect(md.Labels).To(HaveKeyWithValue(capiv1.ClusterNameLabel, capiClusterName)) @@ -1780,14 +1778,13 @@ func TestCAPIReconcile(t *testing.T) { // Check MachineDeployment template spec g.Expect(md.Spec.Template.Spec.ClusterName).To(Equal(capiClusterName)) - g.Expect(md.Spec.Template.Spec.InfrastructureRef.APIVersion).To(Equal("infrastructure.cluster.x-k8s.io/v1beta2")) + g.Expect(md.Spec.Template.Spec.InfrastructureRef.APIGroup).To(Equal("infrastructure.cluster.x-k8s.io")) g.Expect(md.Spec.Template.Spec.InfrastructureRef.Kind).To(Equal("AWSMachineTemplate")) - g.Expect(md.Spec.Template.Spec.InfrastructureRef.Namespace).To(Equal(controlpaneNamespace)) g.Expect(md.Spec.Template.Spec.InfrastructureRef.Name).To(Equal(awsMachineTemplateName)) - g.Expect(*md.Spec.Template.Spec.Version).To(Equal("target-version")) - g.Expect(md.Spec.Template.Spec.NodeDrainTimeout).To(Equal(tt.nodePool.Spec.NodeDrainTimeout)) - g.Expect(md.Spec.Template.Spec.NodeVolumeDetachTimeout).To(Equal(tt.nodePool.Spec.NodeVolumeDetachTimeout)) + g.Expect(md.Spec.Template.Spec.Version).To(Equal("target-version")) + g.Expect(md.Spec.Template.Spec.Deletion.NodeDrainTimeoutSeconds).To(Equal(durationToSeconds(tt.nodePool.Spec.NodeDrainTimeout))) + g.Expect(md.Spec.Template.Spec.Deletion.NodeVolumeDetachTimeoutSeconds).To(Equal(durationToSeconds(tt.nodePool.Spec.NodeVolumeDetachTimeout))) // Check Bootstrap DataSecretName. g.Expect(md.Spec.Template.Spec.Bootstrap.DataSecretName).NotTo(BeNil()) @@ -1842,10 +1839,10 @@ func TestCAPIReconcile(t *testing.T) { g.Expect(err).NotTo(HaveOccurred()) // Update MachineDeployment status to indicate rollout is complete. - md.Status.Replicas = *tt.nodePool.Spec.Replicas - md.Status.UpdatedReplicas = *tt.nodePool.Spec.Replicas - md.Status.ReadyReplicas = *tt.nodePool.Spec.Replicas - md.Status.AvailableReplicas = *tt.nodePool.Spec.Replicas + md.Status.Replicas = tt.nodePool.Spec.Replicas + md.Status.ReadyReplicas = tt.nodePool.Spec.Replicas + md.Status.AvailableReplicas = tt.nodePool.Spec.Replicas + md.Status.UpToDateReplicas = tt.nodePool.Spec.Replicas md.Status.ObservedGeneration = md.Generation err = capi.Client.Update(t.Context(), md) g.Expect(err).NotTo(HaveOccurred()) @@ -1950,11 +1947,10 @@ func TestGlobalPSManagedLabelOnMachines(t *testing.T) { Spec: capiv1.MachineSetSpec{ Template: capiv1.MachineTemplateSpec{ Spec: capiv1.MachineSpec{ - InfrastructureRef: corev1.ObjectReference{ - Kind: "AWSMachineTemplate", - APIVersion: "infrastructure.cluster.x-k8s.io/v1beta2", - Namespace: controlPlaneNamespace, - Name: awsMachineTemplateName, + InfrastructureRef: capiv1.ContractVersionedObjectReference{ + Kind: "AWSMachineTemplate", + APIGroup: "infrastructure.cluster.x-k8s.io", + Name: awsMachineTemplateName, }, }, }, @@ -2098,11 +2094,10 @@ func TestGlobalPSManagedLabelOnMachines(t *testing.T) { Spec: capiv1.MachineSetSpec{ Template: capiv1.MachineTemplateSpec{ Spec: capiv1.MachineSpec{ - InfrastructureRef: corev1.ObjectReference{ - Kind: "AWSMachineTemplate", - APIVersion: "infrastructure.cluster.x-k8s.io/v1beta2", - Namespace: controlPlaneNamespace, - Name: awsMachineTemplateName, + InfrastructureRef: capiv1.ContractVersionedObjectReference{ + Kind: "AWSMachineTemplate", + APIGroup: "infrastructure.cluster.x-k8s.io", + Name: awsMachineTemplateName, }, }, }, @@ -2405,7 +2400,7 @@ func TestSetMachineDeploymentFailureDomain(t *testing.T) { testCases := []struct { name string nodePool *hyperv1.NodePool - expectedFailureDomain *string + expectedFailureDomain string }{ { name: "When platform is OpenStack with AvailabilityZone set, it should set failure domain", @@ -2419,7 +2414,7 @@ func TestSetMachineDeploymentFailureDomain(t *testing.T) { }, }, }, - expectedFailureDomain: ptr.To("az-1"), + expectedFailureDomain: "az-1", }, { name: "When platform is OpenStack with empty AvailabilityZone, it should not set failure domain", @@ -2433,7 +2428,7 @@ func TestSetMachineDeploymentFailureDomain(t *testing.T) { }, }, }, - expectedFailureDomain: nil, + expectedFailureDomain: "", }, { name: "When platform is GCP with Zone set, it should set failure domain", @@ -2447,7 +2442,7 @@ func TestSetMachineDeploymentFailureDomain(t *testing.T) { }, }, }, - expectedFailureDomain: ptr.To("us-central1-a"), + expectedFailureDomain: "us-central1-a", }, { name: "When platform is GCP with empty Zone, it should not set failure domain", @@ -2461,7 +2456,7 @@ func TestSetMachineDeploymentFailureDomain(t *testing.T) { }, }, }, - expectedFailureDomain: nil, + expectedFailureDomain: "", }, { name: "When platform is AWS, it should not set failure domain", @@ -2473,7 +2468,7 @@ func TestSetMachineDeploymentFailureDomain(t *testing.T) { }, }, }, - expectedFailureDomain: nil, + expectedFailureDomain: "", }, { name: "When platform is OpenStack but spec is nil, it should not set failure domain", @@ -2484,7 +2479,7 @@ func TestSetMachineDeploymentFailureDomain(t *testing.T) { }, }, }, - expectedFailureDomain: nil, + expectedFailureDomain: "", }, { name: "When platform is GCP but spec is nil, it should not set failure domain", @@ -2495,7 +2490,7 @@ func TestSetMachineDeploymentFailureDomain(t *testing.T) { }, }, }, - expectedFailureDomain: nil, + expectedFailureDomain: "", }, } @@ -2605,10 +2600,10 @@ func TestPropagateVersionAndTemplate(t *testing.T) { Bootstrap: capiv1.Bootstrap{ DataSecretName: ptr.To(bootstrapName), }, - InfrastructureRef: corev1.ObjectReference{ + InfrastructureRef: capiv1.ContractVersionedObjectReference{ Name: tc.currentInfraRefName, }, - Version: ptr.To(tc.currentVersion), + Version: tc.currentVersion, }, }, }, @@ -2627,7 +2622,7 @@ func TestPropagateVersionAndTemplate(t *testing.T) { if tc.expectedUpdating && tc.useDifferentUserData { // When updating, bootstrap should be set to the computed user data name. g.Expect(*md.Spec.Template.Spec.Bootstrap.DataSecretName).To(Equal(computedUserDataName)) - g.Expect(*md.Spec.Template.Spec.Version).To(Equal("4.17.0")) + g.Expect(md.Spec.Template.Spec.Version).To(Equal("4.17.0")) } }) } @@ -2655,10 +2650,10 @@ func TestReconcileMachineDeploymentStatus(t *testing.T) { Replicas: ptr.To[int32](3), }, Status: capiv1.MachineDeploymentStatus{ - Replicas: 3, - UpdatedReplicas: 3, - ReadyReplicas: 3, - AvailableReplicas: 3, + Replicas: ptr.To[int32](3), + UpToDateReplicas: ptr.To[int32](3), + ReadyReplicas: ptr.To[int32](3), + AvailableReplicas: ptr.To[int32](3), ObservedGeneration: 1, }, }, @@ -2678,10 +2673,10 @@ func TestReconcileMachineDeploymentStatus(t *testing.T) { Replicas: ptr.To[int32](3), }, Status: capiv1.MachineDeploymentStatus{ - Replicas: 3, - UpdatedReplicas: 1, - ReadyReplicas: 1, - AvailableReplicas: 2, + Replicas: ptr.To[int32](3), + UpToDateReplicas: ptr.To[int32](1), + ReadyReplicas: ptr.To[int32](1), + AvailableReplicas: ptr.To[int32](2), ObservedGeneration: 1, }, }, @@ -2701,11 +2696,11 @@ func TestReconcileMachineDeploymentStatus(t *testing.T) { Replicas: ptr.To[int32](3), }, Status: capiv1.MachineDeploymentStatus{ - AvailableReplicas: 2, - Conditions: capiv1.Conditions{ + AvailableReplicas: ptr.To[int32](2), + Conditions: []metav1.Condition{ { - Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Type: string(capiv1.MachinesReadyCondition), + Status: metav1.ConditionTrue, Reason: "SomeReason", Message: "all good", }, @@ -3281,136 +3276,144 @@ func TestNewCAPI(t *testing.T) { } func TestMachineDeploymentComplete(t *testing.T) { - two := int32(2) - three := int32(3) - - conversionData := func(replicas, upToDate, available int32, observedGen int64) string { - data := map[string]any{ - "apiVersion": "cluster.x-k8s.io/v1beta2", - "kind": "MachineDeployment", - "spec": map[string]any{"replicas": replicas}, - "status": map[string]any{ - "observedGeneration": observedGen, - "replicas": replicas, - "upToDateReplicas": upToDate, - "availableReplicas": available, - }, - } - raw, _ := json.Marshal(data) - return string(raw) - } - testCases := []struct { name string md *capiv1.MachineDeployment expected bool }{ { - name: "When all v1beta1 and v1beta2 fields agree it should return true", + name: "When all fields match spec replicas and generation it should return true", md: &capiv1.MachineDeployment{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 2, - Annotations: map[string]string{ - conversion.DataAnnotation: conversionData(2, 2, 2, 2), - }, + ObjectMeta: metav1.ObjectMeta{Generation: 2}, + Spec: capiv1.MachineDeploymentSpec{Replicas: ptr.To[int32](2)}, + Status: capiv1.MachineDeploymentStatus{ + Replicas: ptr.To[int32](2), + UpToDateReplicas: ptr.To[int32](2), + AvailableReplicas: ptr.To[int32](2), + ObservedGeneration: 2, }, - Spec: capiv1.MachineDeploymentSpec{Replicas: &two}, - Status: capiv1.MachineDeploymentStatus{Replicas: 2, UpdatedReplicas: 2, AvailableReplicas: 2, ObservedGeneration: 2}, }, expected: true, }, { - name: "When v1beta1 looks complete but v1beta2 upToDateReplicas disagrees it should return false", + name: "When upToDateReplicas does not match it should return false", md: &capiv1.MachineDeployment{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 2, - Annotations: map[string]string{ - conversion.DataAnnotation: conversionData(2, 0, 2, 2), - }, + ObjectMeta: metav1.ObjectMeta{Generation: 2}, + Spec: capiv1.MachineDeploymentSpec{Replicas: ptr.To[int32](2)}, + Status: capiv1.MachineDeploymentStatus{ + Replicas: ptr.To[int32](2), + UpToDateReplicas: ptr.To[int32](0), + AvailableReplicas: ptr.To[int32](2), + ObservedGeneration: 2, }, - Spec: capiv1.MachineDeploymentSpec{Replicas: &two}, - Status: capiv1.MachineDeploymentStatus{Replicas: 2, UpdatedReplicas: 2, AvailableReplicas: 2, ObservedGeneration: 2}, }, expected: false, }, { - name: "When v1beta1 looks complete but v1beta2 replicas shows surge it should return false", + name: "When replicas shows surge it should return false", md: &capiv1.MachineDeployment{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 2, - Annotations: map[string]string{ - conversion.DataAnnotation: conversionData(3, 2, 2, 2), - }, + ObjectMeta: metav1.ObjectMeta{Generation: 2}, + Spec: capiv1.MachineDeploymentSpec{Replicas: ptr.To[int32](2)}, + Status: capiv1.MachineDeploymentStatus{ + Replicas: ptr.To[int32](3), + UpToDateReplicas: ptr.To[int32](2), + AvailableReplicas: ptr.To[int32](2), + ObservedGeneration: 2, }, - Spec: capiv1.MachineDeploymentSpec{Replicas: &two}, - Status: capiv1.MachineDeploymentStatus{Replicas: 2, UpdatedReplicas: 2, AvailableReplicas: 2, ObservedGeneration: 2}, }, expected: false, }, { - name: "When v1beta1 looks complete but v1beta2 observedGeneration is stale it should return false", + name: "When observedGeneration is stale it should return false", md: &capiv1.MachineDeployment{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 2, - Annotations: map[string]string{ - conversion.DataAnnotation: conversionData(2, 2, 2, 1), - }, + ObjectMeta: metav1.ObjectMeta{Generation: 2}, + Spec: capiv1.MachineDeploymentSpec{Replicas: ptr.To[int32](2)}, + Status: capiv1.MachineDeploymentStatus{ + Replicas: ptr.To[int32](2), + UpToDateReplicas: ptr.To[int32](2), + AvailableReplicas: ptr.To[int32](2), + ObservedGeneration: 1, }, - Spec: capiv1.MachineDeploymentSpec{Replicas: &two}, - Status: capiv1.MachineDeploymentStatus{Replicas: 2, UpdatedReplicas: 2, AvailableReplicas: 2, ObservedGeneration: 2}, }, expected: false, }, { - name: "When v1beta1 is not complete it should return false without checking conversion data", + name: "When AvailableReplicas does not match it should return false", md: &capiv1.MachineDeployment{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 2, + ObjectMeta: metav1.ObjectMeta{Generation: 2}, + Spec: capiv1.MachineDeploymentSpec{Replicas: ptr.To[int32](2)}, + Status: capiv1.MachineDeploymentStatus{ + Replicas: ptr.To[int32](2), + UpToDateReplicas: ptr.To[int32](2), + AvailableReplicas: ptr.To[int32](1), + ObservedGeneration: 2, }, - Spec: capiv1.MachineDeploymentSpec{Replicas: &two}, - Status: capiv1.MachineDeploymentStatus{Replicas: 3, UpdatedReplicas: 1, AvailableReplicas: 2, ObservedGeneration: 2}, }, expected: false, }, { - name: "When no conversion-data annotation exists it should fall back to v1beta1 only", + name: "When spec replicas is nil it should default to 0", md: &capiv1.MachineDeployment{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 1, + ObjectMeta: metav1.ObjectMeta{Generation: 1}, + Spec: capiv1.MachineDeploymentSpec{}, + Status: capiv1.MachineDeploymentStatus{ + Replicas: ptr.To[int32](0), + UpToDateReplicas: ptr.To[int32](0), + AvailableReplicas: ptr.To[int32](0), + ObservedGeneration: 1, }, - Spec: capiv1.MachineDeploymentSpec{Replicas: &two}, - Status: capiv1.MachineDeploymentStatus{Replicas: 2, UpdatedReplicas: 2, AvailableReplicas: 2, ObservedGeneration: 1}, }, expected: true, }, { - name: "When conversion-data annotation is malformed it should fall back to v1beta1 result", + name: "When v1beta2 fields are nil but deprecated v1beta1 fields match it should return true", md: &capiv1.MachineDeployment{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 1, - Annotations: map[string]string{ - conversion.DataAnnotation: "not-valid-json", + ObjectMeta: metav1.ObjectMeta{Generation: 2}, + Spec: capiv1.MachineDeploymentSpec{Replicas: ptr.To[int32](2)}, + Status: capiv1.MachineDeploymentStatus{ + Replicas: ptr.To[int32](2), + ObservedGeneration: 2, + Deprecated: &capiv1.MachineDeploymentDeprecatedStatus{ + V1Beta1: &capiv1.MachineDeploymentV1Beta1DeprecatedStatus{ + UpdatedReplicas: 2, + AvailableReplicas: 2, + }, }, }, - Spec: capiv1.MachineDeploymentSpec{Replicas: &two}, - Status: capiv1.MachineDeploymentStatus{Replicas: 2, UpdatedReplicas: 2, AvailableReplicas: 2, ObservedGeneration: 1}, }, expected: true, }, { - name: "When v1beta1 replicas does not match spec it should return false", + name: "When v1beta2 fields are nil and deprecated v1beta1 available does not match it should return false", md: &capiv1.MachineDeployment{ - ObjectMeta: metav1.ObjectMeta{ - Generation: 2, - Annotations: map[string]string{ - conversion.DataAnnotation: conversionData(3, 2, 2, 2), + ObjectMeta: metav1.ObjectMeta{Generation: 2}, + Spec: capiv1.MachineDeploymentSpec{Replicas: ptr.To[int32](2)}, + Status: capiv1.MachineDeploymentStatus{ + Replicas: ptr.To[int32](2), + ObservedGeneration: 2, + Deprecated: &capiv1.MachineDeploymentDeprecatedStatus{ + V1Beta1: &capiv1.MachineDeploymentV1Beta1DeprecatedStatus{ + UpdatedReplicas: 2, + AvailableReplicas: 1, + }, }, }, - Spec: capiv1.MachineDeploymentSpec{Replicas: &three}, - Status: capiv1.MachineDeploymentStatus{Replicas: 2, UpdatedReplicas: 2, AvailableReplicas: 2, ObservedGeneration: 2}, }, expected: false, }, + { + name: "When all v1beta2 and deprecated fields are nil it should fall back to replicas check", + md: &capiv1.MachineDeployment{ + ObjectMeta: metav1.ObjectMeta{Generation: 2}, + Spec: capiv1.MachineDeploymentSpec{Replicas: ptr.To[int32](2)}, + Status: capiv1.MachineDeploymentStatus{ + Replicas: ptr.To[int32](2), + AvailableReplicas: ptr.To[int32](2), + ObservedGeneration: 2, + }, + }, + expected: true, + }, } for _, tc := range testCases { diff --git a/hypershift-operator/controllers/nodepool/conditions.go b/hypershift-operator/controllers/nodepool/conditions.go index cff009e3590e..10ac12225bc4 100644 --- a/hypershift-operator/controllers/nodepool/conditions.go +++ b/hypershift-operator/controllers/nodepool/conditions.go @@ -20,7 +20,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" crclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -100,17 +100,17 @@ func FindStatusCondition(conditions []hyperv1.NodePoolCondition, conditionType s // machineConditionResult normalizes a CAPI Machine condition into a common struct. type machineConditionResult struct { - Status corev1.ConditionStatus + Status metav1.ConditionStatus Reason string Message string } // findMachineStatusCondition looks up a condition on a CAPI Machine from -// Machine.Status.Conditions ([]capiv1.Condition). +// Machine.Status.Conditions ([]metav1.Condition). // Returns nil if the condition is not found. func findMachineStatusCondition(machine *capiv1.Machine, conditionType string) *machineConditionResult { for i := range machine.Status.Conditions { - if string(machine.Status.Conditions[i].Type) == conditionType { + if machine.Status.Conditions[i].Type == conditionType { return &machineConditionResult{ Status: machine.Status.Conditions[i].Status, Reason: machine.Status.Conditions[i].Reason, @@ -637,10 +637,10 @@ func (r *NodePoolReconciler) setAllNodesHealthyCondition(nodePool *hyperv1.NodeP // NodeHealthy condition not yet reported; treat as not healthy. status = corev1.ConditionFalse numNotHealthy++ - mapReason := capiv1.WaitingForNodeRefReason + mapReason := capiv1.WaitingForNodeRefV1Beta1Reason mapMessage := fmt.Sprintf("Machine %s: %s\n", machine.Name, mapReason) messageMap[mapReason] = append(messageMap[mapReason], mapMessage) - } else if condition.Status != corev1.ConditionTrue { + } else if condition.Status != metav1.ConditionTrue { status = corev1.ConditionFalse numNotHealthy++ mapReason := condition.Reason @@ -700,10 +700,10 @@ func (r *NodePoolReconciler) setAllMachinesReadyCondition(nodePool *hyperv1.Node // Ready condition not yet reported; treat as not ready. status = corev1.ConditionFalse numNotReady++ - mapReason := capiv1.WaitingForInfrastructureFallbackReason + mapReason := capiv1.WaitingForInfrastructureFallbackV1Beta1Reason mapMessage := fmt.Sprintf("Machine %s: %s\n", machine.Name, mapReason) messageMap[mapReason] = append(messageMap[mapReason], mapMessage) - } else if readyCond.Status != corev1.ConditionTrue { + } else if readyCond.Status != metav1.ConditionTrue { status = corev1.ConditionFalse numNotReady++ infraReadyCond := findMachineStatusCondition(machine, string(capiv1.InfrastructureReadyCondition)) @@ -716,7 +716,7 @@ func (r *NodePoolReconciler) setAllMachinesReadyCondition(nodePool *hyperv1.Node // status: "False" // type: Ready var mapReason, mapMessage string - if infraReadyCond != nil && infraReadyCond.Status != corev1.ConditionTrue && !isSetupCounterCondMessage.MatchString(infraReadyCond.Message) { + if infraReadyCond != nil && infraReadyCond.Status != metav1.ConditionTrue && !isSetupCounterCondMessage.MatchString(infraReadyCond.Message) { mapReason = infraReadyCond.Reason mapMessage = fmt.Sprintf("Machine %s: %s: %s\n", machine.Name, infraReadyCond.Reason, infraReadyCond.Message) } else { @@ -780,7 +780,6 @@ func (r *NodePoolReconciler) setCIDRConflictCondition(nodePool *hyperv1.NodePool if len(messages) > 0 { message := "" for _, entry := range messages { - if len(message) == 0 { message = entry } else if len(entry)+len(message) < maxMessageLength { diff --git a/hypershift-operator/controllers/nodepool/conditions_test.go b/hypershift-operator/controllers/nodepool/conditions_test.go index c52571f328cd..d388ff30c265 100644 --- a/hypershift-operator/controllers/nodepool/conditions_test.go +++ b/hypershift-operator/controllers/nodepool/conditions_test.go @@ -20,7 +20,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" - "sigs.k8s.io/cluster-api/api/core/v1beta1" + "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/blang/semver" @@ -487,8 +487,8 @@ spec: return pullSecret, ignitionServerCACert, machineConfig, ignitionConfig, ignitionConfig2, ignitionConfig3 } -func setUpDummyMachineSet(nodePool *hyperv1.NodePool, hostedCluster *hyperv1.HostedCluster, machineSetUpgradeFail bool) *v1beta1.MachineSet { - machineSet := &v1beta1.MachineSet{ +func setUpDummyMachineSet(nodePool *hyperv1.NodePool, hostedCluster *hyperv1.HostedCluster, machineSetUpgradeFail bool) *v1beta2.MachineSet { + machineSet := &v1beta2.MachineSet{ ObjectMeta: metav1.ObjectMeta{ Name: nodePool.Name, Namespace: hostedCluster.Namespace + "-" + hostedCluster.Name, diff --git a/hypershift-operator/controllers/nodepool/gcp.go b/hypershift-operator/controllers/nodepool/gcp.go index 50a107b210b4..87129f150116 100644 --- a/hypershift-operator/controllers/nodepool/gcp.go +++ b/hypershift-operator/controllers/nodepool/gcp.go @@ -12,7 +12,7 @@ import ( "k8s.io/utils/ptr" capigcp "sigs.k8s.io/cluster-api-provider-gcp/api/v1beta1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" ) diff --git a/hypershift-operator/controllers/nodepool/metrics/metrics.go b/hypershift-operator/controllers/nodepool/metrics/metrics.go index 0fb0e01c4a68..37759e15ea4c 100644 --- a/hypershift-operator/controllers/nodepool/metrics/metrics.go +++ b/hypershift-operator/controllers/nodepool/metrics/metrics.go @@ -21,7 +21,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/utils/clock" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" ctrllog "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/metrics" diff --git a/hypershift-operator/controllers/nodepool/nodepool_controller.go b/hypershift-operator/controllers/nodepool/nodepool_controller.go index fbbd74145794..e3d42c6b5566 100644 --- a/hypershift-operator/controllers/nodepool/nodepool_controller.go +++ b/hypershift-operator/controllers/nodepool/nodepool_controller.go @@ -2,7 +2,6 @@ package nodepool import ( "context" - "encoding/json" coreerrors "errors" "fmt" "os" @@ -42,9 +41,8 @@ import ( capiaws "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" capiazure "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" capiopenstackv1beta1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/cluster-api/util" - "sigs.k8s.io/cluster-api/util/conversion" "sigs.k8s.io/cluster-api/util/patch" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -781,54 +779,63 @@ func defaultNodePoolGCPImage(specifiedArch string, releaseImage *releaseinfo.Rel // MachineDeploymentComplete considers a MachineDeployment to be complete once all of its desired replicas // are updated and available, and no old machines are running. // -// In CAPI v1.11+, the controller writes status natively in v1beta2 and the v1beta1 status -// fields come from conversion. The converted v1beta1 fields (especially UpdatedReplicas, -// which maps from deprecated.v1beta1.updatedReplicas rather than the native upToDateReplicas) -// can transiently disagree with the v1beta2 native fields. To guard against this, when the -// v1beta1 fields indicate completion we cross-check against the authoritative v1beta2 status -// stored in the conversion-data annotation. +// When v1beta1 is the storage version, a v1beta1-native CAPI controller populates only the +// deprecated v1beta1 status fields; the v1beta2 conversion resets the top-level replica +// counters and only restores them from the V1Beta2 substruct (which a v1beta1 controller +// never writes). We therefore fall back to the deprecated fields when the top-level ones +// are nil. func MachineDeploymentComplete(deployment *capiv1.MachineDeployment) bool { - newStatus := &deployment.Status - v1beta1Complete := newStatus.UpdatedReplicas == *(deployment.Spec.Replicas) && - newStatus.Replicas == *(deployment.Spec.Replicas) && - newStatus.AvailableReplicas == *(deployment.Spec.Replicas) && - newStatus.ObservedGeneration >= deployment.Generation - if !v1beta1Complete { + if deployment.Status.ObservedGeneration < deployment.Generation { return false } - return machineDeploymentCompleteFromConversionData(deployment) -} -// machineDeploymentCompleteFromConversionData parses the v1beta2 conversion-data annotation -// and verifies that the native v1beta2 status also indicates completion. If the annotation -// is absent (e.g. CAPI < v1.11), returns true to preserve backwards compatibility. -func machineDeploymentCompleteFromConversionData(deployment *capiv1.MachineDeployment) bool { - raw, ok := deployment.Annotations[conversion.DataAnnotation] - if !ok { - return true + desired := ptr.Deref(deployment.Spec.Replicas, 0) + + available := ptr.Deref(deployment.Status.AvailableReplicas, 0) + replicas := ptr.Deref(deployment.Status.Replicas, 0) + + // When v1beta2 fields are populated (v1beta2-native CAPI controller or V1Beta2 substruct + // present in storage), also require UpToDateReplicas to match. + if deployment.Status.UpToDateReplicas != nil { + return ptr.Deref(deployment.Status.UpToDateReplicas, 0) == desired && + replicas == desired && + available == desired } - var v1beta2MD struct { - Spec struct { - Replicas *int32 `json:"replicas"` - } `json:"spec"` - Status struct { - ObservedGeneration int64 `json:"observedGeneration"` - Replicas *int32 `json:"replicas"` - AvailableReplicas *int32 `json:"availableReplicas"` - UpToDateReplicas *int32 `json:"upToDateReplicas"` - } `json:"status"` + // Fall back to deprecated v1beta1 fields for controllers that only write v1beta1 status. + if deployment.Status.Deprecated != nil && deployment.Status.Deprecated.V1Beta1 != nil { + dep := deployment.Status.Deprecated.V1Beta1 + return dep.UpdatedReplicas == desired && //nolint:staticcheck + dep.AvailableReplicas == desired && //nolint:staticcheck + replicas == desired } - if err := json.Unmarshal([]byte(raw), &v1beta2MD); err != nil { - ctrl.Log.WithName("nodepool").Error(err, "Failed to unmarshal conversion-data annotation, falling back to v1beta1 status") - return true + + return replicas == desired && available == desired +} + +func availableReplicasFromMachineSet(ms *capiv1.MachineSet) int32 { + if ms.Status.AvailableReplicas != nil { + return *ms.Status.AvailableReplicas + } + if ms.Status.Deprecated != nil && ms.Status.Deprecated.V1Beta1 != nil { + return ms.Status.Deprecated.V1Beta1.AvailableReplicas //nolint:staticcheck } + return 0 +} - desired := ptr.Deref(v1beta2MD.Spec.Replicas, 0) - return ptr.Deref(v1beta2MD.Status.UpToDateReplicas, 0) == desired && - ptr.Deref(v1beta2MD.Status.Replicas, 0) == desired && - ptr.Deref(v1beta2MD.Status.AvailableReplicas, 0) == desired && - v1beta2MD.Status.ObservedGeneration >= deployment.Generation +// availableReplicasFromMachineDeployment returns the number of available replicas from a MachineDeployment, +// falling back to the deprecated v1beta1 status fields when the v1beta2 top-level fields are nil. +// This fallback is necessary while v1beta1 is the storage version: the v1beta1→v1beta2 conversion +// resets the top-level AvailableReplicas to nil and only restores it from the V1Beta2 substruct, +// which a v1beta1-native CAPI controller never populates. +func availableReplicasFromMachineDeployment(deployment *capiv1.MachineDeployment) int32 { + if deployment.Status.AvailableReplicas != nil { + return *deployment.Status.AvailableReplicas + } + if deployment.Status.Deprecated != nil && deployment.Status.Deprecated.V1Beta1 != nil { + return deployment.Status.Deprecated.V1Beta1.AvailableReplicas //nolint:staticcheck + } + return 0 } // GetHostedClusterByName finds and return a HostedCluster object using the specified params. diff --git a/hypershift-operator/controllers/nodepool/nodepool_controller_test.go b/hypershift-operator/controllers/nodepool/nodepool_controller_test.go index f3ece180df0c..e37b54cd926a 100644 --- a/hypershift-operator/controllers/nodepool/nodepool_controller_test.go +++ b/hypershift-operator/controllers/nodepool/nodepool_controller_test.go @@ -34,7 +34,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -773,10 +773,10 @@ func TestFindMachineStatusCondition(t *testing.T) { name: "When condition is False it should return the condition values", machine: &capiv1.Machine{ Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "InstanceTerminated", Message: "i-0abc123def456 instance is in terminated state", }, @@ -785,7 +785,7 @@ func TestFindMachineStatusCondition(t *testing.T) { }, conditionType: string(capiv1.ReadyCondition), expected: &machineConditionResult{ - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "InstanceTerminated", Message: "i-0abc123def456 instance is in terminated state", }, @@ -794,10 +794,10 @@ func TestFindMachineStatusCondition(t *testing.T) { name: "When neither has condition it should return nil", machine: &capiv1.Machine{ Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.InfrastructureReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -809,10 +809,10 @@ func TestFindMachineStatusCondition(t *testing.T) { name: "When condition is True it should return the condition values", machine: &capiv1.Machine{ Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, Reason: "InstanceProvisionStarted", Message: "started provisioning i-0abc123def456", }, @@ -821,7 +821,7 @@ func TestFindMachineStatusCondition(t *testing.T) { }, conditionType: string(capiv1.ReadyCondition), expected: &machineConditionResult{ - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, Reason: "InstanceProvisionStarted", Message: "started provisioning i-0abc123def456", }, @@ -830,7 +830,7 @@ func TestFindMachineStatusCondition(t *testing.T) { name: "When machine has no conditions it should return nil", machine: &capiv1.Machine{ Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{}, + Conditions: []metav1.Condition{}, }, }, conditionType: string(capiv1.ReadyCondition), @@ -840,15 +840,15 @@ func TestFindMachineStatusCondition(t *testing.T) { name: "When looking up MachineNodeHealthyCondition it should return matching values", machine: &capiv1.Machine{ Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionFalse, - Reason: capiv1.NodeConditionsFailedReason, + Status: metav1.ConditionFalse, + Reason: capiv1.NodeConditionsFailedV1Beta1Reason, Message: "Condition Ready on node is reporting status False", }, }, @@ -856,8 +856,8 @@ func TestFindMachineStatusCondition(t *testing.T) { }, conditionType: string(capiv1.MachineNodeHealthyCondition), expected: &machineConditionResult{ - Status: corev1.ConditionFalse, - Reason: capiv1.NodeConditionsFailedReason, + Status: metav1.ConditionFalse, + Reason: capiv1.NodeConditionsFailedV1Beta1Reason, Message: "Condition Ready on node is reporting status False", }, }, @@ -948,14 +948,14 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -969,14 +969,14 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -1007,16 +1007,16 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode1", Message: "test message node 1", }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode1", Message: "test message node 1", }, @@ -1032,16 +1032,16 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode2", Message: "test message node 2", }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode2", Message: "test message node 2", }, @@ -1075,22 +1075,22 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode1", Message: "test message node 1", }, { Type: capiv1.InfrastructureReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode1", Message: "12 of 34 completed", }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode1", Message: "test message node 1", }, @@ -1107,22 +1107,22 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode2", Message: "test message node 2", }, { Type: capiv1.InfrastructureReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode2", Message: "some real failed message", }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode2", Message: "test message node 2", }, @@ -1139,14 +1139,14 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -1178,22 +1178,22 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode1", Message: "test message node 1", }, { Type: capiv1.InfrastructureReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode1", Message: "some real failed message", }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode1", Message: "test message node 1", }, @@ -1210,22 +1210,22 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode2", Message: "test message node 2", }, { Type: capiv1.InfrastructureReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode2", Message: "12 of 34 completed", }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode2", Message: "test message node 2", }, @@ -1242,14 +1242,14 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -1286,16 +1286,16 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode1", Message: "not ready", }, { Type: capiv1.InfrastructureReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode1", Message: longMessage, }, @@ -1313,16 +1313,16 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode2", Message: "not ready", }, { Type: capiv1.InfrastructureReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode2", Message: longMessage, }, @@ -1340,16 +1340,16 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode3", Message: "not ready", }, { Type: capiv1.InfrastructureReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "TestReasonNode3", Message: longMessage, }, @@ -1367,10 +1367,10 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -1398,14 +1398,14 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, Addresses: capiv1.MachineAddresses{ @@ -1425,14 +1425,14 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, Addresses: capiv1.MachineAddresses{ @@ -1477,10 +1477,10 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -1494,7 +1494,7 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, expectedAllNodes: &testCondition{ Status: corev1.ConditionFalse, - Reason: capiv1.WaitingForNodeRefReason, + Reason: capiv1.WaitingForNodeRefV1Beta1Reason, Messages: []string{"1 of 1 machines are not healthy", "Machine node1: WaitingForNodeRef"}, }, }, @@ -1511,10 +1511,10 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -1523,7 +1523,7 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, expectedAllMachine: &testCondition{ Status: corev1.ConditionFalse, - Reason: capiv1.WaitingForInfrastructureFallbackReason, + Reason: capiv1.WaitingForInfrastructureFallbackV1Beta1Reason, Messages: []string{"1 of 1 machines are not ready", "Machine node1: WaitingForInfrastructure"}, }, expectedAllNodes: &testCondition{ @@ -1545,15 +1545,15 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionFalse, - Reason: capiv1.NodeProvisioningReason, + Status: metav1.ConditionFalse, + Reason: capiv1.NodeProvisioningV1Beta1Reason, }, }, }, @@ -1567,8 +1567,8 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, expectedAllNodes: &testCondition{ Status: corev1.ConditionFalse, - Reason: capiv1.NodeProvisioningReason, - Messages: []string{"1 of 1 machines are not healthy", "Machine node1: " + capiv1.NodeProvisioningReason}, + Reason: capiv1.NodeProvisioningV1Beta1Reason, + Messages: []string{"1 of 1 machines are not healthy", "Machine node1: " + capiv1.NodeProvisioningV1Beta1Reason}, }, }, { @@ -1584,10 +1584,10 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -1601,15 +1601,15 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionFalse, - Reason: capiv1.NodeConditionsFailedReason, + Status: metav1.ConditionFalse, + Reason: capiv1.NodeConditionsFailedV1Beta1Reason, Message: "Condition Ready on node is reporting status False", }, }, @@ -1624,14 +1624,14 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -1645,8 +1645,8 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, expectedAllNodes: &testCondition{ Status: corev1.ConditionFalse, - Reason: capiv1.NodeConditionsFailedReason + "," + capiv1.WaitingForNodeRefReason, - Messages: []string{"2 of 3 machines are not healthy", "Machine node1: WaitingForNodeRef", "Machine node2: " + capiv1.NodeConditionsFailedReason + ": Condition Ready on node is reporting status False"}, + Reason: capiv1.NodeConditionsFailedV1Beta1Reason + "," + capiv1.WaitingForNodeRefV1Beta1Reason, + Messages: []string{"2 of 3 machines are not healthy", "Machine node1: WaitingForNodeRef", "Machine node2: " + capiv1.NodeConditionsFailedV1Beta1Reason + ": Condition Ready on node is reporting status False"}, }, }, { @@ -1662,16 +1662,16 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "InstanceTerminated", Message: "i-0abc123def456 instance is in terminated state", }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -1702,16 +1702,16 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: "InstanceProvisionStarted", Message: "3 of 7 completed", }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -1742,10 +1742,10 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -1759,16 +1759,16 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, - Reason: capiv1.MachineHasFailureReason, + Status: metav1.ConditionFalse, + Reason: capiv1.MachineHasFailureV1Beta1Reason, Message: "Machine has FailureMessage: i-0abc123def456 is in terminated state", }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -1777,8 +1777,8 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, expectedAllMachine: &testCondition{ Status: corev1.ConditionFalse, - Reason: capiv1.MachineHasFailureReason + "," + capiv1.WaitingForInfrastructureFallbackReason, - Messages: []string{"2 of 2 machines are not ready", "Machine node1: WaitingForInfrastructure", "Machine node2: " + capiv1.MachineHasFailureReason + ": Machine has FailureMessage: i-0abc123def456 is in terminated state"}, + Reason: capiv1.MachineHasFailureV1Beta1Reason + "," + capiv1.WaitingForInfrastructureFallbackV1Beta1Reason, + Messages: []string{"2 of 2 machines are not ready", "Machine node1: WaitingForInfrastructure", "Machine node2: " + capiv1.MachineHasFailureV1Beta1Reason + ": Machine has FailureMessage: i-0abc123def456 is in terminated state"}, }, expectedAllNodes: &testCondition{ Status: corev1.ConditionTrue, @@ -1809,16 +1809,16 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: fmt.Sprintf("Reason%02d", r), Message: longMsg, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: fmt.Sprintf("Reason%02d", r), Message: longMsg, }, @@ -1850,40 +1850,40 @@ func TestSetMachineAndNodeConditions(t *testing.T) { reason string message string }{ - {capiv1.WaitingForInfrastructureFallbackReason, ""}, - {capiv1.MachineHasFailureReason, "Machine has FailureReason: InsufficientCapacity"}, - {capiv1.DeletingReason, "Waiting for machine volumes to be detached"}, - {capiv1.DeletionFailedReason, "failed to delete machine"}, - {capiv1.DrainingReason, "Draining node node-4"}, - {capiv1.DrainingFailedReason, "failed to drain node: cannot evict pod"}, - {capiv1.WaitingForVolumeDetachReason, "Waiting for 2 volumes to be detached"}, - {capiv1.WaitingExternalHookReason, "Waiting for external hook to complete"}, - {capiv1.PreflightCheckFailedReason, "Machine pre-flight checks failed"}, - {capiv1.MachineCreationFailedReason, "failed to create machine: quota exceeded"}, - {capiv1.ScalingUpReason, "Scaling up to 10 replicas"}, - {capiv1.ScalingDownReason, "Scaling down to 5 replicas"}, - {capiv1.WaitingForDataSecretFallbackReason, ""}, - {capiv1.WaitingForControlPlaneFallbackReason, ""}, - {capiv1.WaitingForControlPlaneAvailableReason, "Control plane is not available"}, - {capiv1.BootstrapTemplateCloningFailedReason, "failed to clone bootstrap template"}, - {capiv1.InfrastructureTemplateCloningFailedReason, "failed to clone infrastructure template"}, - {capiv1.IncorrectExternalRefReason, "external ref is incorrect"}, - {capiv1.RemediationFailedReason, "remediation failed"}, - {capiv1.RemediationInProgressReason, "remediation in progress for node-18"}, - {capiv1.WaitingForRemediationReason, "waiting for remediation to complete"}, - {capiv1.NodeStartupTimeoutReason, "Node failed to report NodeReady condition within 20m0s"}, - {capiv1.WaitingForNodeRefReason, ""}, - {capiv1.NodeProvisioningReason, "Node is provisioning"}, - {capiv1.NodeNotFoundReason, "node not found in cluster"}, - {capiv1.NodeConditionsFailedReason, "Condition Ready on node is reporting status False"}, - {capiv1.NodeInspectionFailedReason, "failed to inspect node"}, - {capiv1.UnhealthyNodeConditionReason, "Node condition ReadonlyFilesystem is True"}, - {capiv1.HasRemediateMachineAnnotationReason, "machine has remediate annotation"}, - {capiv1.TooManyUnhealthyReason, "too many unhealthy machines: 10 of 20"}, - {capiv1.ExternalRemediationTemplateNotFoundReason, "external remediation template not found"}, - {capiv1.ExternalRemediationRequestCreationFailedReason, "failed to create external remediation request"}, - {capiv1.WaitingForControlPlaneProviderInitializedReason, "control plane provider is not initialized"}, - {capiv1.MissingNodeRefReason, "machine does not have a node ref"}, + {capiv1.WaitingForInfrastructureFallbackV1Beta1Reason, ""}, + {capiv1.MachineHasFailureV1Beta1Reason, "Machine has FailureReason: InsufficientCapacity"}, + {capiv1.DeletingV1Beta1Reason, "Waiting for machine volumes to be detached"}, + {capiv1.DeletionFailedV1Beta1Reason, "failed to delete machine"}, + {capiv1.DrainingV1Beta1Reason, "Draining node node-4"}, + {capiv1.DrainingFailedV1Beta1Reason, "failed to drain node: cannot evict pod"}, + {capiv1.WaitingForVolumeDetachV1Beta1Reason, "Waiting for 2 volumes to be detached"}, + {capiv1.WaitingExternalHookV1Beta1Reason, "Waiting for external hook to complete"}, + {capiv1.PreflightCheckFailedV1Beta1Reason, "Machine pre-flight checks failed"}, + {capiv1.MachineCreationFailedV1Beta1Reason, "failed to create machine: quota exceeded"}, + {capiv1.ScalingUpV1Beta1Reason, "Scaling up to 10 replicas"}, + {capiv1.ScalingDownV1Beta1Reason, "Scaling down to 5 replicas"}, + {capiv1.WaitingForDataSecretFallbackV1Beta1Reason, ""}, + {capiv1.WaitingForControlPlaneFallbackV1Beta1Reason, ""}, + {capiv1.WaitingForControlPlaneAvailableV1Beta1Reason, "Control plane is not available"}, + {capiv1.BootstrapTemplateCloningFailedV1Beta1Reason, "failed to clone bootstrap template"}, + {capiv1.InfrastructureTemplateCloningFailedV1Beta1Reason, "failed to clone infrastructure template"}, + {capiv1.IncorrectExternalRefV1Beta1Reason, "external ref is incorrect"}, + {capiv1.RemediationFailedV1Beta1Reason, "remediation failed"}, + {capiv1.RemediationInProgressV1Beta1Reason, "remediation in progress for node-18"}, + {capiv1.WaitingForRemediationV1Beta1Reason, "waiting for remediation to complete"}, + {capiv1.NodeStartupTimeoutV1Beta1Reason, "Node failed to report NodeReady condition within 20m0s"}, + {capiv1.WaitingForNodeRefV1Beta1Reason, ""}, + {capiv1.NodeProvisioningV1Beta1Reason, "Node is provisioning"}, + {capiv1.NodeNotFoundV1Beta1Reason, "node not found in cluster"}, + {capiv1.NodeConditionsFailedV1Beta1Reason, "Condition Ready on node is reporting status False"}, + {capiv1.NodeInspectionFailedV1Beta1Reason, "failed to inspect node"}, + {capiv1.UnhealthyNodeConditionV1Beta1Reason, "Node condition ReadonlyFilesystem is True"}, + {capiv1.HasRemediateMachineAnnotationV1Beta1Reason, "machine has remediate annotation"}, + {capiv1.TooManyUnhealthyV1Beta1Reason, "too many unhealthy machines: 10 of 20"}, + {capiv1.ExternalRemediationTemplateNotFoundV1Beta1Reason, "external remediation template not found"}, + {capiv1.ExternalRemediationRequestCreationFailedV1Beta1Reason, "failed to create external remediation request"}, + {capiv1.WaitingForControlPlaneProviderInitializedV1Beta1Reason, "control plane provider is not initialized"}, + {capiv1.MissingNodeRefV1Beta1Reason, "machine does not have a node ref"}, // Realistic cloud-provider reasons (CAPA/CAPZ) — already used in existing tests. {"InstanceTerminated", "i-0abc123def456 instance is in terminated state"}, {"InstanceProvisionFailed", "failed to create instance: InsufficientInstanceCapacity"}, @@ -1912,16 +1912,16 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: fr.reason, Message: fr.message, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: fr.reason, Message: fr.message, }, @@ -1951,16 +1951,16 @@ func TestSetMachineAndNodeConditions(t *testing.T) { reason string message string }{ - {capiv1.NodeStartupTimeoutReason, "Node failed to report NodeReady condition within 20m0s"}, - {capiv1.NodeStartupTimeoutReason, "Node failed to report NodeReady condition within 20m0s"}, - {capiv1.MachineHasFailureReason, "Machine has FailureReason: InsufficientCapacity"}, - {capiv1.MachineHasFailureReason, "Machine has FailureMessage: i-0abc123def456 is in terminated state"}, + {capiv1.NodeStartupTimeoutV1Beta1Reason, "Node failed to report NodeReady condition within 20m0s"}, + {capiv1.NodeStartupTimeoutV1Beta1Reason, "Node failed to report NodeReady condition within 20m0s"}, + {capiv1.MachineHasFailureV1Beta1Reason, "Machine has FailureReason: InsufficientCapacity"}, + {capiv1.MachineHasFailureV1Beta1Reason, "Machine has FailureMessage: i-0abc123def456 is in terminated state"}, {"InstanceTerminated", "i-0abc123def456 instance is in terminated state"}, {"InstanceTerminated", "i-0def456abc789 instance is in terminated state"}, {"InstanceProvisionFailed", "failed to create instance: InsufficientInstanceCapacity: We currently do not have sufficient capacity in the Availability Zone you requested"}, {"InstanceProvisionFailed", "failed to create instance: Unsupported: The requested configuration is currently not supported"}, - {capiv1.WaitingForInfrastructureFallbackReason, ""}, - {capiv1.WaitingForInfrastructureFallbackReason, ""}, + {capiv1.WaitingForInfrastructureFallbackV1Beta1Reason, ""}, + {capiv1.WaitingForInfrastructureFallbackV1Beta1Reason, ""}, } for i := range 10 { machines[i] = &capiv1.Machine{ @@ -1972,16 +1972,16 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionFalse, + Status: metav1.ConditionFalse, Reason: failureReasons[i].reason, Message: failureReasons[i].message, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -1997,14 +1997,14 @@ func TestSetMachineAndNodeConditions(t *testing.T) { }, }, Status: capiv1.MachineStatus{ - Conditions: []capiv1.Condition{ + Conditions: []metav1.Condition{ { Type: capiv1.ReadyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, { Type: capiv1.MachineNodeHealthyCondition, - Status: corev1.ConditionTrue, + Status: metav1.ConditionTrue, }, }, }, @@ -2090,14 +2090,14 @@ func TestTruncateReasons(t *testing.T) { }{ { name: "When reasons fit within limit it should return them unchanged", - reasons: []string{capiv1.MachineHasFailureReason, capiv1.NodeConditionsFailedReason, capiv1.WaitingForNodeRefReason}, - expectSuffix: capiv1.WaitingForNodeRefReason, + reasons: []string{capiv1.MachineHasFailureV1Beta1Reason, capiv1.NodeConditionsFailedV1Beta1Reason, capiv1.WaitingForNodeRefV1Beta1Reason}, + expectSuffix: capiv1.WaitingForNodeRefV1Beta1Reason, expectMaxLen: maxReasonLength, }, { name: "When a single reason fits within limit it should return it unchanged", - reasons: []string{capiv1.ExternalRemediationRequestCreationFailedReason}, - expectSuffix: capiv1.ExternalRemediationRequestCreationFailedReason, + reasons: []string{capiv1.ExternalRemediationRequestCreationFailedV1Beta1Reason}, + expectSuffix: capiv1.ExternalRemediationRequestCreationFailedV1Beta1Reason, expectMaxLen: maxReasonLength, }, { @@ -2108,40 +2108,40 @@ func TestTruncateReasons(t *testing.T) { { name: "When many CAPI reasons exceed limit it should truncate with ReasonsTruncated suffix", reasons: []string{ - capiv1.WaitingForInfrastructureFallbackReason, - capiv1.MachineHasFailureReason, - capiv1.DeletingReason, - capiv1.DeletionFailedReason, - capiv1.DrainingReason, - capiv1.DrainingFailedReason, - capiv1.WaitingForVolumeDetachReason, - capiv1.WaitingExternalHookReason, - capiv1.PreflightCheckFailedReason, - capiv1.MachineCreationFailedReason, - capiv1.ScalingUpReason, - capiv1.ScalingDownReason, - capiv1.WaitingForDataSecretFallbackReason, - capiv1.WaitingForControlPlaneFallbackReason, - capiv1.WaitingForControlPlaneAvailableReason, - capiv1.BootstrapTemplateCloningFailedReason, - capiv1.InfrastructureTemplateCloningFailedReason, - capiv1.IncorrectExternalRefReason, - capiv1.RemediationFailedReason, - capiv1.RemediationInProgressReason, - capiv1.WaitingForRemediationReason, - capiv1.NodeStartupTimeoutReason, - capiv1.WaitingForNodeRefReason, - capiv1.NodeProvisioningReason, - capiv1.NodeNotFoundReason, - capiv1.NodeConditionsFailedReason, - capiv1.NodeInspectionFailedReason, - capiv1.UnhealthyNodeConditionReason, - capiv1.HasRemediateMachineAnnotationReason, - capiv1.TooManyUnhealthyReason, - capiv1.ExternalRemediationTemplateNotFoundReason, - capiv1.ExternalRemediationRequestCreationFailedReason, - capiv1.WaitingForControlPlaneProviderInitializedReason, - capiv1.MissingNodeRefReason, + capiv1.WaitingForInfrastructureFallbackV1Beta1Reason, + capiv1.MachineHasFailureV1Beta1Reason, + capiv1.DeletingV1Beta1Reason, + capiv1.DeletionFailedV1Beta1Reason, + capiv1.DrainingV1Beta1Reason, + capiv1.DrainingFailedV1Beta1Reason, + capiv1.WaitingForVolumeDetachV1Beta1Reason, + capiv1.WaitingExternalHookV1Beta1Reason, + capiv1.PreflightCheckFailedV1Beta1Reason, + capiv1.MachineCreationFailedV1Beta1Reason, + capiv1.ScalingUpV1Beta1Reason, + capiv1.ScalingDownV1Beta1Reason, + capiv1.WaitingForDataSecretFallbackV1Beta1Reason, + capiv1.WaitingForControlPlaneFallbackV1Beta1Reason, + capiv1.WaitingForControlPlaneAvailableV1Beta1Reason, + capiv1.BootstrapTemplateCloningFailedV1Beta1Reason, + capiv1.InfrastructureTemplateCloningFailedV1Beta1Reason, + capiv1.IncorrectExternalRefV1Beta1Reason, + capiv1.RemediationFailedV1Beta1Reason, + capiv1.RemediationInProgressV1Beta1Reason, + capiv1.WaitingForRemediationV1Beta1Reason, + capiv1.NodeStartupTimeoutV1Beta1Reason, + capiv1.WaitingForNodeRefV1Beta1Reason, + capiv1.NodeProvisioningV1Beta1Reason, + capiv1.NodeNotFoundV1Beta1Reason, + capiv1.NodeConditionsFailedV1Beta1Reason, + capiv1.NodeInspectionFailedV1Beta1Reason, + capiv1.UnhealthyNodeConditionV1Beta1Reason, + capiv1.HasRemediateMachineAnnotationV1Beta1Reason, + capiv1.TooManyUnhealthyV1Beta1Reason, + capiv1.ExternalRemediationTemplateNotFoundV1Beta1Reason, + capiv1.ExternalRemediationRequestCreationFailedV1Beta1Reason, + capiv1.WaitingForControlPlaneProviderInitializedV1Beta1Reason, + capiv1.MissingNodeRefV1Beta1Reason, // Realistic cloud-provider reasons (CAPA/CAPZ). "InstanceTerminated", "InstanceProvisionFailed", @@ -2196,30 +2196,30 @@ func TestAggregateMachineReasonsAndMessages(t *testing.T) { { name: "When a single machine fails it should return its reason and message", messageMap: map[string][]string{ - capiv1.NodeConditionsFailedReason: { + capiv1.NodeConditionsFailedV1Beta1Reason: { "Machine machine-0: NodeConditionsFailed: Condition Ready on node is reporting status False\n", }, }, numMachines: 3, numNotReady: 1, state: aggregatorMachineStateHealthy, - expectReason: capiv1.NodeConditionsFailedReason, + expectReason: capiv1.NodeConditionsFailedV1Beta1Reason, expectMessages: []string{"1 of 3 machines are not healthy", "Machine machine-0: NodeConditionsFailed: Condition Ready on node is reporting status False"}, }, { name: "When machines fail with two reasons it should join reasons with comma", messageMap: map[string][]string{ - capiv1.MachineHasFailureReason: { + capiv1.MachineHasFailureV1Beta1Reason: { "Machine machine-0: MachineHasFailure: Machine has FailureReason: InsufficientCapacity\n", }, - capiv1.WaitingForInfrastructureFallbackReason: { + capiv1.WaitingForInfrastructureFallbackV1Beta1Reason: { "Machine machine-1: WaitingForInfrastructure\n", }, }, numMachines: 5, numNotReady: 2, state: aggregatorMachineStateReady, - expectReason: capiv1.MachineHasFailureReason + "," + capiv1.WaitingForInfrastructureFallbackReason, + expectReason: capiv1.MachineHasFailureV1Beta1Reason + "," + capiv1.WaitingForInfrastructureFallbackV1Beta1Reason, expectMessages: []string{"2 of 5 machines are not ready", "Machine machine-0: MachineHasFailure", "Machine machine-1: WaitingForInfrastructure"}, }, { @@ -2230,13 +2230,13 @@ func TestAggregateMachineReasonsAndMessages(t *testing.T) { msgs[i] = fmt.Sprintf("Machine machine-%d: MachineHasFailure: Machine has FailureMessage: i-%012d is in terminated state\n", i, i) } return map[string][]string{ - capiv1.MachineHasFailureReason: msgs, + capiv1.MachineHasFailureV1Beta1Reason: msgs, } }(), numMachines: 30, numNotReady: 30, state: aggregatorMachineStateReady, - expectReason: capiv1.MachineHasFailureReason, + expectReason: capiv1.MachineHasFailureV1Beta1Reason, expectMessages: []string{"30 of 30 machines are not ready", "Machine machine-0: MachineHasFailure", endOfMessage}, }, { @@ -2245,16 +2245,16 @@ func TestAggregateMachineReasonsAndMessages(t *testing.T) { m := make(map[string][]string) // 10 distinct reasons, each with 20 machines producing ~1000 char blocks. reasons := []string{ - capiv1.MachineHasFailureReason, - capiv1.NodeConditionsFailedReason, - capiv1.WaitingForInfrastructureFallbackReason, - capiv1.DeletingReason, - capiv1.DrainingReason, - capiv1.NodeStartupTimeoutReason, - capiv1.WaitingForNodeRefReason, - capiv1.RemediationInProgressReason, - capiv1.PreflightCheckFailedReason, - capiv1.MachineCreationFailedReason, + capiv1.MachineHasFailureV1Beta1Reason, + capiv1.NodeConditionsFailedV1Beta1Reason, + capiv1.WaitingForInfrastructureFallbackV1Beta1Reason, + capiv1.DeletingV1Beta1Reason, + capiv1.DrainingV1Beta1Reason, + capiv1.NodeStartupTimeoutV1Beta1Reason, + capiv1.WaitingForNodeRefV1Beta1Reason, + capiv1.RemediationInProgressV1Beta1Reason, + capiv1.PreflightCheckFailedV1Beta1Reason, + capiv1.MachineCreationFailedV1Beta1Reason, } longMsg := strings.Repeat("x", 80) machineIdx := 0 @@ -2277,7 +2277,7 @@ func TestAggregateMachineReasonsAndMessages(t *testing.T) { { name: "When messages within a reason are unsorted it should sort them deterministically", messageMap: map[string][]string{ - capiv1.NodeConditionsFailedReason: { + capiv1.NodeConditionsFailedV1Beta1Reason: { "Machine machine-2: NodeConditionsFailed: Condition MemoryPressure is True\n", "Machine machine-0: NodeConditionsFailed: Condition Ready is False\n", "Machine machine-1: NodeConditionsFailed: Condition DiskPressure is True\n", @@ -2286,7 +2286,7 @@ func TestAggregateMachineReasonsAndMessages(t *testing.T) { numMachines: 5, numNotReady: 3, state: aggregatorMachineStateHealthy, - expectReason: capiv1.NodeConditionsFailedReason, + expectReason: capiv1.NodeConditionsFailedV1Beta1Reason, // After sorting, machine-0 should come first, then machine-1, then machine-2. expectMessages: []string{ "3 of 5 machines are not healthy", diff --git a/hypershift-operator/controllers/nodepool/powervs.go b/hypershift-operator/controllers/nodepool/powervs.go index 7f2bf8ee9fb4..feb10ddbb87f 100644 --- a/hypershift-operator/controllers/nodepool/powervs.go +++ b/hypershift-operator/controllers/nodepool/powervs.go @@ -12,7 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" capipowervs "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "github.com/coreos/stream-metadata-go/stream" diff --git a/hypershift-operator/controllers/nodepool/scale_from_zero_test.go b/hypershift-operator/controllers/nodepool/scale_from_zero_test.go index bec100f788b2..281d8a31b655 100644 --- a/hypershift-operator/controllers/nodepool/scale_from_zero_test.go +++ b/hypershift-operator/controllers/nodepool/scale_from_zero_test.go @@ -15,7 +15,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ) type mockProvider struct { diff --git a/hypershift-operator/controllers/nodepool/version.go b/hypershift-operator/controllers/nodepool/version.go index d63ca3417daa..0b8ffeb0a395 100644 --- a/hypershift-operator/controllers/nodepool/version.go +++ b/hypershift-operator/controllers/nodepool/version.go @@ -7,9 +7,9 @@ import ( hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1" - corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ) // versionKey is used as a map key for grouping machines by version. @@ -53,7 +53,7 @@ func (r *NodePoolReconciler) nodeVersionsFromMachines(_ context.Context, machine // Determine node health from CAPI NodeHealthy condition. condition := findMachineStatusCondition(machine, string(capiv1.MachineNodeHealthyCondition)) - if condition != nil && condition.Status == corev1.ConditionTrue { + if condition != nil && condition.Status == metav1.ConditionTrue { versionCounts[key].ready++ } else { versionCounts[key].unready++ diff --git a/hypershift-operator/controllers/nodepool/version_test.go b/hypershift-operator/controllers/nodepool/version_test.go index 581ad975c5ab..714ad85701f4 100644 --- a/hypershift-operator/controllers/nodepool/version_test.go +++ b/hypershift-operator/controllers/nodepool/version_test.go @@ -13,7 +13,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" - "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" ) @@ -21,7 +21,7 @@ import ( func TestNodeVersionsFromMachines(t *testing.T) { testCases := []struct { name string - machines []*v1beta1.Machine + machines []*capiv1.Machine nodePool *hyperv1.NodePool expected []hyperv1.NodeVersion }{ @@ -35,7 +35,7 @@ func TestNodeVersionsFromMachines(t *testing.T) { }, { name: "When all machines have the same version and are healthy it should return a single entry", - machines: []*v1beta1.Machine{ + machines: []*capiv1.Machine{ machineWithVersionAndHealth("m1", "v1.31.4", true, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.18.12"}), machineWithVersionAndHealth("m2", "v1.31.4", true, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.18.12"}), machineWithVersionAndHealth("m3", "v1.31.4", true, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.18.12"}), @@ -49,7 +49,7 @@ func TestNodeVersionsFromMachines(t *testing.T) { }, { name: "When there are mixed versions during rolling upgrade it should return one entry per version", - machines: []*v1beta1.Machine{ + machines: []*capiv1.Machine{ machineWithVersionAndHealth("m1", "v1.31.4", true, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.18.12"}), machineWithVersionAndHealth("m2", "v1.31.4", true, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.18.12"}), machineWithVersionAndHealth("m3", "v1.32.1", true, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.19.1"}), @@ -64,7 +64,7 @@ func TestNodeVersionsFromMachines(t *testing.T) { }, { name: "When there is mixed health it should report ready and unready counts per version", - machines: []*v1beta1.Machine{ + machines: []*capiv1.Machine{ machineWithVersionAndHealth("m1", "v1.31.4", true, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.18.12"}), machineWithVersionAndHealth("m2", "v1.32.1", true, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.19.1"}), machineWithVersionAndHealth("m3", "v1.32.1", false, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.19.1"}), @@ -79,7 +79,7 @@ func TestNodeVersionsFromMachines(t *testing.T) { }, { name: "When NodeHealthy condition is absent it should count the node as unready", - machines: []*v1beta1.Machine{ + machines: []*capiv1.Machine{ machineWithVersionAndConditions("m1", "v1.31.4", nil, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.18.12"}), }, nodePool: &hyperv1.NodePool{ @@ -91,14 +91,14 @@ func TestNodeVersionsFromMachines(t *testing.T) { }, { name: "When some machines have no NodeInfo it should skip them", - machines: []*v1beta1.Machine{ + machines: []*capiv1.Machine{ machineWithVersionAndHealth("m1", "v1.31.4", true, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.18.12"}), { ObjectMeta: metav1.ObjectMeta{ Name: "m2", Annotations: map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.19.1"}, }, - Status: v1beta1.MachineStatus{ + Status: capiv1.MachineStatus{ // NodeInfo is nil — not yet provisioned }, }, @@ -112,10 +112,10 @@ func TestNodeVersionsFromMachines(t *testing.T) { }, { name: "When all machines have no NodeInfo it should return nil", - machines: []*v1beta1.Machine{ + machines: []*capiv1.Machine{ { ObjectMeta: metav1.ObjectMeta{Name: "m1"}, - Status: v1beta1.MachineStatus{}, + Status: capiv1.MachineStatus{}, }, }, nodePool: &hyperv1.NodePool{ @@ -125,7 +125,7 @@ func TestNodeVersionsFromMachines(t *testing.T) { }, { name: "When machine has release-version annotation it should use it for ocpVersion", - machines: []*v1beta1.Machine{ + machines: []*capiv1.Machine{ machineWithVersionAndHealth("m1", "v1.31.4", true, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.18.12"}), }, nodePool: &hyperv1.NodePool{ @@ -137,7 +137,7 @@ func TestNodeVersionsFromMachines(t *testing.T) { }, { name: "When machine has no annotation it should fall back to nodePool.Status.Version", - machines: []*v1beta1.Machine{ + machines: []*capiv1.Machine{ machineWithVersionAndHealth("m1", "v1.31.4", true, nil), }, nodePool: &hyperv1.NodePool{ @@ -149,7 +149,7 @@ func TestNodeVersionsFromMachines(t *testing.T) { }, { name: "When there are multiple versions it should sort by ocpVersion then kubeletVersion", - machines: []*v1beta1.Machine{ + machines: []*capiv1.Machine{ machineWithVersionAndHealth("m1", "v1.32.1", true, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.19.1"}), machineWithVersionAndHealth("m2", "v1.31.4", true, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.18.12"}), machineWithVersionAndHealth("m3", "v1.31.5", true, map[string]string{hyperv1.NodePoolReleaseVersionAnnotation: "4.18.12"}), @@ -214,7 +214,7 @@ func TestSetNodesInfoStatus(t *testing.T) { { name: "When machines exist with NodeInfo it should populate NodesInfo", machines: []client.Object{ - &v1beta1.Machine{ + &capiv1.Machine{ ObjectMeta: metav1.ObjectMeta{ Name: "m1", Namespace: "clusters-test-cluster", @@ -223,10 +223,10 @@ func TestSetNodesInfoStatus(t *testing.T) { hyperv1.NodePoolReleaseVersionAnnotation: "4.18.12", }, }, - Status: v1beta1.MachineStatus{ + Status: capiv1.MachineStatus{ NodeInfo: &corev1.NodeSystemInfo{KubeletVersion: "v1.31.4"}, - Conditions: v1beta1.Conditions{ - {Type: v1beta1.MachineNodeHealthyCondition, Status: corev1.ConditionTrue}, + Conditions: []metav1.Condition{ + {Type: capiv1.MachineNodeHealthyCondition, Status: metav1.ConditionStatus(corev1.ConditionTrue)}, }, }, }, @@ -252,7 +252,7 @@ func TestSetNodesInfoStatus(t *testing.T) { { name: "When all machines lack NodeInfo it should clear previously set NodesInfo", machines: []client.Object{ - &v1beta1.Machine{ + &capiv1.Machine{ ObjectMeta: metav1.ObjectMeta{ Name: "m1", Namespace: "clusters-test-cluster", @@ -260,7 +260,7 @@ func TestSetNodesInfoStatus(t *testing.T) { nodePoolAnnotation: "clusters/test-nodepool", }, }, - Status: v1beta1.MachineStatus{}, + Status: capiv1.MachineStatus{}, }, }, nodePool: &hyperv1.NodePool{ @@ -303,23 +303,23 @@ func TestSetNodesInfoStatus(t *testing.T) { } } -func machineWithVersionAndHealth(name, kubeletVersion string, healthy bool, annotations map[string]string) *v1beta1.Machine { - healthStatus := corev1.ConditionTrue +func machineWithVersionAndHealth(name, kubeletVersion string, healthy bool, annotations map[string]string) *capiv1.Machine { + healthStatus := metav1.ConditionStatus(corev1.ConditionTrue) if !healthy { - healthStatus = corev1.ConditionFalse + healthStatus = metav1.ConditionStatus(corev1.ConditionFalse) } - return machineWithVersionAndConditions(name, kubeletVersion, v1beta1.Conditions{ - {Type: v1beta1.MachineNodeHealthyCondition, Status: healthStatus}, + return machineWithVersionAndConditions(name, kubeletVersion, []metav1.Condition{ + {Type: capiv1.MachineNodeHealthyCondition, Status: healthStatus}, }, annotations) } -func machineWithVersionAndConditions(name, kubeletVersion string, conditions v1beta1.Conditions, annotations map[string]string) *v1beta1.Machine { - return &v1beta1.Machine{ +func machineWithVersionAndConditions(name, kubeletVersion string, conditions []metav1.Condition, annotations map[string]string) *capiv1.Machine { + return &capiv1.Machine{ ObjectMeta: metav1.ObjectMeta{ Name: name, Annotations: annotations, }, - Status: v1beta1.MachineStatus{ + Status: capiv1.MachineStatus{ NodeInfo: &corev1.NodeSystemInfo{KubeletVersion: kubeletVersion}, Conditions: conditions, }, diff --git a/karpenter-operator/controllers/karpenter/karpenter_controller.go b/karpenter-operator/controllers/karpenter/karpenter_controller.go index 218179a84f5b..dbc0567893fe 100644 --- a/karpenter-operator/controllers/karpenter/karpenter_controller.go +++ b/karpenter-operator/controllers/karpenter/karpenter_controller.go @@ -33,7 +33,7 @@ import ( utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/utils/ptr" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/cluster" diff --git a/karpenter-operator/controllers/karpenter/karpenter_controller_test.go b/karpenter-operator/controllers/karpenter/karpenter_controller_test.go index 7cfb9e94301a..2ce6451a9d1a 100644 --- a/karpenter-operator/controllers/karpenter/karpenter_controller_test.go +++ b/karpenter-operator/controllers/karpenter/karpenter_controller_test.go @@ -20,7 +20,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" diff --git a/support/api/capi_types.go b/support/api/capi_types.go index 3c6e71a4bba9..c6351cf7f216 100644 --- a/support/api/capi_types.go +++ b/support/api/capi_types.go @@ -9,5 +9,8 @@ import ( _ "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta1" _ "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2" _ "sigs.k8s.io/cluster-api/api/addons/v1beta1" - _ "sigs.k8s.io/cluster-api/api/core/v1beta1" + _ "sigs.k8s.io/cluster-api/api/addons/v1beta2" + _ "sigs.k8s.io/cluster-api/api/core/v1beta2" + _ "sigs.k8s.io/cluster-api/api/ipam/v1beta1" + _ "sigs.k8s.io/cluster-api/api/ipam/v1beta2" ) diff --git a/support/k8sutil/resources.go b/support/k8sutil/resources.go index ade91311e71f..0a0925d024d0 100644 --- a/support/k8sutil/resources.go +++ b/support/k8sutil/resources.go @@ -14,7 +14,7 @@ import ( capiibmv1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2" capikubevirt "sigs.k8s.io/cluster-api-provider-kubevirt/api/v1alpha1" capiopenstackv1beta1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" secretsstorev1 "sigs.k8s.io/secrets-store-csi-driver/apis/v1" ) diff --git a/support/upsert/upsert.go b/support/upsert/upsert.go index b181fd4fc730..292d9d368656 100644 --- a/support/upsert/upsert.go +++ b/support/upsert/upsert.go @@ -22,7 +22,7 @@ import ( capigcp "sigs.k8s.io/cluster-api-provider-gcp/api/v1beta1" capiibmv1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2" capikubevirt "sigs.k8s.io/cluster-api-provider-kubevirt/api/v1alpha1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" crclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) diff --git a/test/e2e/autoscaling_test.go b/test/e2e/autoscaling_test.go index 62f5c07374bd..584a615672ab 100644 --- a/test/e2e/autoscaling_test.go +++ b/test/e2e/autoscaling_test.go @@ -26,7 +26,7 @@ import ( "k8s.io/client-go/util/retry" "k8s.io/utils/ptr" capiaws "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" crclient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -779,7 +779,7 @@ func testScaleFromZero(ctx context.Context, mgtClient crclient.Client, hostedClu // Get the AWSMachineTemplate to check for Status.Capacity awsMachineTemplate := &capiaws.AWSMachineTemplate{} err = mgtClient.Get(ctx, crclient.ObjectKey{ - Namespace: md.Spec.Template.Spec.InfrastructureRef.Namespace, + Namespace: md.Namespace, Name: md.Spec.Template.Spec.InfrastructureRef.Name, }, awsMachineTemplate) if err != nil { @@ -830,7 +830,7 @@ func testScaleFromZero(ctx context.Context, mgtClient crclient.Client, hostedClu // Get the AWSMachineTemplate again to display capacity info awsMachineTemplate := &capiaws.AWSMachineTemplate{} err = mgtClient.Get(ctx, crclient.ObjectKey{ - Namespace: md.Spec.Template.Spec.InfrastructureRef.Namespace, + Namespace: md.Namespace, Name: md.Spec.Template.Spec.InfrastructureRef.Name, }, awsMachineTemplate) g.Expect(err).NotTo(HaveOccurred(), "failed to get AWSMachineTemplate for logging") diff --git a/test/e2e/nodepool_day2_tags_test.go b/test/e2e/nodepool_day2_tags_test.go index 2267acc635da..c43eebe5d6b3 100644 --- a/test/e2e/nodepool_day2_tags_test.go +++ b/test/e2e/nodepool_day2_tags_test.go @@ -17,7 +17,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" capiaws "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" crclient "sigs.k8s.io/controller-runtime/pkg/client" ) diff --git a/test/e2e/nodepool_kv_advanced_multinet_test.go b/test/e2e/nodepool_kv_advanced_multinet_test.go index 4934ced402e5..b71e54c0f09c 100644 --- a/test/e2e/nodepool_kv_advanced_multinet_test.go +++ b/test/e2e/nodepool_kv_advanced_multinet_test.go @@ -22,7 +22,7 @@ import ( "k8s.io/utils/ptr" kubevirtv1 "kubevirt.io/api/core/v1" capkv1alpha1 "sigs.k8s.io/cluster-api-provider-kubevirt/api/v1alpha1" - clusterapiv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/cluster-api/util" "sigs.k8s.io/controller-runtime/pkg/client" crclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -261,7 +261,7 @@ func (k KubeVirtAdvancedMultinetTest) firstMachineAddress() (string, error) { namespace := manifests.HostedControlPlaneNamespace(k.infra.HostedCluster().Namespace, k.infra.HostedCluster().Name) if err := k.infra.MGMTClient().List(k.infra.Ctx(), &machineList, client.InNamespace(namespace), client.MatchingLabels{ - clusterapiv1beta1.MachineDeploymentNameLabel: k.nodePoolName, + capiv1.MachineDeploymentNameLabel: k.nodePoolName, }); err != nil { return "", err } diff --git a/test/e2e/nodepool_osp_advanced_test.go b/test/e2e/nodepool_osp_advanced_test.go index 4d03a9aa2330..f7b726362ed5 100644 --- a/test/e2e/nodepool_osp_advanced_test.go +++ b/test/e2e/nodepool_osp_advanced_test.go @@ -16,7 +16,7 @@ import ( "k8s.io/utils/ptr" capiopenstackv1alpha1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha1" capiopenstackv1beta1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/cluster-api/util" crclient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -167,10 +167,10 @@ func (o OpenStackAdvancedTest) Run(t *testing.T, nodePool hyperv1.NodePool, _ [] }, []e2eutil.Predicate[*capiv1.Machine]{ func(machine *capiv1.Machine) (done bool, reasons string, err error) { - if machine.Spec.FailureDomain == nil { + if machine.Spec.FailureDomain == "" { return false, "Machine does not have a failure domain", nil } - want, got := getAZName(), *machine.Spec.FailureDomain + want, got := getAZName(), machine.Spec.FailureDomain return want == got, fmt.Sprintf("expected Machine to have failure domain %s, got %s", want, got), nil }, }, diff --git a/test/e2e/nodepool_rolling_upgrade_test.go b/test/e2e/nodepool_rolling_upgrade_test.go index 120a78dd6c84..6a3e9402c912 100644 --- a/test/e2e/nodepool_rolling_upgrade_test.go +++ b/test/e2e/nodepool_rolling_upgrade_test.go @@ -17,7 +17,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" capiaws "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" capiazure "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/cluster-api/util/labels/format" crclient "sigs.k8s.io/controller-runtime/pkg/client" ) diff --git a/test/e2e/nodepool_spot_termination_handler_test.go b/test/e2e/nodepool_spot_termination_handler_test.go index 2ade4368de71..1b4a66bfbcd7 100644 --- a/test/e2e/nodepool_spot_termination_handler_test.go +++ b/test/e2e/nodepool_spot_termination_handler_test.go @@ -20,7 +20,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" crclient "sigs.k8s.io/controller-runtime/pkg/client" ) diff --git a/test/e2e/upgrade_hypershift_operator_test.go b/test/e2e/upgrade_hypershift_operator_test.go index bf8aca31e9ef..7243355d5388 100644 --- a/test/e2e/upgrade_hypershift_operator_test.go +++ b/test/e2e/upgrade_hypershift_operator_test.go @@ -14,7 +14,7 @@ import ( e2eutil "github.com/openshift/hypershift/test/e2e/util" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" - "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" crclient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -38,7 +38,7 @@ func TestUpgradeHyperShiftOperator(t *testing.T) { var hostedCluster *hyperv1.HostedCluster var hcpNameSpace string var nodePoolsMap map[string]*hyperv1.NodePool - var machineDeploymentMap map[string]*v1beta1.MachineDeployment + var machineDeploymentMap map[string]*capiv1.MachineDeployment hyperShiftOperatorLatestImage := globalOpts.HyperShiftOperatorLatestImage @@ -110,7 +110,7 @@ func TestUpgradeHyperShiftOperator(t *testing.T) { } // Get the MachineDeployments - machineDeployments := &v1beta1.MachineDeploymentList{} + machineDeployments := &capiv1.MachineDeploymentList{} hcpNameSpace = manifests.HostedControlPlaneNamespace(hostedCluster.Namespace, hostedCluster.Name) err = mgmtClient.List(ctx, machineDeployments, crclient.InNamespace(hcpNameSpace)) @@ -122,7 +122,7 @@ func TestUpgradeHyperShiftOperator(t *testing.T) { g.Expect(len(machineDeployments.Items)).To(gomega.BeEquivalentTo(len(nodepools.Items)), "Number of MachineDeployments and NodePools should match") - machineDeploymentMap = make(map[string]*v1beta1.MachineDeployment) + machineDeploymentMap = make(map[string]*capiv1.MachineDeployment) t.Logf("Found %d MachineDeployments", len(machineDeployments.Items)) for i := range machineDeployments.Items { t.Logf("Found MachineDeployment %s", machineDeployments.Items[i].Name) @@ -202,7 +202,7 @@ func TestUpgradeHyperShiftOperator(t *testing.T) { } } - postUpgradeMachineDeployments := &v1beta1.MachineDeploymentList{} + postUpgradeMachineDeployments := &capiv1.MachineDeploymentList{} err = mgmtClient.List(ctx, postUpgradeMachineDeployments, crclient.InNamespace(hcpNameSpace)) if err != nil { gomega.StopTrying(fmt.Sprintf("Error listing MachineDeployments: %v", err)).Now() @@ -213,7 +213,7 @@ func TestUpgradeHyperShiftOperator(t *testing.T) { } for _, machineDeployment := range postUpgradeMachineDeployments.Items { t.Logf("Verifying MachineDeployment %s", machineDeployment.Name) - var preUpgradeMachineDeployment *v1beta1.MachineDeployment + var preUpgradeMachineDeployment *capiv1.MachineDeployment var ok bool if preUpgradeMachineDeployment, ok = machineDeploymentMap[machineDeployment.Name]; !ok { gomega.StopTrying(fmt.Sprintf("MachineDeployment %s not found", machineDeployment.Name)).Now() diff --git a/test/e2e/util/util.go b/test/e2e/util/util.go index 27359db6b2a6..9f81bc8804b0 100644 --- a/test/e2e/util/util.go +++ b/test/e2e/util/util.go @@ -73,7 +73,7 @@ import ( "k8s.io/client-go/util/retry" "k8s.io/utils/ptr" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" crclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" diff --git a/test/e2e/v2/backuprestore/cleanup.go b/test/e2e/v2/backuprestore/cleanup.go index d33dd1b32795..4d62c531dd74 100644 --- a/test/e2e/v2/backuprestore/cleanup.go +++ b/test/e2e/v2/backuprestore/cleanup.go @@ -20,7 +20,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/discovery" - capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta1" + capiv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" crclient "sigs.k8s.io/controller-runtime/pkg/client" ) 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 8486514f0a18..cfc63ec4be22 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 @@ -419,6 +419,26 @@ type HostedControlPlaneStatus struct { // configuration contains the cluster configuration status of the HostedCluster // +optional Configuration *ConfigurationStatus `json:"configuration,omitempty"` + + // initialization contains fields that track the status of the initialization of the HostedControlPlane. + // This satisfies the CAPI v1beta2 ControlPlane provider contract: + // https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + // +optional + Initialization HostedControlPlaneInitializationStatus `json:"initialization,omitzero"` +} + +// HostedControlPlaneInitializationStatus provides observations of the HostedControlPlane initialization process. +// This satisfies the CAPI v1beta2 ControlPlane provider contract: +// https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1361-L1379 +// +kubebuilder:validation:MinProperties=1 +type HostedControlPlaneInitializationStatus struct { + // controlPlaneInitialized is true when the control plane is functional enough to accept requests. + // Once this condition is marked true, its value is never changed. See the Ready condition for an + // indication of the current readiness of the cluster's control plane. + // This satisfies CAPI contract https://github.com/kubernetes-sigs/cluster-api/blob/v1.11.5/api/core/v1beta2/cluster_types.go#L1371-L1379 + // +optional + // +default=false + ControlPlaneInitialized *bool `json:"controlPlaneInitialized,omitempty"` } // APIEndpoint represents a reachable Kubernetes API endpoint. diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go index 454f86378499..b9e2e2546e76 100644 --- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go @@ -2500,6 +2500,26 @@ func (in *HostedControlPlane) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HostedControlPlaneInitializationStatus) DeepCopyInto(out *HostedControlPlaneInitializationStatus) { + *out = *in + if in.ControlPlaneInitialized != nil { + in, out := &in.ControlPlaneInitialized, &out.ControlPlaneInitialized + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostedControlPlaneInitializationStatus. +func (in *HostedControlPlaneInitializationStatus) DeepCopy() *HostedControlPlaneInitializationStatus { + if in == nil { + return nil + } + out := new(HostedControlPlaneInitializationStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HostedControlPlaneList) DeepCopyInto(out *HostedControlPlaneList) { *out = *in @@ -2697,6 +2717,7 @@ func (in *HostedControlPlaneStatus) DeepCopyInto(out *HostedControlPlaneStatus) *out = new(ConfigurationStatus) (*in).DeepCopyInto(*out) } + in.Initialization.DeepCopyInto(&out.Initialization) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostedControlPlaneStatus.