Skip to content

Commit 1c66d11

Browse files
authored
✨ taint propagation: machine related API changes, conversion and feature gate (#12936)
* taint propagation: machine related API changes, conversion and feature gate * make generate * taint propagation: implement validation * taint propagation: implement validation unit tests * taint propagation: in-place propagate via MachineDeployment and MachineSet * taint propagation: implement propagation in machine controller * taint propagation: implement unit tests for machine controller * fixup arbitrary test * fix generate * rebase fixes * Review changes v1 * make generate * Review changes v2 * make generate * Review fixes v3 * Update unit tests * fix tests after rebase * Review fixes v4 * Review fixes v5 * Review fixes * fixup godoc and make generate
1 parent 28caab0 commit 1c66d11

38 files changed

+1680
-59
lines changed

api/core/v1beta1/conversion.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ func (src *Machine) ConvertTo(dstRaw conversion.Hub) error {
408408
// Recover other values.
409409
if ok {
410410
dst.Spec.MinReadySeconds = restored.Spec.MinReadySeconds
411+
dst.Spec.Taints = restored.Spec.Taints
411412
// Restore the phase, this also means that any client using v1beta1 during a round-trip
412413
// won't be able to write the Phase field. But that's okay as the only client writing the Phase
413414
// field should be the Machine controller.
@@ -450,6 +451,17 @@ func (src *MachineSet) ConvertTo(dstRaw conversion.Hub) error {
450451
dst.Spec.Template.Spec.MinReadySeconds = &src.Spec.MinReadySeconds
451452
}
452453

454+
restored := &clusterv1.MachineSet{}
455+
ok, err := utilconversion.UnmarshalData(src, restored)
456+
if err != nil {
457+
return err
458+
}
459+
460+
// Recover other values
461+
if ok {
462+
dst.Spec.Template.Spec.Taints = restored.Spec.Template.Spec.Taints
463+
}
464+
453465
return nil
454466
}
455467

@@ -467,7 +479,8 @@ func (dst *MachineSet) ConvertFrom(srcRaw conversion.Hub) error {
467479
dst.Spec.MinReadySeconds = ptr.Deref(src.Spec.Template.Spec.MinReadySeconds, 0)
468480

469481
dropEmptyStringsMachineSpec(&dst.Spec.Template.Spec)
470-
return nil
482+
483+
return utilconversion.MarshalData(src, dst)
471484
}
472485

473486
func (src *MachineDeployment) ConvertTo(dstRaw conversion.Hub) error {
@@ -492,6 +505,11 @@ func (src *MachineDeployment) ConvertTo(dstRaw conversion.Hub) error {
492505
// Recover intent for bool values converted to *bool.
493506
clusterv1.Convert_bool_To_Pointer_bool(src.Spec.Paused, ok, restored.Spec.Paused, &dst.Spec.Paused)
494507

508+
// Recover other values
509+
if ok {
510+
dst.Spec.Template.Spec.Taints = restored.Spec.Template.Spec.Taints
511+
}
512+
495513
return nil
496514
}
497515

@@ -578,6 +596,11 @@ func (src *MachinePool) ConvertTo(dstRaw conversion.Hub) error {
578596
dst.Status.Initialization = initialization
579597
}
580598

599+
// Recover other values
600+
if ok {
601+
dst.Spec.Template.Spec.Taints = restored.Spec.Template.Spec.Taints
602+
}
603+
581604
return nil
582605
}
583606

api/core/v1beta1/zz_generated.conversion.go

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

api/core/v1beta2/common_types.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ const (
9999
// AnnotationsFromMachineAnnotation is the annotation set on nodes to track the annotations that originated from machines.
100100
AnnotationsFromMachineAnnotation = "cluster.x-k8s.io/annotations-from-machine"
101101

102+
// TaintsFromMachineAnnotation is the annotation set on nodes to track the taints that originated from machines.
103+
TaintsFromMachineAnnotation = "cluster.x-k8s.io/taints-from-machine"
104+
102105
// OwnerNameAnnotation is the annotation set on nodes identifying the owner name.
103106
OwnerNameAnnotation = "cluster.x-k8s.io/owner-name"
104107

@@ -405,3 +408,58 @@ func (r *ContractVersionedObjectReference) GroupKind() schema.GroupKind {
405408
Kind: r.Kind,
406409
}
407410
}
411+
412+
// MachineTaint defines a taint equivalent to corev1.Taint, but additionally having a propagation field.
413+
type MachineTaint struct {
414+
// key is the taint key to be applied to a node.
415+
// Must be a valid qualified name of maximum size 63 characters
416+
// with an optional subdomain prefix of maximum size 253 characters,
417+
// separated by a `/`.
418+
// +required
419+
// +kubebuilder:validation:MinLength=1
420+
// +kubebuilder:validation:MaxLength=317
421+
// +kubebuilder:validation:Pattern=^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/)?([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$
422+
// +kubebuilder:validation:XValidation:rule="self.contains('/') ? ( self.split('/') [0].size() <= 253 && self.split('/') [1].size() <= 63 && self.split('/').size() == 2 ) : self.size() <= 63",message="key must be a valid qualified name of max size 63 characters with an optional subdomain prefix of max size 253 characters"
423+
Key string `json:"key,omitempty"`
424+
425+
// value is the taint value corresponding to the taint key.
426+
// It must be a valid label value of maximum size 63 characters.
427+
// +optional
428+
// +kubebuilder:validation:MinLength=1
429+
// +kubebuilder:validation:MaxLength=63
430+
// +kubebuilder:validation:Pattern=^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$
431+
Value string `json:"value,omitempty"`
432+
433+
// effect is the effect for the taint. Valid values are NoSchedule, PreferNoSchedule and NoExecute.
434+
// +required
435+
// +kubebuilder:validation:Enum=NoSchedule;PreferNoSchedule;NoExecute
436+
Effect corev1.TaintEffect `json:"effect,omitempty"`
437+
438+
// propagation defines how this taint should be propagated to nodes.
439+
// Valid values are 'Always' and 'OnInitialization'.
440+
// Always: The taint will be continuously reconciled. If it is not set for a node, it will be added during reconciliation.
441+
// OnInitialization: The taint will be added during node initialization. If it gets removed from the node later on it will not get added again.
442+
// +required
443+
Propagation MachineTaintPropagation `json:"propagation,omitempty"`
444+
}
445+
446+
// MachineTaintPropagation defines when a taint should be propagated to nodes.
447+
// +kubebuilder:validation:Enum=Always;OnInitialization
448+
type MachineTaintPropagation string
449+
450+
const (
451+
// MachineTaintPropagationAlways means the taint should be continuously reconciled and kept on the node.
452+
// - If an Always taint is added to the Machine, the taint will be added to the node.
453+
// - If an Always taint is removed from the Machine, the taint will be removed from the node.
454+
// - If an OnInitialization taint is changed to Always, the Machine controller will ensure the taint is set on the node.
455+
// - If an Always taint is removed from the node, it will be re-added during reconciliation.
456+
MachineTaintPropagationAlways MachineTaintPropagation = "Always"
457+
458+
// MachineTaintPropagationOnInitialization means the taint should be set once during initialization and then
459+
// left alone.
460+
// - If an OnInitialization taint is added to the Machine, the taint will only be added to the node on initialization.
461+
// - If an OnInitialization taint is removed from the Machine nothing will be changed on the node.
462+
// - If an Always taint is changed to OnInitialization, the taint will only be added to the node on initialization.
463+
// - If an OnInitialization taint is removed from the node, it will not be re-added during reconciliation.
464+
MachineTaintPropagationOnInitialization MachineTaintPropagation = "OnInitialization"
465+
)

api/core/v1beta2/machine_types.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,23 @@ type MachineSpec struct {
488488
// deletion contains configuration options for Machine deletion.
489489
// +optional
490490
Deletion MachineDeletionSpec `json:"deletion,omitempty,omitzero"`
491+
492+
// taints are the node taints that Cluster API will manage.
493+
// This list is not necessarily complete: other Kubernetes components may add or remove other taints from nodes,
494+
// e.g. the node controller might add the node.kubernetes.io/not-ready taint.
495+
// Only those taints defined in this list will be added or removed by core Cluster API controllers.
496+
//
497+
// There can be at most 64 taints.
498+
// A pod would have to tolerate all existing taints to run on the corresponding node.
499+
//
500+
// NOTE: This list is implemented as a "map" type, meaning that individual elements can be managed by different owners.
501+
// +optional
502+
// +listType=map
503+
// +listMapKey=key
504+
// +listMapKey=effect
505+
// +kubebuilder:validation:MinItems=1
506+
// +kubebuilder:validation:MaxItems=64
507+
Taints []MachineTaint `json:"taints,omitempty"`
491508
}
492509

493510
// MachineDeletionSpec contains configuration options for Machine deletion.

api/core/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.

api/core/v1beta2/zz_generated.openapi.go

Lines changed: 67 additions & 1 deletion
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_machinedeployments.yaml

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

0 commit comments

Comments
 (0)