Skip to content

Commit d753f40

Browse files
authored
Merge pull request #12102 from fabriziopandini/add-status-initialization-to-MachinePool
⚠️ Add initialization to MachinePool Status
2 parents 4936a19 + 5c133a1 commit d753f40

17 files changed

+197
-71
lines changed

bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1369,7 +1369,7 @@ func TestBootstrapTokenRotationMachinePool(t *testing.T) {
13691369

13701370
patchHelper, err := patch.NewHelper(workerMachinePool, myclient)
13711371
g.Expect(err).ShouldNot(HaveOccurred())
1372-
workerMachinePool.Status.InfrastructureReady = true
1372+
workerMachinePool.Status.Initialization = &expv1.MachinePoolInitializationStatus{InfrastructureProvisioned: true}
13731373
g.Expect(patchHelper.Patch(ctx, workerMachinePool, patch.WithStatusObservedGeneration{})).To(Succeed())
13741374

13751375
result, err = k.Reconcile(ctx, request)

bootstrap/util/configowner.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,8 @@ type ConfigOwner struct {
4040
*unstructured.Unstructured
4141
}
4242

43-
// IsInfrastructureReady extracts infrastructure status from the config owner.
44-
func (co ConfigOwner) IsInfrastructureReady() bool {
45-
if co.IsMachinePool() {
46-
infrastructureReady, _, err := unstructured.NestedBool(co.Object, "status", "infrastructureReady")
47-
if err != nil {
48-
return false
49-
}
50-
return infrastructureReady
51-
}
43+
// IsInfrastructureProvisioned extracts infrastructure status from the config owner.
44+
func (co ConfigOwner) IsInfrastructureProvisioned() bool {
5245
infrastructureReady, _, err := unstructured.NestedBool(co.Object, "status", "initialization", "infrastructureProvisioned")
5346
if err != nil {
5447
return false

bootstrap/util/configowner_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func TestGetConfigOwner(t *testing.T) {
8282
g.Expect(err).ToNot(HaveOccurred())
8383
g.Expect(configOwner).ToNot(BeNil())
8484
g.Expect(configOwner.ClusterName()).To(BeEquivalentTo("my-cluster"))
85-
g.Expect(configOwner.IsInfrastructureReady()).To(BeTrue())
85+
g.Expect(configOwner.IsInfrastructureProvisioned()).To(BeTrue())
8686
g.Expect(configOwner.IsControlPlaneMachine()).To(BeTrue())
8787
g.Expect(configOwner.IsMachinePool()).To(BeFalse())
8888
g.Expect(configOwner.KubernetesVersion()).To(Equal("v1.19.6"))
@@ -110,7 +110,9 @@ func TestGetConfigOwner(t *testing.T) {
110110
},
111111
},
112112
Status: expv1.MachinePoolStatus{
113-
InfrastructureReady: true,
113+
Initialization: &expv1.MachinePoolInitializationStatus{
114+
InfrastructureProvisioned: true,
115+
},
114116
},
115117
}
116118

@@ -132,7 +134,7 @@ func TestGetConfigOwner(t *testing.T) {
132134
g.Expect(err).ToNot(HaveOccurred())
133135
g.Expect(configOwner).ToNot(BeNil())
134136
g.Expect(configOwner.ClusterName()).To(BeEquivalentTo("my-cluster"))
135-
g.Expect(configOwner.IsInfrastructureReady()).To(BeTrue())
137+
g.Expect(configOwner.IsInfrastructureProvisioned()).To(BeTrue())
136138
g.Expect(configOwner.IsControlPlaneMachine()).To(BeFalse())
137139
g.Expect(configOwner.IsMachinePool()).To(BeTrue())
138140
g.Expect(configOwner.KubernetesVersion()).To(Equal("v1.19.6"))

config/crd/bases/cluster.x-k8s.io_machinepools.yaml

Lines changed: 18 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

exp/api/v1beta1/conversion.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ func Convert_v1beta2_MachinePoolStatus_To_v1beta1_MachinePoolStatus(in *expv1.Ma
6464
out.UnavailableReplicas = in.Deprecated.V1Beta1.UnavailableReplicas
6565
}
6666

67+
// Move initialization to old fields
68+
if in.Initialization != nil {
69+
out.BootstrapReady = in.Initialization.BootstrapDataSecretCreated
70+
out.InfrastructureReady = in.Initialization.InfrastructureProvisioned
71+
}
72+
6773
// Move new conditions (v1beta2) and replica counters to the v1beta2 field.
6874
if in.Conditions == nil && in.ReadyReplicas == nil && in.AvailableReplicas == nil && in.UpToDateReplicas == nil {
6975
return nil
@@ -98,6 +104,15 @@ func Convert_v1beta1_MachinePoolStatus_To_v1beta2_MachinePoolStatus(in *MachineP
98104
out.UpToDateReplicas = in.V1Beta2.UpToDateReplicas
99105
}
100106

107+
// Move BootstrapReady and InfrastructureReady to Initialization
108+
if in.BootstrapReady || in.InfrastructureReady {
109+
if out.Initialization == nil {
110+
out.Initialization = &expv1.MachinePoolInitializationStatus{}
111+
}
112+
out.Initialization.BootstrapDataSecretCreated = in.BootstrapReady
113+
out.Initialization.InfrastructureProvisioned = in.InfrastructureReady
114+
}
115+
101116
// Move legacy conditions (v1beta1), failureReason, failureMessage and replica counters to the deprecated field.
102117
if out.Deprecated == nil {
103118
out.Deprecated = &expv1.MachinePoolDeprecatedStatus{}

exp/api/v1beta1/conversion_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ func hubMachinePoolStatus(in *expv1.MachinePoolStatus, c fuzz.Continue) {
5656
if in.Deprecated.V1Beta1 == nil {
5757
in.Deprecated.V1Beta1 = &expv1.MachinePoolV1Beta1DeprecatedStatus{}
5858
}
59+
60+
// Drop empty structs with only omit empty fields.
61+
if in.Initialization != nil {
62+
if reflect.DeepEqual(in.Initialization, &expv1.MachinePoolInitializationStatus{}) {
63+
in.Initialization = nil
64+
}
65+
}
5966
}
6067

6168
func spokeMachinePoolStatus(in *MachinePoolStatus, c fuzz.Continue) {

exp/api/v1beta1/zz_generated.conversion.go

Lines changed: 3 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

exp/api/v1beta2/machinepool_types.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ type MachinePoolStatus struct {
8686
// +kubebuilder:validation:MaxItems=32
8787
Conditions []metav1.Condition `json:"conditions,omitempty"`
8888

89+
// initialization provides observations of the MachinePool initialization process.
90+
// NOTE: Fields in this struct are part of the Cluster API contract and are used to orchestrate initial MachinePool provisioning.
91+
// +optional
92+
Initialization *MachinePoolInitializationStatus `json:"initialization,omitempty"`
93+
8994
// nodeRefs will point to the corresponding Nodes if it they exist.
9095
// +optional
9196
// +kubebuilder:validation:MaxItems=10000
@@ -112,14 +117,6 @@ type MachinePoolStatus struct {
112117
// +kubebuilder:validation:Enum=Pending;Provisioning;Provisioned;Running;ScalingUp;ScalingDown;Scaling;Deleting;Failed;Unknown
113118
Phase string `json:"phase,omitempty"`
114119

115-
// bootstrapReady is the state of the bootstrap provider.
116-
// +optional
117-
BootstrapReady bool `json:"bootstrapReady"`
118-
119-
// infrastructureReady is the state of the infrastructure provider.
120-
// +optional
121-
InfrastructureReady bool `json:"infrastructureReady"`
122-
123120
// observedGeneration is the latest generation observed by the controller.
124121
// +optional
125122
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
@@ -129,6 +126,22 @@ type MachinePoolStatus struct {
129126
Deprecated *MachinePoolDeprecatedStatus `json:"deprecated,omitempty"`
130127
}
131128

129+
// MachinePoolInitializationStatus provides observations of the MachinePool initialization process.
130+
// NOTE: Fields in this struct are part of the Cluster API contract and are used to orchestrate initial MachinePool provisioning.
131+
type MachinePoolInitializationStatus struct {
132+
// infrastructureProvisioned is true when the infrastructure provider reports that MachinePool's infrastructure is fully provisioned.
133+
// NOTE: this field is part of the Cluster API contract, and it is used to orchestrate provisioning.
134+
// The value of this field is never updated after provisioning is completed.
135+
// +optional
136+
InfrastructureProvisioned bool `json:"infrastructureProvisioned"`
137+
138+
// bootstrapDataSecretCreated is true when the bootstrap provider reports that the MachinePool's boostrap secret is created.
139+
// NOTE: this field is part of the Cluster API contract, and it is used to orchestrate provisioning.
140+
// The value of this field is never updated after provisioning is completed.
141+
// +optional
142+
BootstrapDataSecretCreated bool `json:"bootstrapDataSecretCreated"`
143+
}
144+
132145
// MachinePoolDeprecatedStatus groups all the status fields that are deprecated and will be removed in a future version.
133146
// See https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/proposals/20240916-improve-status-in-CAPI-resources.md for more context.
134147
type MachinePoolDeprecatedStatus struct {

exp/api/v1beta2/zz_generated.deepcopy.go

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

exp/internal/controllers/machinepool_controller_phases.go

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func (r *MachinePoolReconciler) reconcilePhase(mp *expv1.MachinePool) {
6060
}
6161

6262
// Set the phase to "provisioning" if bootstrap is ready and the infrastructure isn't.
63-
if mp.Status.BootstrapReady && !mp.Status.InfrastructureReady {
63+
if mp.Status.Initialization != nil && mp.Status.Initialization.BootstrapDataSecretCreated && !mp.Status.Initialization.InfrastructureProvisioned {
6464
mp.Status.SetTypedPhase(expv1.MachinePoolPhaseProvisioning)
6565
}
6666

@@ -75,12 +75,12 @@ func (r *MachinePoolReconciler) reconcilePhase(mp *expv1.MachinePool) {
7575
if mp.Status.Deprecated != nil && mp.Status.Deprecated.V1Beta1 != nil {
7676
readyReplicas = mp.Status.Deprecated.V1Beta1.ReadyReplicas
7777
}
78-
if mp.Status.InfrastructureReady && mp.Spec.Replicas != nil && *mp.Spec.Replicas == readyReplicas {
78+
if mp.Status.Initialization != nil && mp.Status.Initialization.InfrastructureProvisioned && mp.Spec.Replicas != nil && *mp.Spec.Replicas == readyReplicas {
7979
mp.Status.SetTypedPhase(expv1.MachinePoolPhaseRunning)
8080
}
8181

8282
// Set the appropriate phase in response to the MachinePool replica count being greater than the observed infrastructure replicas.
83-
if mp.Status.InfrastructureReady && mp.Spec.Replicas != nil && *mp.Spec.Replicas > readyReplicas {
83+
if mp.Status.Initialization != nil && mp.Status.Initialization.InfrastructureProvisioned && mp.Spec.Replicas != nil && *mp.Spec.Replicas > readyReplicas {
8484
// If we are being managed by an external autoscaler and can't predict scaling direction, set to "Scaling".
8585
if annotations.ReplicasManagedByExternalAutoscaler(mp) {
8686
mp.Status.SetTypedPhase(expv1.MachinePoolPhaseScaling)
@@ -91,7 +91,7 @@ func (r *MachinePoolReconciler) reconcilePhase(mp *expv1.MachinePool) {
9191
}
9292

9393
// Set the appropriate phase in response to the MachinePool replica count being less than the observed infrastructure replicas.
94-
if mp.Status.InfrastructureReady && mp.Spec.Replicas != nil && *mp.Spec.Replicas < readyReplicas {
94+
if mp.Status.Initialization != nil && mp.Status.Initialization.InfrastructureProvisioned && mp.Spec.Replicas != nil && *mp.Spec.Replicas < readyReplicas {
9595
// If we are being managed by an external autoscaler and can't predict scaling direction, set to "Scaling".
9696
if annotations.ReplicasManagedByExternalAutoscaler(mp) {
9797
mp.Status.SetTypedPhase(expv1.MachinePoolPhaseScaling)
@@ -231,7 +231,10 @@ func (r *MachinePoolReconciler) reconcileBootstrap(ctx context.Context, s *scope
231231

232232
if !dataSecretCreated {
233233
log.Info("Waiting for bootstrap provider to generate data secret and report status.ready", bootstrapConfig.GetKind(), klog.KObj(bootstrapConfig))
234-
m.Status.BootstrapReady = dataSecretCreated
234+
if m.Status.Initialization == nil {
235+
m.Status.Initialization = &expv1.MachinePoolInitializationStatus{}
236+
}
237+
m.Status.Initialization.BootstrapDataSecretCreated = dataSecretCreated
235238
return ctrl.Result{}, nil
236239
}
237240

@@ -244,13 +247,19 @@ func (r *MachinePoolReconciler) reconcileBootstrap(ctx context.Context, s *scope
244247
}
245248

246249
m.Spec.Template.Spec.Bootstrap.DataSecretName = secretName
247-
m.Status.BootstrapReady = true
250+
if m.Status.Initialization == nil {
251+
m.Status.Initialization = &expv1.MachinePoolInitializationStatus{}
252+
}
253+
m.Status.Initialization.BootstrapDataSecretCreated = true
248254
return ctrl.Result{}, nil
249255
}
250256

251257
// If dataSecretName is set without a ConfigRef, this means the user brought their own bootstrap data.
252258
if m.Spec.Template.Spec.Bootstrap.DataSecretName != nil {
253-
m.Status.BootstrapReady = true
259+
if m.Status.Initialization == nil {
260+
m.Status.Initialization = &expv1.MachinePoolInitializationStatus{}
261+
}
262+
m.Status.Initialization.BootstrapDataSecretCreated = true
254263
v1beta1conditions.MarkTrue(m, clusterv1.BootstrapReadyV1Beta1Condition)
255264
return ctrl.Result{}, nil
256265
}
@@ -269,7 +278,7 @@ func (r *MachinePoolReconciler) reconcileInfrastructure(ctx context.Context, s *
269278
if err != nil {
270279
if apierrors.IsNotFound(errors.Cause(err)) {
271280
log.Error(err, "infrastructure reference could not be found")
272-
if mp.Status.InfrastructureReady {
281+
if mp.Status.Initialization != nil && mp.Status.Initialization.InfrastructureProvisioned {
273282
// Infra object went missing after the machine pool was up and running
274283
log.Error(err, "infrastructure reference has been deleted after being ready, setting failure state")
275284
if mp.Status.Deprecated == nil {
@@ -297,7 +306,10 @@ func (r *MachinePoolReconciler) reconcileInfrastructure(ctx context.Context, s *
297306
return ctrl.Result{}, err
298307
}
299308

300-
mp.Status.InfrastructureReady = ready
309+
if mp.Status.Initialization == nil {
310+
mp.Status.Initialization = &expv1.MachinePoolInitializationStatus{}
311+
}
312+
mp.Status.Initialization.InfrastructureProvisioned = ready
301313

302314
// Report a summary of current status of the infrastructure object defined for this machine pool.
303315
v1beta1conditions.SetMirror(mp, clusterv1.InfrastructureReadyV1Beta1Condition,
@@ -320,7 +332,7 @@ func (r *MachinePoolReconciler) reconcileInfrastructure(ctx context.Context, s *
320332
return ctrl.Result{}, kerrors.NewAggregate([]error{errors.Wrapf(err, "failed to reconcile Machines for MachinePool %s", klog.KObj(mp)), errors.Wrapf(getNodeRefsErr, "failed to get nodeRefs for MachinePool %s", klog.KObj(mp))})
321333
}
322334

323-
if !mp.Status.InfrastructureReady {
335+
if mp.Status.Initialization == nil && !mp.Status.Initialization.InfrastructureProvisioned {
324336
log.Info("Infrastructure provider is not yet ready", infraConfig.GetKind(), klog.KObj(infraConfig))
325337
return ctrl.Result{}, nil
326338
}

0 commit comments

Comments
 (0)