diff --git a/api/v1beta1/conversion.go b/api/v1beta1/conversion.go index a2cdc3b88330..085ad3744791 100644 --- a/api/v1beta1/conversion.go +++ b/api/v1beta1/conversion.go @@ -478,6 +478,12 @@ func Convert_v1beta2_MachineStatus_To_v1beta1_MachineStatus(in *clusterv1.Machin out.FailureMessage = in.Deprecated.V1Beta1.FailureMessage } + // Move initialization to old fields + if in.Initialization != nil { + out.BootstrapReady = in.Initialization.BootstrapDataSecretCreated + out.InfrastructureReady = in.Initialization.InfrastructureProvisioned + } + // Move new conditions (v1beta2) to the v1beta2 field. if in.Conditions == nil { return nil @@ -501,6 +507,15 @@ func Convert_v1beta1_MachineStatus_To_v1beta2_MachineStatus(in *MachineStatus, o out.Conditions = in.V1Beta2.Conditions } + // Move BootstrapReady and InfrastructureReady to Initialization + if in.BootstrapReady || in.InfrastructureReady { + if out.Initialization == nil { + out.Initialization = &clusterv1.MachineInitializationStatus{} + } + out.Initialization.BootstrapDataSecretCreated = in.BootstrapReady + out.Initialization.InfrastructureProvisioned = in.InfrastructureReady + } + // Move legacy conditions (v1beta1), failureReason and failureMessage to the deprecated field. if in.Conditions == nil && in.FailureReason == nil && in.FailureMessage == nil { return nil diff --git a/api/v1beta1/conversion_test.go b/api/v1beta1/conversion_test.go index 37780fb70016..44456ca3f5fd 100644 --- a/api/v1beta1/conversion_test.go +++ b/api/v1beta1/conversion_test.go @@ -225,6 +225,13 @@ func hubMachineStatus(in *clusterv1.MachineStatus, c fuzz.Continue) { in.Deprecated = nil } } + + // Drop empty structs with only omit empty fields. + if in.Initialization != nil { + if reflect.DeepEqual(in.Initialization, &clusterv1.MachineInitializationStatus{}) { + in.Initialization = nil + } + } } func spokeMachineStatus(in *MachineStatus, c fuzz.Continue) { diff --git a/api/v1beta1/zz_generated.conversion.go b/api/v1beta1/zz_generated.conversion.go index 8d7457a4d3b2..729071b8dcd6 100644 --- a/api/v1beta1/zz_generated.conversion.go +++ b/api/v1beta1/zz_generated.conversion.go @@ -3159,8 +3159,8 @@ func autoConvert_v1beta1_MachineStatus_To_v1beta2_MachineStatus(in *MachineStatu out.Addresses = *(*v1beta2.MachineAddresses)(unsafe.Pointer(&in.Addresses)) out.Phase = in.Phase out.CertificatesExpiryDate = (*v1.Time)(unsafe.Pointer(in.CertificatesExpiryDate)) - out.BootstrapReady = in.BootstrapReady - out.InfrastructureReady = in.InfrastructureReady + // WARNING: in.BootstrapReady requires manual conversion: does not exist in peer-type + // WARNING: in.InfrastructureReady requires manual conversion: does not exist in peer-type out.ObservedGeneration = in.ObservedGeneration if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -3190,14 +3190,13 @@ func autoConvert_v1beta2_MachineStatus_To_v1beta1_MachineStatus(in *v1beta2.Mach } else { out.Conditions = nil } + // WARNING: in.Initialization requires manual conversion: does not exist in peer-type out.NodeRef = (*corev1.ObjectReference)(unsafe.Pointer(in.NodeRef)) out.NodeInfo = (*corev1.NodeSystemInfo)(unsafe.Pointer(in.NodeInfo)) out.LastUpdated = (*v1.Time)(unsafe.Pointer(in.LastUpdated)) out.Addresses = *(*MachineAddresses)(unsafe.Pointer(&in.Addresses)) out.Phase = in.Phase out.CertificatesExpiryDate = (*v1.Time)(unsafe.Pointer(in.CertificatesExpiryDate)) - out.BootstrapReady = in.BootstrapReady - out.InfrastructureReady = in.InfrastructureReady out.ObservedGeneration = in.ObservedGeneration out.Deletion = (*MachineDeletionStatus)(unsafe.Pointer(in.Deletion)) // WARNING: in.Deprecated requires manual conversion: does not exist in peer-type diff --git a/api/v1beta2/machine_types.go b/api/v1beta2/machine_types.go index 023e9bc3a9b3..8ac7374aa1d1 100644 --- a/api/v1beta2/machine_types.go +++ b/api/v1beta2/machine_types.go @@ -509,6 +509,11 @@ type MachineStatus struct { // +kubebuilder:validation:MaxItems=32 Conditions []metav1.Condition `json:"conditions,omitempty"` + // initialization provides observations of the Machine initialization process. + // NOTE: Fields in this struct are part of the Cluster API contract and are used to orchestrate initial Machine provisioning. + // +optional + Initialization *MachineInitializationStatus `json:"initialization,omitempty"` + // nodeRef will point to the corresponding Node if it exists. // +optional NodeRef *corev1.ObjectReference `json:"nodeRef,omitempty"` @@ -537,14 +542,6 @@ type MachineStatus struct { // +optional CertificatesExpiryDate *metav1.Time `json:"certificatesExpiryDate,omitempty"` - // bootstrapReady is the state of the bootstrap provider. - // +optional - BootstrapReady bool `json:"bootstrapReady"` - - // infrastructureReady is the state of the infrastructure provider. - // +optional - InfrastructureReady bool `json:"infrastructureReady"` - // observedGeneration is the latest generation observed by the controller. // +optional ObservedGeneration int64 `json:"observedGeneration,omitempty"` @@ -559,6 +556,22 @@ type MachineStatus struct { Deprecated *MachineDeprecatedStatus `json:"deprecated,omitempty"` } +// MachineInitializationStatus provides observations of the Machine initialization process. +// NOTE: Fields in this struct are part of the Cluster API contract and are used to orchestrate initial Machine provisioning. +type MachineInitializationStatus struct { + // infrastructureProvisioned is true when the infrastructure provider reports that Machine's infrastructure is fully provisioned. + // NOTE: this field is part of the Cluster API contract, and it is used to orchestrate provisioning. + // The value of this field is never updated after provisioning is completed. + // +optional + InfrastructureProvisioned bool `json:"infrastructureProvisioned"` + + // bootstrapDataSecretCreated is true when the bootstrap provider reports that the Machine's boostrap secret is created. + // NOTE: this field is part of the Cluster API contract, and it is used to orchestrate provisioning. + // The value of this field is never updated after provisioning is completed. + // +optional + BootstrapDataSecretCreated bool `json:"bootstrapDataSecretCreated"` +} + // MachineDeprecatedStatus groups all the status fields that are deprecated and will be removed in a future version. // See https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/proposals/20240916-improve-status-in-CAPI-resources.md for more context. type MachineDeprecatedStatus struct { diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go index 02d4f467186e..33bbe510560d 100644 --- a/api/v1beta2/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -2045,6 +2045,21 @@ func (in *MachineHealthCheckV1Beta1DeprecatedStatus) DeepCopy() *MachineHealthCh return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineInitializationStatus) DeepCopyInto(out *MachineInitializationStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineInitializationStatus. +func (in *MachineInitializationStatus) DeepCopy() *MachineInitializationStatus { + if in == nil { + return nil + } + out := new(MachineInitializationStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MachineList) DeepCopyInto(out *MachineList) { *out = *in @@ -2536,6 +2551,11 @@ func (in *MachineStatus) DeepCopyInto(out *MachineStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Initialization != nil { + in, out := &in.Initialization, &out.Initialization + *out = new(MachineInitializationStatus) + **out = **in + } if in.NodeRef != nil { in, out := &in.NodeRef, &out.NodeRef *out = new(v1.ObjectReference) diff --git a/api/v1beta2/zz_generated.openapi.go b/api/v1beta2/zz_generated.openapi.go index 6fe5bbf26818..cd9bcb183168 100644 --- a/api/v1beta2/zz_generated.openapi.go +++ b/api/v1beta2/zz_generated.openapi.go @@ -93,6 +93,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "sigs.k8s.io/cluster-api/api/v1beta2.MachineHealthCheckStatus": schema_sigsk8sio_cluster_api_api_v1beta2_MachineHealthCheckStatus(ref), "sigs.k8s.io/cluster-api/api/v1beta2.MachineHealthCheckTopology": schema_sigsk8sio_cluster_api_api_v1beta2_MachineHealthCheckTopology(ref), "sigs.k8s.io/cluster-api/api/v1beta2.MachineHealthCheckV1Beta1DeprecatedStatus": schema_sigsk8sio_cluster_api_api_v1beta2_MachineHealthCheckV1Beta1DeprecatedStatus(ref), + "sigs.k8s.io/cluster-api/api/v1beta2.MachineInitializationStatus": schema_sigsk8sio_cluster_api_api_v1beta2_MachineInitializationStatus(ref), "sigs.k8s.io/cluster-api/api/v1beta2.MachineList": schema_sigsk8sio_cluster_api_api_v1beta2_MachineList(ref), "sigs.k8s.io/cluster-api/api/v1beta2.MachineNamingStrategy": schema_sigsk8sio_cluster_api_api_v1beta2_MachineNamingStrategy(ref), "sigs.k8s.io/cluster-api/api/v1beta2.MachinePoolClass": schema_sigsk8sio_cluster_api_api_v1beta2_MachinePoolClass(ref), @@ -3500,6 +3501,35 @@ func schema_sigsk8sio_cluster_api_api_v1beta2_MachineHealthCheckV1Beta1Deprecate } } +func schema_sigsk8sio_cluster_api_api_v1beta2_MachineInitializationStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MachineInitializationStatus provides observations of the Machine initialization process. NOTE: Fields in this struct are part of the Cluster API contract and are used to orchestrate initial Machine provisioning.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "infrastructureProvisioned": { + SchemaProps: spec.SchemaProps{ + Description: "infrastructureProvisioned is true when the infrastructure provider reports that Machine's infrastructure is fully provisioned. NOTE: this field is part of the Cluster API contract, and it is used to orchestrate provisioning. The value of this field is never updated after provisioning is completed.", + Default: false, + Type: []string{"boolean"}, + Format: "", + }, + }, + "bootstrapDataSecretCreated": { + SchemaProps: spec.SchemaProps{ + Description: "bootstrapDataSecretCreated is true when the bootstrap provider reports that the Machine's boostrap secret is created. NOTE: this field is part of the Cluster API contract, and it is used to orchestrate provisioning. The value of this field is never updated after provisioning is completed.", + Default: false, + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + }, + }, + } +} + func schema_sigsk8sio_cluster_api_api_v1beta2_MachineList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -4365,6 +4395,12 @@ func schema_sigsk8sio_cluster_api_api_v1beta2_MachineStatus(ref common.Reference }, }, }, + "initialization": { + SchemaProps: spec.SchemaProps{ + Description: "initialization provides observations of the Machine initialization process. NOTE: Fields in this struct are part of the Cluster API contract and are used to orchestrate initial Machine provisioning.", + Ref: ref("sigs.k8s.io/cluster-api/api/v1beta2.MachineInitializationStatus"), + }, + }, "nodeRef": { SchemaProps: spec.SchemaProps{ Description: "nodeRef will point to the corresponding Node if it exists.", @@ -4410,22 +4446,6 @@ func schema_sigsk8sio_cluster_api_api_v1beta2_MachineStatus(ref common.Reference Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, - "bootstrapReady": { - SchemaProps: spec.SchemaProps{ - Description: "bootstrapReady is the state of the bootstrap provider.", - Default: false, - Type: []string{"boolean"}, - Format: "", - }, - }, - "infrastructureReady": { - SchemaProps: spec.SchemaProps{ - Description: "infrastructureReady is the state of the infrastructure provider.", - Default: false, - Type: []string{"boolean"}, - Format: "", - }, - }, "observedGeneration": { SchemaProps: spec.SchemaProps{ Description: "observedGeneration is the latest generation observed by the controller.", @@ -4449,7 +4469,7 @@ func schema_sigsk8sio_cluster_api_api_v1beta2_MachineStatus(ref common.Reference }, }, Dependencies: []string{ - "k8s.io/api/core/v1.NodeSystemInfo", "k8s.io/api/core/v1.ObjectReference", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time", "sigs.k8s.io/cluster-api/api/v1beta2.MachineAddress", "sigs.k8s.io/cluster-api/api/v1beta2.MachineDeletionStatus", "sigs.k8s.io/cluster-api/api/v1beta2.MachineDeprecatedStatus"}, + "k8s.io/api/core/v1.NodeSystemInfo", "k8s.io/api/core/v1.ObjectReference", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time", "sigs.k8s.io/cluster-api/api/v1beta2.MachineAddress", "sigs.k8s.io/cluster-api/api/v1beta2.MachineDeletionStatus", "sigs.k8s.io/cluster-api/api/v1beta2.MachineDeprecatedStatus", "sigs.k8s.io/cluster-api/api/v1beta2.MachineInitializationStatus"}, } } diff --git a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go index cd0f540a8556..e143fc2c1869 100644 --- a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go +++ b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go @@ -1166,12 +1166,16 @@ func TestBootstrapTokenTTLExtension(t *testing.T) { patchHelper, err := patch.NewHelper(workerMachine, myclient) g.Expect(err).ShouldNot(HaveOccurred()) - workerMachine.Status.InfrastructureReady = true + workerMachine.Status.Initialization = &clusterv1.MachineInitializationStatus{ + InfrastructureProvisioned: true, + } g.Expect(patchHelper.Patch(ctx, workerMachine)).To(Succeed()) patchHelper, err = patch.NewHelper(controlPlaneJoinMachine, myclient) g.Expect(err).ShouldNot(HaveOccurred()) - controlPlaneJoinMachine.Status.InfrastructureReady = true + controlPlaneJoinMachine.Status.Initialization = &clusterv1.MachineInitializationStatus{ + InfrastructureProvisioned: true, + } g.Expect(patchHelper.Patch(ctx, controlPlaneJoinMachine)).To(Succeed()) for _, req := range []ctrl.Request{ diff --git a/bootstrap/util/configowner.go b/bootstrap/util/configowner.go index 540f948ac03a..9fb5a1017f31 100644 --- a/bootstrap/util/configowner.go +++ b/bootstrap/util/configowner.go @@ -42,7 +42,14 @@ type ConfigOwner struct { // IsInfrastructureReady extracts infrastructure status from the config owner. func (co ConfigOwner) IsInfrastructureReady() bool { - infrastructureReady, _, err := unstructured.NestedBool(co.Object, "status", "infrastructureReady") + if co.IsMachinePool() { + infrastructureReady, _, err := unstructured.NestedBool(co.Object, "status", "infrastructureReady") + if err != nil { + return false + } + return infrastructureReady + } + infrastructureReady, _, err := unstructured.NestedBool(co.Object, "status", "initialization", "infrastructureProvisioned") if err != nil { return false } diff --git a/bootstrap/util/configowner_test.go b/bootstrap/util/configowner_test.go index 6779cc653030..f6fd5d31bdb1 100644 --- a/bootstrap/util/configowner_test.go +++ b/bootstrap/util/configowner_test.go @@ -58,7 +58,9 @@ func TestGetConfigOwner(t *testing.T) { Version: ptr.To("v1.19.6"), }, Status: clusterv1.MachineStatus{ - InfrastructureReady: true, + Initialization: &clusterv1.MachineInitializationStatus{ + InfrastructureProvisioned: true, + }, }, } @@ -215,7 +217,9 @@ func TestHasNodeRefs(t *testing.T) { Namespace: metav1.NamespaceDefault, }, Status: clusterv1.MachineStatus{ - InfrastructureReady: true, + Initialization: &clusterv1.MachineInitializationStatus{ + InfrastructureProvisioned: true, + }, NodeRef: &corev1.ObjectReference{ Kind: "Node", Namespace: metav1.NamespaceDefault, diff --git a/config/crd/bases/cluster.x-k8s.io_machines.yaml b/config/crd/bases/cluster.x-k8s.io_machines.yaml index a0851a7253ef..c19c20d01837 100644 --- a/config/crd/bases/cluster.x-k8s.io_machines.yaml +++ b/config/crd/bases/cluster.x-k8s.io_machines.yaml @@ -1747,9 +1747,6 @@ spec: - type type: object type: array - bootstrapReady: - description: bootstrapReady is the state of the bootstrap provider. - type: boolean certificatesExpiryDate: description: |- certificatesExpiryDate is the expiry date of the machine certificates. @@ -1957,10 +1954,24 @@ spec: type: string type: object type: object - infrastructureReady: - description: infrastructureReady is the state of the infrastructure - provider. - type: boolean + initialization: + description: |- + initialization provides observations of the Machine initialization process. + NOTE: Fields in this struct are part of the Cluster API contract and are used to orchestrate initial Machine provisioning. + properties: + bootstrapDataSecretCreated: + description: |- + bootstrapDataSecretCreated is true when the bootstrap provider reports that the Machine's boostrap secret is created. + NOTE: this field is part of the Cluster API contract, and it is used to orchestrate provisioning. + The value of this field is never updated after provisioning is completed. + type: boolean + infrastructureProvisioned: + description: |- + infrastructureProvisioned is true when the infrastructure provider reports that Machine's infrastructure is fully provisioned. + NOTE: this field is part of the Cluster API contract, and it is used to orchestrate provisioning. + The value of this field is never updated after provisioning is completed. + type: boolean + type: object lastUpdated: description: lastUpdated identifies when the phase of the Machine last transitioned. diff --git a/internal/apis/core/v1alpha3/conversion.go b/internal/apis/core/v1alpha3/conversion.go index e706e1783a38..3b87cc1d37d2 100644 --- a/internal/apis/core/v1alpha3/conversion.go +++ b/internal/apis/core/v1alpha3/conversion.go @@ -131,6 +131,15 @@ func (src *Machine) ConvertTo(dstRaw conversion.Hub) error { dst.Status.Deprecated.V1Beta1.FailureMessage = src.Status.FailureMessage } + // Move BootstrapReady and InfrastructureReady to Initialization + if src.Status.BootstrapReady || src.Status.InfrastructureReady { + if dst.Status.Initialization == nil { + dst.Status.Initialization = &clusterv1.MachineInitializationStatus{} + } + dst.Status.Initialization.BootstrapDataSecretCreated = src.Status.BootstrapReady + dst.Status.Initialization.InfrastructureProvisioned = src.Status.InfrastructureReady + } + // Manually restore data. restored := &clusterv1.Machine{} if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok { @@ -170,6 +179,12 @@ func (dst *Machine) ConvertFrom(srcRaw conversion.Hub) error { } } + // Move initialization to old fields + if src.Status.Initialization != nil { + dst.Status.BootstrapReady = src.Status.Initialization.BootstrapDataSecretCreated + dst.Status.InfrastructureReady = src.Status.Initialization.InfrastructureProvisioned + } + // Preserve Hub data on down-conversion except for metadata if err := utilconversion.MarshalData(src, dst); err != nil { return err diff --git a/internal/apis/core/v1alpha3/conversion_test.go b/internal/apis/core/v1alpha3/conversion_test.go index eafd7c66bd4b..979b9063d74e 100644 --- a/internal/apis/core/v1alpha3/conversion_test.go +++ b/internal/apis/core/v1alpha3/conversion_test.go @@ -83,6 +83,13 @@ func hubMachineStatus(in *clusterv1.MachineStatus, c fuzz.Continue) { in.Deprecated = nil } } + + // Drop empty structs with only omit empty fields. + if in.Initialization != nil { + if reflect.DeepEqual(in.Initialization, &clusterv1.MachineInitializationStatus{}) { + in.Initialization = nil + } + } } func spokeMachineStatus(in *MachineStatus, c fuzz.Continue) { diff --git a/internal/apis/core/v1alpha3/zz_generated.conversion.go b/internal/apis/core/v1alpha3/zz_generated.conversion.go index 560f097d4f36..da80a9fe760a 100644 --- a/internal/apis/core/v1alpha3/zz_generated.conversion.go +++ b/internal/apis/core/v1alpha3/zz_generated.conversion.go @@ -1271,8 +1271,8 @@ func autoConvert_v1alpha3_MachineStatus_To_v1beta2_MachineStatus(in *MachineStat // WARNING: in.FailureMessage requires manual conversion: does not exist in peer-type out.Addresses = *(*v1beta2.MachineAddresses)(unsafe.Pointer(&in.Addresses)) out.Phase = in.Phase - out.BootstrapReady = in.BootstrapReady - out.InfrastructureReady = in.InfrastructureReady + // WARNING: in.BootstrapReady requires manual conversion: does not exist in peer-type + // WARNING: in.InfrastructureReady requires manual conversion: does not exist in peer-type out.ObservedGeneration = in.ObservedGeneration if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -1300,14 +1300,13 @@ func autoConvert_v1beta2_MachineStatus_To_v1alpha3_MachineStatus(in *v1beta2.Mac } else { out.Conditions = nil } + // WARNING: in.Initialization requires manual conversion: does not exist in peer-type out.NodeRef = (*corev1.ObjectReference)(unsafe.Pointer(in.NodeRef)) // WARNING: in.NodeInfo requires manual conversion: does not exist in peer-type out.LastUpdated = (*v1.Time)(unsafe.Pointer(in.LastUpdated)) out.Addresses = *(*MachineAddresses)(unsafe.Pointer(&in.Addresses)) out.Phase = in.Phase // WARNING: in.CertificatesExpiryDate requires manual conversion: does not exist in peer-type - out.BootstrapReady = in.BootstrapReady - out.InfrastructureReady = in.InfrastructureReady out.ObservedGeneration = in.ObservedGeneration // WARNING: in.Deletion requires manual conversion: does not exist in peer-type // WARNING: in.Deprecated requires manual conversion: does not exist in peer-type diff --git a/internal/apis/core/v1alpha4/conversion.go b/internal/apis/core/v1alpha4/conversion.go index a6186d9d4287..50eea54e9994 100644 --- a/internal/apis/core/v1alpha4/conversion.go +++ b/internal/apis/core/v1alpha4/conversion.go @@ -219,6 +219,15 @@ func (src *Machine) ConvertTo(dstRaw conversion.Hub) error { dst.Status.Deprecated.V1Beta1.FailureMessage = src.Status.FailureMessage } + // Move BootstrapReady and InfrastructureReady to Initialization + if src.Status.BootstrapReady || src.Status.InfrastructureReady { + if dst.Status.Initialization == nil { + dst.Status.Initialization = &clusterv1.MachineInitializationStatus{} + } + dst.Status.Initialization.BootstrapDataSecretCreated = src.Status.BootstrapReady + dst.Status.Initialization.InfrastructureProvisioned = src.Status.InfrastructureReady + } + // Manually restore data. restored := &clusterv1.Machine{} if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok { @@ -257,6 +266,12 @@ func (dst *Machine) ConvertFrom(srcRaw conversion.Hub) error { } } + // Move initialization to old fields + if src.Status.Initialization != nil { + dst.Status.BootstrapReady = src.Status.Initialization.BootstrapDataSecretCreated + dst.Status.InfrastructureReady = src.Status.Initialization.InfrastructureProvisioned + } + // Preserve Hub data on down-conversion except for metadata if err := utilconversion.MarshalData(src, dst); err != nil { return err diff --git a/internal/apis/core/v1alpha4/conversion_test.go b/internal/apis/core/v1alpha4/conversion_test.go index e583b11be70a..b385a35bb27f 100644 --- a/internal/apis/core/v1alpha4/conversion_test.go +++ b/internal/apis/core/v1alpha4/conversion_test.go @@ -83,6 +83,13 @@ func hubMachineStatus(in *clusterv1.MachineStatus, c fuzz.Continue) { in.Deprecated = nil } } + + // Drop empty structs with only omit empty fields. + if in.Initialization != nil { + if reflect.DeepEqual(in.Initialization, &clusterv1.MachineInitializationStatus{}) { + in.Initialization = nil + } + } } func spokeMachineStatus(in *MachineStatus, c fuzz.Continue) { diff --git a/internal/apis/core/v1alpha4/zz_generated.conversion.go b/internal/apis/core/v1alpha4/zz_generated.conversion.go index 8816ca925e9a..1b24ce009bf5 100644 --- a/internal/apis/core/v1alpha4/zz_generated.conversion.go +++ b/internal/apis/core/v1alpha4/zz_generated.conversion.go @@ -1729,8 +1729,8 @@ func autoConvert_v1alpha4_MachineStatus_To_v1beta2_MachineStatus(in *MachineStat // WARNING: in.FailureMessage requires manual conversion: does not exist in peer-type out.Addresses = *(*v1beta2.MachineAddresses)(unsafe.Pointer(&in.Addresses)) out.Phase = in.Phase - out.BootstrapReady = in.BootstrapReady - out.InfrastructureReady = in.InfrastructureReady + // WARNING: in.BootstrapReady requires manual conversion: does not exist in peer-type + // WARNING: in.InfrastructureReady requires manual conversion: does not exist in peer-type out.ObservedGeneration = in.ObservedGeneration if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -1758,14 +1758,13 @@ func autoConvert_v1beta2_MachineStatus_To_v1alpha4_MachineStatus(in *v1beta2.Mac } else { out.Conditions = nil } + // WARNING: in.Initialization requires manual conversion: does not exist in peer-type out.NodeRef = (*corev1.ObjectReference)(unsafe.Pointer(in.NodeRef)) out.NodeInfo = (*corev1.NodeSystemInfo)(unsafe.Pointer(in.NodeInfo)) out.LastUpdated = (*v1.Time)(unsafe.Pointer(in.LastUpdated)) out.Addresses = *(*MachineAddresses)(unsafe.Pointer(&in.Addresses)) out.Phase = in.Phase // WARNING: in.CertificatesExpiryDate requires manual conversion: does not exist in peer-type - out.BootstrapReady = in.BootstrapReady - out.InfrastructureReady = in.InfrastructureReady out.ObservedGeneration = in.ObservedGeneration // WARNING: in.Deletion requires manual conversion: does not exist in peer-type // WARNING: in.Deprecated requires manual conversion: does not exist in peer-type diff --git a/internal/controllers/machine/machine_controller_phases.go b/internal/controllers/machine/machine_controller_phases.go index 2dca6d233389..f7e1c8916194 100644 --- a/internal/controllers/machine/machine_controller_phases.go +++ b/internal/controllers/machine/machine_controller_phases.go @@ -188,7 +188,10 @@ func (r *Reconciler) reconcileBootstrap(ctx context.Context, s *scope) (ctrl.Res // If the bootstrap data is populated, set ready and return. if m.Spec.Bootstrap.DataSecretName != nil { - m.Status.BootstrapReady = true + if m.Status.Initialization == nil { + m.Status.Initialization = &clusterv1.MachineInitializationStatus{} + } + m.Status.Initialization.BootstrapDataSecretCreated = true v1beta1conditions.MarkTrue(m, clusterv1.BootstrapReadyV1Beta1Condition) return ctrl.Result{}, nil } @@ -242,10 +245,13 @@ func (r *Reconciler) reconcileBootstrap(ctx context.Context, s *scope) (ctrl.Res m.Spec.Bootstrap.DataSecretName = secretName } - if !m.Status.BootstrapReady { + if m.Status.Initialization == nil || !m.Status.Initialization.BootstrapDataSecretCreated { log.Info("Bootstrap provider generated data secret", s.bootstrapConfig.GetKind(), klog.KObj(s.bootstrapConfig), "Secret", klog.KRef(m.Namespace, *secretName)) } - m.Status.BootstrapReady = true + if m.Status.Initialization == nil { + m.Status.Initialization = &clusterv1.MachineInitializationStatus{} + } + m.Status.Initialization.BootstrapDataSecretCreated = true return ctrl.Result{}, nil } @@ -266,7 +272,7 @@ func (r *Reconciler) reconcileInfrastructure(ctx context.Context, s *scope) (ctr return ctrl.Result{}, nil } - if m.Status.InfrastructureReady { + if m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned { // Infra object went missing after the machine was up and running log.Error(err, "Machine infrastructure reference has been deleted after provisioning was completed, setting failure state") if m.Status.Deprecated == nil { @@ -302,7 +308,7 @@ func (r *Reconciler) reconcileInfrastructure(ctx context.Context, s *scope) (ctr } else { provisioned = *provisionedPtr } - if provisioned && !m.Status.InfrastructureReady { + if provisioned && (m.Status.Initialization == nil || !m.Status.Initialization.InfrastructureProvisioned) { log.Info("Infrastructure provider has completed provisioning", s.infraMachine.GetKind(), klog.KObj(s.infraMachine)) } @@ -318,7 +324,7 @@ func (r *Reconciler) reconcileInfrastructure(ctx context.Context, s *scope) (ctr } // If the InfrastructureMachine is not provisioned (and it wasn't already provisioned before), return. - if !provisioned && !m.Status.InfrastructureReady { + if !provisioned && (m.Status.Initialization == nil || !m.Status.Initialization.InfrastructureProvisioned) { log.Info(fmt.Sprintf("Waiting for infrastructure provider to create machine infrastructure and set %s", contract.InfrastructureMachine().Provisioned(contractVersion).Path().String()), s.infraMachine.GetKind(), klog.KObj(s.infraMachine)) @@ -362,7 +368,10 @@ func (r *Reconciler) reconcileInfrastructure(ctx context.Context, s *scope) (ctr // - the infra machine is reporting provisioned for the first time // - the infra machine already reported provisioned (and thus m.Status.InfrastructureReady is already true and it should not flip back) m.Spec.ProviderID = providerID - m.Status.InfrastructureReady = true + if m.Status.Initialization == nil { + m.Status.Initialization = &clusterv1.MachineInitializationStatus{} + } + m.Status.Initialization.InfrastructureProvisioned = true return ctrl.Result{}, nil } diff --git a/internal/controllers/machine/machine_controller_phases_test.go b/internal/controllers/machine/machine_controller_phases_test.go index da34e71fc39e..e8c7f23ed330 100644 --- a/internal/controllers/machine/machine_controller_phases_test.go +++ b/internal/controllers/machine/machine_controller_phases_test.go @@ -109,7 +109,7 @@ func TestReconcileBootstrap(t *testing.T) { expectResult: ctrl.Result{RequeueAfter: externalReadyWait}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.BootstrapReady).To(BeFalse()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.BootstrapDataSecretCreated).To(BeFalse()) }, }, { @@ -133,7 +133,7 @@ func TestReconcileBootstrap(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.BootstrapReady).To(BeFalse()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.BootstrapDataSecretCreated).To(BeFalse()) g.Expect(m.Spec.Bootstrap.DataSecretName).To(BeNil()) }, }, @@ -158,7 +158,7 @@ func TestReconcileBootstrap(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.BootstrapReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.BootstrapDataSecretCreated).To(BeTrue()) g.Expect(m.Spec.Bootstrap.DataSecretName).NotTo(BeNil()) g.Expect(*m.Spec.Bootstrap.DataSecretName).To(Equal("secret-data")) }, @@ -187,7 +187,7 @@ func TestReconcileBootstrap(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.BootstrapReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.BootstrapDataSecretCreated).To(BeTrue()) g.Expect(m.Spec.Bootstrap.DataSecretName).NotTo(BeNil()) g.Expect(*m.Spec.Bootstrap.DataSecretName).To(Equal("secret-data")) }, @@ -218,7 +218,7 @@ func TestReconcileBootstrap(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.BootstrapReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.BootstrapDataSecretCreated).To(BeTrue()) g.Expect(m.Spec.Bootstrap.DataSecretName).NotTo(BeNil()) g.Expect(*m.Spec.Bootstrap.DataSecretName).To(Equal("secret-data")) }, @@ -243,7 +243,7 @@ func TestReconcileBootstrap(t *testing.T) { expectResult: ctrl.Result{}, expectError: true, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.BootstrapReady).To(BeFalse()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.BootstrapDataSecretCreated).To(BeFalse()) g.Expect(m.Spec.Bootstrap.DataSecretName).To(BeNil()) }, }, @@ -267,7 +267,9 @@ func TestReconcileBootstrap(t *testing.T) { }, }, Status: clusterv1.MachineStatus{ - BootstrapReady: true, + Initialization: &clusterv1.MachineInitializationStatus{ + BootstrapDataSecretCreated: true, + }, }, }, bootstrapConfig: map[string]interface{}{ @@ -287,7 +289,7 @@ func TestReconcileBootstrap(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.BootstrapReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.BootstrapDataSecretCreated).To(BeTrue()) g.Expect(*m.Spec.Bootstrap.DataSecretName).To(Equal("secret-data")) }, }, @@ -313,7 +315,9 @@ func TestReconcileBootstrap(t *testing.T) { }, }, Status: clusterv1.MachineStatus{ - BootstrapReady: true, + Initialization: &clusterv1.MachineInitializationStatus{ + BootstrapDataSecretCreated: true, + }, }, }, bootstrapConfig: nil, @@ -432,7 +436,7 @@ func TestReconcileInfrastructure(t *testing.T) { expectResult: ctrl.Result{RequeueAfter: externalReadyWait}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.InfrastructureReady).To(BeFalse()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned).To(BeFalse()) g.Expect(m.Status.Deprecated).To(BeNil()) }, }, @@ -468,7 +472,7 @@ func TestReconcileInfrastructure(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.InfrastructureReady).To(BeFalse()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned).To(BeFalse()) g.Expect(m.Spec.ProviderID).To(BeNil()) g.Expect(m.Spec.FailureDomain).To(BeNil()) g.Expect(m.Status.Addresses).To(BeNil()) @@ -496,7 +500,7 @@ func TestReconcileInfrastructure(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.InfrastructureReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned).To(BeTrue()) g.Expect(ptr.Deref(m.Spec.ProviderID, "")).To(Equal("test://id-1")) g.Expect(m.Spec.FailureDomain).To(BeNil()) g.Expect(m.Status.Addresses).To(BeNil()) @@ -526,7 +530,7 @@ func TestReconcileInfrastructure(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.InfrastructureReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned).To(BeTrue()) g.Expect(ptr.Deref(m.Spec.ProviderID, "")).To(Equal("test://id-1")) g.Expect(m.Spec.FailureDomain).To(BeNil()) g.Expect(m.Status.Addresses).To(BeNil()) @@ -555,7 +559,7 @@ func TestReconcileInfrastructure(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.InfrastructureReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned).To(BeTrue()) g.Expect(ptr.Deref(m.Spec.ProviderID, "")).To(Equal("test://id-1")) g.Expect(ptr.Deref(m.Spec.FailureDomain, "")).To(Equal("foo")) g.Expect(m.Status.Addresses).To(BeNil()) @@ -593,7 +597,7 @@ func TestReconcileInfrastructure(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.InfrastructureReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned).To(BeTrue()) g.Expect(ptr.Deref(m.Spec.ProviderID, "")).To(Equal("test://id-1")) g.Expect(m.Spec.FailureDomain).To(BeNil()) g.Expect(m.Status.Addresses).To(HaveLen(2)) @@ -632,7 +636,7 @@ func TestReconcileInfrastructure(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.InfrastructureReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned).To(BeTrue()) g.Expect(ptr.Deref(m.Spec.ProviderID, "")).To(Equal("test://id-1")) g.Expect(ptr.Deref(m.Spec.FailureDomain, "")).To(Equal("foo")) g.Expect(m.Status.Addresses).To(HaveLen(2)) @@ -674,7 +678,7 @@ func TestReconcileInfrastructure(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.InfrastructureReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned).To(BeTrue()) g.Expect(ptr.Deref(m.Spec.ProviderID, "")).To(Equal("test://id-1")) g.Expect(ptr.Deref(m.Spec.FailureDomain, "")).To(Equal("foo")) g.Expect(m.Status.Addresses).To(HaveLen(2)) @@ -719,7 +723,9 @@ func TestReconcileInfrastructure(t *testing.T) { FailureDomain: ptr.To("something"), }, Status: clusterv1.MachineStatus{ - InfrastructureReady: true, + Initialization: &clusterv1.MachineInitializationStatus{ + InfrastructureProvisioned: true, + }, Addresses: []clusterv1.MachineAddress{ { Type: clusterv1.MachineExternalIP, @@ -757,7 +763,7 @@ func TestReconcileInfrastructure(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.InfrastructureReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned).To(BeTrue()) g.Expect(ptr.Deref(m.Spec.ProviderID, "")).To(Equal("test://id-1")) g.Expect(ptr.Deref(m.Spec.FailureDomain, "")).To(Equal("foo")) g.Expect(m.Status.Addresses).To(HaveLen(2)) @@ -782,7 +788,9 @@ func TestReconcileInfrastructure(t *testing.T) { FailureDomain: ptr.To("something"), }, Status: clusterv1.MachineStatus{ - InfrastructureReady: true, + Initialization: &clusterv1.MachineInitializationStatus{ + InfrastructureProvisioned: true, + }, Addresses: []clusterv1.MachineAddress{ { Type: clusterv1.MachineExternalIP, @@ -820,7 +828,7 @@ func TestReconcileInfrastructure(t *testing.T) { expectResult: ctrl.Result{}, expectError: false, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.InfrastructureReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned).To(BeTrue()) g.Expect(ptr.Deref(m.Spec.ProviderID, "")).To(Equal("test://id-1")) g.Expect(ptr.Deref(m.Spec.FailureDomain, "")).To(Equal("foo")) g.Expect(m.Status.Addresses).To(HaveLen(2)) @@ -843,7 +851,9 @@ func TestReconcileInfrastructure(t *testing.T) { }, }, Status: clusterv1.MachineStatus{ - InfrastructureReady: true, + Initialization: &clusterv1.MachineInitializationStatus{ + InfrastructureProvisioned: true, + }, }, }, infraMachine: nil, @@ -851,7 +861,7 @@ func TestReconcileInfrastructure(t *testing.T) { expectResult: ctrl.Result{}, expectError: true, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.InfrastructureReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned).To(BeTrue()) g.Expect(m.Status.Deprecated).To(BeNil()) }, }, @@ -872,7 +882,9 @@ func TestReconcileInfrastructure(t *testing.T) { }, }, Status: clusterv1.MachineStatus{ - InfrastructureReady: true, + Initialization: &clusterv1.MachineInitializationStatus{ + InfrastructureProvisioned: true, + }, }, }, infraMachine: nil, @@ -880,7 +892,7 @@ func TestReconcileInfrastructure(t *testing.T) { expectResult: ctrl.Result{}, expectError: true, expected: func(g *WithT, m *clusterv1.Machine) { - g.Expect(m.Status.InfrastructureReady).To(BeTrue()) + g.Expect(m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned).To(BeTrue()) g.Expect(m.Status.Deprecated).ToNot(BeNil()) g.Expect(m.Status.Deprecated.V1Beta1).ToNot(BeNil()) g.Expect(m.Status.Deprecated.V1Beta1.FailureMessage).ToNot(BeNil()) @@ -906,7 +918,9 @@ func TestReconcileInfrastructure(t *testing.T) { }, }, Status: clusterv1.MachineStatus{ - InfrastructureReady: false, + Initialization: &clusterv1.MachineInitializationStatus{ + InfrastructureProvisioned: false, + }, }, }, infraMachine: nil, @@ -934,7 +948,9 @@ func TestReconcileInfrastructure(t *testing.T) { }, }, Status: clusterv1.MachineStatus{ - InfrastructureReady: true, + Initialization: &clusterv1.MachineInitializationStatus{ + InfrastructureProvisioned: true, + }, }, }, infraMachine: nil, diff --git a/internal/controllers/machine/machine_controller_status.go b/internal/controllers/machine/machine_controller_status.go index e5e58077e4b9..c7693b5e68b3 100644 --- a/internal/controllers/machine/machine_controller_status.go +++ b/internal/controllers/machine/machine_controller_status.go @@ -84,13 +84,14 @@ func setBootstrapReadyCondition(_ context.Context, machine *clusterv1.Machine, b } if bootstrapConfig != nil { + dataSecretCreated := machine.Status.Initialization != nil && machine.Status.Initialization.BootstrapDataSecretCreated ready, err := conditions.NewMirrorConditionFromUnstructured( bootstrapConfig, contract.Bootstrap().ReadyConditionType(), conditions.TargetConditionType(clusterv1.MachineBootstrapConfigReadyCondition), conditions.FallbackCondition{ - Status: conditions.BoolToStatus(machine.Status.BootstrapReady), - Reason: fallbackReason(machine.Status.BootstrapReady, clusterv1.MachineBootstrapConfigReadyReason, clusterv1.MachineBootstrapConfigNotReadyReason), - Message: bootstrapConfigReadyFallBackMessage(machine.Spec.Bootstrap.ConfigRef.Kind, machine.Status.BootstrapReady), + Status: conditions.BoolToStatus(dataSecretCreated), + Reason: fallbackReason(dataSecretCreated, clusterv1.MachineBootstrapConfigReadyReason, clusterv1.MachineBootstrapConfigNotReadyReason), + Message: bootstrapConfigReadyFallBackMessage(machine.Spec.Bootstrap.ConfigRef.Kind, dataSecretCreated), }, ) if err != nil { @@ -125,7 +126,7 @@ func setBootstrapReadyCondition(_ context.Context, machine *clusterv1.Machine, b } // Bootstrap config missing when the machine is deleting and we know that the BootstrapConfig actually existed. - if !machine.DeletionTimestamp.IsZero() && machine.Status.BootstrapReady { + if !machine.DeletionTimestamp.IsZero() && machine.Status.Initialization != nil && machine.Status.Initialization.BootstrapDataSecretCreated { conditions.Set(machine, metav1.Condition{ Type: clusterv1.MachineBootstrapConfigReadyCondition, Status: metav1.ConditionFalse, @@ -163,13 +164,14 @@ func bootstrapConfigReadyFallBackMessage(kind string, ready bool) string { func setInfrastructureReadyCondition(_ context.Context, machine *clusterv1.Machine, infraMachine *unstructured.Unstructured, infraMachineIsNotFound bool) { if infraMachine != nil { + infrastructureProvisioned := machine.Status.Initialization != nil && machine.Status.Initialization.InfrastructureProvisioned ready, err := conditions.NewMirrorConditionFromUnstructured( infraMachine, contract.InfrastructureMachine().ReadyConditionType(), conditions.TargetConditionType(clusterv1.MachineInfrastructureReadyCondition), conditions.FallbackCondition{ - Status: conditions.BoolToStatus(machine.Status.InfrastructureReady), - Reason: fallbackReason(machine.Status.InfrastructureReady, clusterv1.MachineInfrastructureReadyReason, clusterv1.MachineInfrastructureNotReadyReason), - Message: infrastructureReadyFallBackMessage(machine.Spec.InfrastructureRef.Kind, machine.Status.InfrastructureReady), + Status: conditions.BoolToStatus(infrastructureProvisioned), + Reason: fallbackReason(infrastructureProvisioned, clusterv1.MachineInfrastructureReadyReason, clusterv1.MachineInfrastructureNotReadyReason), + Message: infrastructureReadyFallBackMessage(machine.Spec.InfrastructureRef.Kind, infrastructureProvisioned), }, ) if err != nil { @@ -207,7 +209,7 @@ func setInfrastructureReadyCondition(_ context.Context, machine *clusterv1.Machi // NOTE: in case an accidental deletion happens before volume detach is completed, the Node hosted on the Machine // will be considered unreachable Machine deletion will complete. if !machine.DeletionTimestamp.IsZero() { - if machine.Status.InfrastructureReady { + if machine.Status.Initialization != nil && machine.Status.Initialization.InfrastructureProvisioned { conditions.Set(machine, metav1.Condition{ Type: clusterv1.MachineInfrastructureReadyCondition, Status: metav1.ConditionFalse, @@ -227,7 +229,7 @@ func setInfrastructureReadyCondition(_ context.Context, machine *clusterv1.Machi } // Report an issue if infra machine missing after the machine has been initialized (and the machine is still running). - if machine.Status.InfrastructureReady { + if machine.Status.Initialization != nil && machine.Status.Initialization.InfrastructureProvisioned { conditions.Set(machine, metav1.Condition{ Type: clusterv1.MachineInfrastructureReadyCondition, Status: metav1.ConditionFalse, @@ -790,7 +792,7 @@ func setMachinePhaseAndLastUpdated(_ context.Context, m *clusterv1.Machine) { } // Set the phase to "provisioning" if bootstrap is ready and the infrastructure isn't. - if m.Status.BootstrapReady && !m.Status.InfrastructureReady { + if m.Status.Initialization != nil && m.Status.Initialization.BootstrapDataSecretCreated && !m.Status.Initialization.InfrastructureProvisioned { m.Status.SetTypedPhase(clusterv1.MachinePhaseProvisioning) } @@ -800,7 +802,7 @@ func setMachinePhaseAndLastUpdated(_ context.Context, m *clusterv1.Machine) { } // Set the phase to "running" if there is a NodeRef field and infrastructure is ready. - if m.Status.NodeRef != nil && m.Status.InfrastructureReady { + if m.Status.NodeRef != nil && m.Status.Initialization != nil && m.Status.Initialization.InfrastructureProvisioned { m.Status.SetTypedPhase(clusterv1.MachinePhaseRunning) } diff --git a/internal/controllers/machine/machine_controller_status_test.go b/internal/controllers/machine/machine_controller_status_test.go index 4b24fe777219..7d28327cd314 100644 --- a/internal/controllers/machine/machine_controller_status_test.go +++ b/internal/controllers/machine/machine_controller_status_test.go @@ -168,7 +168,7 @@ func TestSetBootstrapReadyCondition(t *testing.T) { name: "Use status.BoostrapReady flag as a fallback Ready condition from bootstrap config is missing (ready true)", machine: func() *clusterv1.Machine { m := defaultMachine.DeepCopy() - m.Status.BootstrapReady = true + m.Status.Initialization = &clusterv1.MachineInitializationStatus{BootstrapDataSecretCreated: true} return m }(), bootstrapConfig: &unstructured.Unstructured{Object: map[string]interface{}{ @@ -231,7 +231,7 @@ func TestSetBootstrapReadyCondition(t *testing.T) { name: "bootstrap config that was ready not found while machine is deleting", machine: func() *clusterv1.Machine { m := defaultMachine.DeepCopy() - m.Status.BootstrapReady = true + m.Status.Initialization = &clusterv1.MachineInitializationStatus{BootstrapDataSecretCreated: true} m.SetDeletionTimestamp(&metav1.Time{Time: time.Now()}) return m }(), @@ -392,7 +392,7 @@ func TestSetInfrastructureReadyCondition(t *testing.T) { name: "Use status.InfrastructureReady flag as a fallback Ready condition from infra machine is missing (ready true)", machine: func() *clusterv1.Machine { m := defaultMachine.DeepCopy() - m.Status.InfrastructureReady = true + m.Status.Initialization = &clusterv1.MachineInitializationStatus{InfrastructureProvisioned: true} return m }(), infraMachine: &unstructured.Unstructured{Object: map[string]interface{}{ @@ -460,7 +460,7 @@ func TestSetInfrastructureReadyCondition(t *testing.T) { machine: func() *clusterv1.Machine { m := defaultMachine.DeepCopy() m.SetDeletionTimestamp(&metav1.Time{Time: time.Now()}) - m.Status.InfrastructureReady = true + m.Status.Initialization = &clusterv1.MachineInitializationStatus{InfrastructureProvisioned: true} return m }(), infraMachine: nil, @@ -492,7 +492,7 @@ func TestSetInfrastructureReadyCondition(t *testing.T) { name: "infra machine not found after the machine has been initialized", machine: func() *clusterv1.Machine { m := defaultMachine.DeepCopy() - m.Status.InfrastructureReady = true + m.Status.Initialization = &clusterv1.MachineInitializationStatus{InfrastructureProvisioned: true} return m }(), infraMachine: nil, diff --git a/internal/controllers/machinehealthcheck/machinehealthcheck_controller_test.go b/internal/controllers/machinehealthcheck/machinehealthcheck_controller_test.go index a6b497c4c376..3e6d914c132e 100644 --- a/internal/controllers/machinehealthcheck/machinehealthcheck_controller_test.go +++ b/internal/controllers/machinehealthcheck/machinehealthcheck_controller_test.go @@ -2482,10 +2482,12 @@ func newRunningMachine(c *clusterv1.Cluster, labels map[string]string) *clusterv }, }, Status: clusterv1.MachineStatus{ - InfrastructureReady: true, - BootstrapReady: true, - Phase: string(clusterv1.MachinePhaseRunning), - ObservedGeneration: 1, + Initialization: &clusterv1.MachineInitializationStatus{ + InfrastructureProvisioned: true, + BootstrapDataSecretCreated: true, + }, + Phase: string(clusterv1.MachinePhaseRunning), + ObservedGeneration: 1, }, } } diff --git a/internal/controllers/machinehealthcheck/machinehealthcheck_targets_test.go b/internal/controllers/machinehealthcheck/machinehealthcheck_targets_test.go index 771de5a90ec1..dd7cf33b7376 100644 --- a/internal/controllers/machinehealthcheck/machinehealthcheck_targets_test.go +++ b/internal/controllers/machinehealthcheck/machinehealthcheck_targets_test.go @@ -648,9 +648,11 @@ func newTestMachine(name, namespace, clusterName, nodeName string, labels map[st }, }, Status: clusterv1.MachineStatus{ - InfrastructureReady: true, - BootstrapReady: true, - Phase: string(clusterv1.MachinePhaseRunning), + Initialization: &clusterv1.MachineInitializationStatus{ + InfrastructureProvisioned: true, + BootstrapDataSecretCreated: true, + }, + Phase: string(clusterv1.MachinePhaseRunning), NodeRef: &corev1.ObjectReference{ Name: nodeName, },