Skip to content

Commit 5883e99

Browse files
committed
Add Conditions to MachineSet.
* MachinesCreatedCondition * MachinesReadyCondition * ReadyCondition * ResizedCondition
1 parent dffe1ce commit 5883e99

File tree

8 files changed

+340
-21
lines changed

8 files changed

+340
-21
lines changed

api/v1alpha3/conversion.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,35 @@ func (dst *MachineList) ConvertFrom(srcRaw conversion.Hub) error {
130130
func (src *MachineSet) ConvertTo(dstRaw conversion.Hub) error {
131131
dst := dstRaw.(*v1alpha4.MachineSet)
132132

133-
return Convert_v1alpha3_MachineSet_To_v1alpha4_MachineSet(src, dst, nil)
133+
if err := Convert_v1alpha3_MachineSet_To_v1alpha4_MachineSet(src, dst, nil); err != nil {
134+
return err
135+
}
136+
// Manually restore data.
137+
restored := &v1alpha4.MachineSet{}
138+
if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok {
139+
return err
140+
}
141+
dst.Status.Conditions = restored.Status.Conditions
142+
return nil
134143
}
135144

136145
func (dst *MachineSet) ConvertFrom(srcRaw conversion.Hub) error {
137146
src := srcRaw.(*v1alpha4.MachineSet)
138147

139-
return Convert_v1alpha4_MachineSet_To_v1alpha3_MachineSet(src, dst, nil)
148+
if err := Convert_v1alpha4_MachineSet_To_v1alpha3_MachineSet(src, dst, nil); err != nil {
149+
return err
150+
}
151+
152+
// Preserve Hub data on down-conversion except for metadata
153+
if err := utilconversion.MarshalData(src, dst); err != nil {
154+
return err
155+
}
156+
return nil
157+
}
158+
159+
// Status.Conditions was introduced in v1alpha4, thus requiring a custom conversion function; the values is going to be preserved in an annotation thus allowing roundtrip without loosing informations
160+
func Convert_v1alpha4_MachineSetStatus_To_v1alpha3_MachineSetStatus(in *v1alpha4.MachineSetStatus, out *MachineSetStatus, s apiconversion.Scope) error {
161+
return autoConvert_v1alpha4_MachineSetStatus_To_v1alpha3_MachineSetStatus(in, out, s)
140162
}
141163

142164
func (src *MachineSetList) ConvertTo(dstRaw conversion.Hub) error {

api/v1alpha3/zz_generated.conversion.go

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

api/v1alpha4/condition_consts.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,36 @@ const (
218218
// WaitingForAvailableMachinesReason (Severity=Warning) reflects the fact that the required minimum number of machines for a machinedeployment are not available.
219219
WaitingForAvailableMachinesReason = "WaitingForAvailableMachines"
220220
)
221+
222+
// Conditions and condition Reasons for MachineSets
223+
224+
const (
225+
// MachinesCreatedCondition documents that the machines controlled by the MachineSet are created.
226+
// When this condition is false, it indicates that there was an error when cloning the infrastructure/bootstrap template or
227+
// when generating the machine object.
228+
MachinesCreatedCondition ConditionType = "MachinesCreated"
229+
230+
// MachinesReadyCondition reports an aggregate of current status of the machines controlled by the MachineSet.
231+
MachinesReadyCondition ConditionType = "MachinesReady"
232+
233+
// BootstrapTemplateCloningFailedReason (Severity=Error) documents a MachineSet failing to
234+
// clone the bootstrap template.
235+
BootstrapTemplateCloningFailedReason = "BootstrapTemplateCloningFailed"
236+
237+
// InfrastructureTemplateCloningFailedReason (Severity=Error) documents a MachineSet failing to
238+
// clone the infrastructure template.
239+
InfrastructureTemplateCloningFailedReason = "InfrastructureTemplateCloningFailed"
240+
241+
// MachineCreationFailedReason (Severity=Error) documents a MachineSet failing to
242+
// generate a machine object.
243+
MachineCreationFailedReason = "MachineCreationFailed"
244+
245+
// ResizedCondition documents a MachineSet is resizing the set of controlled machines.
246+
ResizedCondition ConditionType = "Resized"
247+
248+
// ScalingUpReason (Severity=Info) documents a MachineSet is increasing the number of replicas.
249+
ScalingUpReason = "ScalingUp"
250+
251+
// ScalingDownReason (Severity=Info) documents a MachineSet is decreasing the number of replicas.
252+
ScalingDownReason = "ScalingDown"
253+
)

api/v1alpha4/machineset_types.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ type MachineSetStatus struct {
157157
FailureReason *capierrors.MachineSetStatusError `json:"failureReason,omitempty"`
158158
// +optional
159159
FailureMessage *string `json:"failureMessage,omitempty"`
160+
// Conditions defines current service state of the MachineSet.
161+
// +optional
162+
Conditions Conditions `json:"conditions,omitempty"`
160163
}
161164

162165
// ANCHOR_END: MachineSetStatus
@@ -214,3 +217,13 @@ type MachineSetList struct {
214217
func init() {
215218
SchemeBuilder.Register(&MachineSet{}, &MachineSetList{})
216219
}
220+
221+
// GetConditions returns the set of conditions for the MachineSet.
222+
func (m *MachineSet) GetConditions() Conditions {
223+
return m.Status.Conditions
224+
}
225+
226+
// SetConditions updates the set of conditions on the MachineSet.
227+
func (m *MachineSet) SetConditions(conditions Conditions) {
228+
m.Status.Conditions = conditions
229+
}

api/v1alpha4/zz_generated.deepcopy.go

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

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,50 @@ spec:
735735
minReadySeconds) for this MachineSet.
736736
format: int32
737737
type: integer
738+
conditions:
739+
description: Conditions defines current service state of the MachineSet.
740+
items:
741+
description: Condition defines an observation of a Cluster API resource
742+
operational state.
743+
properties:
744+
lastTransitionTime:
745+
description: Last time the condition transitioned from one status
746+
to another. This should be when the underlying condition changed.
747+
If that is not known, then using the time when the API field
748+
changed is acceptable.
749+
format: date-time
750+
type: string
751+
message:
752+
description: A human readable message indicating details about
753+
the transition. This field may be empty.
754+
type: string
755+
reason:
756+
description: The reason for the condition's last transition
757+
in CamelCase. The specific API may choose whether or not this
758+
field is considered a guaranteed API. This field may not be
759+
empty.
760+
type: string
761+
severity:
762+
description: Severity provides an explicit classification of
763+
Reason code, so the users or machines can immediately understand
764+
the current situation and act accordingly. The Severity field
765+
MUST be set only when Status=False.
766+
type: string
767+
status:
768+
description: Status of the condition, one of True, False, Unknown.
769+
type: string
770+
type:
771+
description: Type of condition in CamelCase or in foo.example.com/CamelCase.
772+
Many .condition.type values are consistent across resources
773+
like Available, but because arbitrary conditions can be useful
774+
(see .node.status.conditions), the ability to deconflict is
775+
important.
776+
type: string
777+
required:
778+
- status
779+
- type
780+
type: object
781+
type: array
738782
failureMessage:
739783
type: string
740784
failureReason:

controllers/machineset_controller.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"sigs.k8s.io/cluster-api/controllers/remote"
3737
"sigs.k8s.io/cluster-api/util"
3838
"sigs.k8s.io/cluster-api/util/annotations"
39+
"sigs.k8s.io/cluster-api/util/collections"
3940
"sigs.k8s.io/cluster-api/util/conditions"
4041
utilconversion "sigs.k8s.io/cluster-api/util/conversion"
4142
"sigs.k8s.io/cluster-api/util/patch"
@@ -143,7 +144,7 @@ func (r *MachineSetReconciler) Reconcile(ctx context.Context, req ctrl.Request)
143144

144145
defer func() {
145146
// Always attempt to patch the object and status after each reconciliation.
146-
if err := patchHelper.Patch(ctx, machineSet); err != nil {
147+
if err := patchMachineSet(ctx, patchHelper, machineSet); err != nil {
147148
reterr = kerrors.NewAggregate([]error{reterr, err})
148149
}
149150
}()
@@ -162,6 +163,28 @@ func (r *MachineSetReconciler) Reconcile(ctx context.Context, req ctrl.Request)
162163
return result, err
163164
}
164165

166+
func patchMachineSet(ctx context.Context, patchHelper *patch.Helper, machineSet *clusterv1.MachineSet, options ...patch.Option) error {
167+
// Always update the readyCondition by summarizing the state of other conditions.
168+
conditions.SetSummary(machineSet,
169+
conditions.WithConditions(
170+
clusterv1.MachinesCreatedCondition,
171+
clusterv1.ResizedCondition,
172+
clusterv1.MachinesReadyCondition,
173+
),
174+
)
175+
176+
// Patch the object, ignoring conflicts on the conditions owned by this controller.
177+
options = append(options,
178+
patch.WithOwnedConditions{Conditions: []clusterv1.ConditionType{
179+
clusterv1.ReadyCondition,
180+
clusterv1.MachinesCreatedCondition,
181+
clusterv1.ResizedCondition,
182+
clusterv1.MachinesReadyCondition,
183+
}},
184+
)
185+
return patchHelper.Patch(ctx, machineSet, options...)
186+
}
187+
165188
func (r *MachineSetReconciler) reconcile(ctx context.Context, cluster *clusterv1.Cluster, machineSet *clusterv1.MachineSet) (ctrl.Result, error) {
166189
log := ctrl.LoggerFrom(ctx)
167190
log.V(4).Info("Reconcile MachineSet")
@@ -350,6 +373,7 @@ func (r *MachineSetReconciler) syncReplicas(ctx context.Context, ms *clusterv1.M
350373
Labels: machine.Labels,
351374
})
352375
if err != nil {
376+
conditions.MarkFalse(ms, clusterv1.MachinesCreatedCondition, clusterv1.BootstrapTemplateCloningFailedReason, clusterv1.ConditionSeverityError, err.Error())
353377
return errors.Wrapf(err, "failed to clone bootstrap configuration for MachineSet %q in namespace %q", ms.Name, ms.Namespace)
354378
}
355379
machine.Spec.Bootstrap.ConfigRef = bootstrapRef
@@ -364,6 +388,7 @@ func (r *MachineSetReconciler) syncReplicas(ctx context.Context, ms *clusterv1.M
364388
Annotations: machine.Annotations,
365389
})
366390
if err != nil {
391+
conditions.MarkFalse(ms, clusterv1.MachinesCreatedCondition, clusterv1.InfrastructureTemplateCloningFailedReason, clusterv1.ConditionSeverityError, err.Error())
367392
return errors.Wrapf(err, "failed to clone infrastructure configuration for MachineSet %q in namespace %q", ms.Name, ms.Namespace)
368393
}
369394
machine.Spec.InfrastructureRef = *infraRef
@@ -372,6 +397,8 @@ func (r *MachineSetReconciler) syncReplicas(ctx context.Context, ms *clusterv1.M
372397
log.Error(err, "Unable to create Machine", "machine", machine.Name)
373398
r.recorder.Eventf(ms, corev1.EventTypeWarning, "FailedCreate", "Failed to create machine %q: %v", machine.Name, err)
374399
errs = append(errs, err)
400+
conditions.MarkFalse(ms, clusterv1.MachinesCreatedCondition, clusterv1.MachineCreationFailedReason,
401+
clusterv1.ConditionSeverityError, err.Error())
375402

376403
// Try to cleanup the external objects if the Machine creation failed.
377404
if err := r.Client.Delete(ctx, util.ObjectReferenceToUnstructured(*infraRef)); !apierrors.IsNotFound(err) {
@@ -601,6 +628,7 @@ func (r *MachineSetReconciler) updateStatus(ctx context.Context, cluster *cluste
601628
fullyLabeledReplicasCount := 0
602629
readyReplicasCount := 0
603630
availableReplicasCount := 0
631+
desiredReplicas := *ms.Spec.Replicas
604632
templateLabel := labels.Set(ms.Spec.Template.Labels).AsSelectorPreValidated()
605633

606634
for _, machine := range filteredMachines {
@@ -644,12 +672,35 @@ func (r *MachineSetReconciler) updateStatus(ctx context.Context, cluster *cluste
644672
newStatus.DeepCopyInto(&ms.Status)
645673

646674
log.V(4).Info(fmt.Sprintf("Updating status for %v: %s/%s, ", ms.Kind, ms.Namespace, ms.Name) +
647-
fmt.Sprintf("replicas %d->%d (need %d), ", ms.Status.Replicas, newStatus.Replicas, *ms.Spec.Replicas) +
675+
fmt.Sprintf("replicas %d->%d (need %d), ", ms.Status.Replicas, newStatus.Replicas, desiredReplicas) +
648676
fmt.Sprintf("fullyLabeledReplicas %d->%d, ", ms.Status.FullyLabeledReplicas, newStatus.FullyLabeledReplicas) +
649677
fmt.Sprintf("readyReplicas %d->%d, ", ms.Status.ReadyReplicas, newStatus.ReadyReplicas) +
650678
fmt.Sprintf("availableReplicas %d->%d, ", ms.Status.AvailableReplicas, newStatus.AvailableReplicas) +
651679
fmt.Sprintf("sequence No: %v->%v", ms.Status.ObservedGeneration, newStatus.ObservedGeneration))
652680
}
681+
switch {
682+
// We are scaling up
683+
case newStatus.Replicas < desiredReplicas:
684+
conditions.MarkFalse(ms, clusterv1.ResizedCondition, clusterv1.ScalingUpReason, clusterv1.ConditionSeverityWarning, "Scaling up MachineSet to %d replicas (actual %d)", desiredReplicas, newStatus.Replicas)
685+
// We are scaling down
686+
case newStatus.Replicas > desiredReplicas:
687+
conditions.MarkFalse(ms, clusterv1.ResizedCondition, clusterv1.ScalingDownReason, clusterv1.ConditionSeverityWarning, "Scaling down MachineSet to %d replicas (actual %d)", desiredReplicas, newStatus.Replicas)
688+
// This means that there was no error in generating the desired number of machine objects
689+
conditions.MarkTrue(ms, clusterv1.MachinesCreatedCondition)
690+
default:
691+
// Make sure last resize operation is marked as completed.
692+
// NOTE: we are checking the number of machines ready so we report resize completed only when the machines
693+
// are actually provisioned (vs reporting completed immediately after the last machine object is created). This convention is also used by KCP.
694+
if newStatus.ReadyReplicas == newStatus.Replicas {
695+
conditions.MarkTrue(ms, clusterv1.ResizedCondition)
696+
}
697+
// This means that there was no error in generating the desired number of machine objects
698+
conditions.MarkTrue(ms, clusterv1.MachinesCreatedCondition)
699+
}
700+
701+
// Aggregate the operational state of all the machines; while aggregating we are adding the
702+
// source ref (reason@machine/name) so the problem can be easily tracked down to its source machine.
703+
conditions.SetAggregate(ms, clusterv1.MachinesReadyCondition, collections.FromMachines(filteredMachines...).ConditionGetters(), conditions.AddSourceRef(), conditions.WithStepCounterIf(false))
653704

654705
return nil
655706
}

0 commit comments

Comments
 (0)