Skip to content

Commit a74e928

Browse files
Yuvaraj Kakaraparthisbueringer
Yuvaraj Kakaraparthi
authored andcommitted
cherry-pick: MachineDeployment rolloutAfter support
1 parent 32bab5e commit a74e928

File tree

17 files changed

+200
-67
lines changed

17 files changed

+200
-67
lines changed

api/v1alpha3/conversion.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ func (src *MachineDeployment) ConvertTo(dstRaw conversion.Hub) error {
199199

200200
dst.Spec.Template.Spec.NodeDeletionTimeout = restored.Spec.Template.Spec.NodeDeletionTimeout
201201
dst.Spec.Template.Spec.NodeVolumeDetachTimeout = restored.Spec.Template.Spec.NodeVolumeDetachTimeout
202+
dst.Spec.RolloutAfter = restored.Spec.RolloutAfter
202203
dst.Status.Conditions = restored.Status.Conditions
203204
return nil
204205
}
@@ -316,6 +317,10 @@ func Convert_v1beta1_MachineSpec_To_v1alpha3_MachineSpec(in *clusterv1.MachineSp
316317
return autoConvert_v1beta1_MachineSpec_To_v1alpha3_MachineSpec(in, out, s)
317318
}
318319

320+
func Convert_v1beta1_MachineDeploymentSpec_To_v1alpha3_MachineDeploymentSpec(in *clusterv1.MachineDeploymentSpec, out *MachineDeploymentSpec, s apiconversion.Scope) error {
321+
return autoConvert_v1beta1_MachineDeploymentSpec_To_v1alpha3_MachineDeploymentSpec(in, out, s)
322+
}
323+
319324
func Convert_v1beta1_MachineDeploymentStatus_To_v1alpha3_MachineDeploymentStatus(in *clusterv1.MachineDeploymentStatus, out *MachineDeploymentStatus, s apiconversion.Scope) error {
320325
// 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
321326
return autoConvert_v1beta1_MachineDeploymentStatus_To_v1alpha3_MachineDeploymentStatus(in, out, s)

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/conversion.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ func (src *MachineDeployment) ConvertTo(dstRaw conversion.Hub) error {
270270

271271
dst.Spec.Template.Spec.NodeDeletionTimeout = restored.Spec.Template.Spec.NodeDeletionTimeout
272272
dst.Spec.Template.Spec.NodeVolumeDetachTimeout = restored.Spec.Template.Spec.NodeVolumeDetachTimeout
273+
dst.Spec.RolloutAfter = restored.Spec.RolloutAfter
273274
return nil
274275
}
275276

@@ -335,6 +336,10 @@ func Convert_v1beta1_MachineSpec_To_v1alpha4_MachineSpec(in *clusterv1.MachineSp
335336
return autoConvert_v1beta1_MachineSpec_To_v1alpha4_MachineSpec(in, out, s)
336337
}
337338

339+
func Convert_v1beta1_MachineDeploymentSpec_To_v1alpha4_MachineDeploymentSpec(in *clusterv1.MachineDeploymentSpec, out *MachineDeploymentSpec, s apiconversion.Scope) error {
340+
return autoConvert_v1beta1_MachineDeploymentSpec_To_v1alpha4_MachineDeploymentSpec(in, out, s)
341+
}
342+
338343
func Convert_v1beta1_Topology_To_v1alpha4_Topology(in *clusterv1.Topology, out *Topology, s apiconversion.Scope) error {
339344
// spec.topology.variables has been added with v1beta1.
340345
return autoConvert_v1beta1_Topology_To_v1alpha4_Topology(in, out, s)

api/v1alpha4/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/v1beta1/machinedeployment_types.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ const (
6666
// As a result, we use the hash of the machine template while ignoring all in-place mutable fields, i.e. the
6767
// machine template with only fields that could trigger a rollout for the machine-template-hash, making it
6868
// independent of the changes to any in-place mutable fields.
69+
// A random string is appended at the end of the label value (label value format is "<hash>-<random string>"))
70+
// to distinguish duplicate MachineSets that have the exact same spec but were created as a result of rolloutAfter.
6971
MachineDeploymentUniqueLabel = "machine-template-hash"
7072
)
7173

@@ -97,6 +99,12 @@ type MachineDeploymentSpec struct {
9799
// +optional
98100
Replicas *int32 `json:"replicas,omitempty"`
99101

102+
// RolloutAfter is a field to indicate a rollout should be performed
103+
// after the specified time even if no changes have been made to the
104+
// MachineDeployment.
105+
// +optional
106+
RolloutAfter *metav1.Time `json:"rolloutAfter,omitempty"`
107+
100108
// Label selector for machines. Existing MachineSets whose machines are
101109
// selected by this will be the ones affected by this deployment.
102110
// It must match the machine template's labels.

api/v1beta1/zz_generated.deepcopy.go

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

api/v1beta1/zz_generated.openapi.go

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

cmd/clusterctl/client/alpha/kubeadmcontrolplane.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ func getKubeadmControlPlane(proxy cluster.Proxy, name, namespace string) (*contr
4646
return kcpObj, nil
4747
}
4848

49-
// setRolloutAfter sets KubeadmControlPlane.spec.rolloutAfter.
50-
func setRolloutAfter(proxy cluster.Proxy, name, namespace string) error {
49+
// setRolloutAfterOnKCP sets KubeadmControlPlane.spec.rolloutAfter.
50+
func setRolloutAfterOnKCP(proxy cluster.Proxy, name, namespace string) error {
5151
patch := client.RawPatch(types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"rolloutAfter":"%v"}}`, time.Now().Format(time.RFC3339))))
5252
return patchKubeadmControlPlane(proxy, name, namespace, patch)
5353
}

cmd/clusterctl/client/alpha/machinedeployment.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ func getMachineDeployment(proxy cluster.Proxy, name, namespace string) (*cluster
5252
return mdObj, nil
5353
}
5454

55-
// setRestartedAtAnnotation sets the restartedAt annotation in the MachineDeployment's spec.template.objectmeta.
56-
func setRestartedAtAnnotation(proxy cluster.Proxy, name, namespace string) error {
57-
patch := client.RawPatch(types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"template":{"metadata":{"annotations":{"cluster.x-k8s.io/restartedAt":"%v"}}}}}`, time.Now().Format(time.RFC3339))))
55+
// setRolloutAfterOnMachineDeployment sets MachineDeployment.spec.rolloutAfter.
56+
func setRolloutAfterOnMachineDeployment(proxy cluster.Proxy, name, namespace string) error {
57+
patch := client.RawPatch(types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"rolloutAfter":"%v"}}`, time.Now().Format(time.RFC3339))))
5858
return patchMachineDeployment(proxy, name, namespace, patch)
5959
}
6060

cmd/clusterctl/client/alpha/rollout_restarter.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ func (r *rollout) ObjectRestarter(proxy cluster.Proxy, ref corev1.ObjectReferenc
3737
if deployment.Spec.Paused {
3838
return errors.Errorf("can't restart paused MachineDeployment (run rollout resume first): %v/%v", ref.Kind, ref.Name)
3939
}
40-
if err := setRestartedAtAnnotation(proxy, ref.Name, ref.Namespace); err != nil {
40+
if deployment.Spec.RolloutAfter != nil && deployment.Spec.RolloutAfter.After(time.Now()) {
41+
return errors.Errorf("can't update MachineDeployment (remove 'spec.rolloutAfter' first): %v/%v", ref.Kind, ref.Name)
42+
}
43+
if err := setRolloutAfterOnMachineDeployment(proxy, ref.Name, ref.Namespace); err != nil {
4144
return err
4245
}
4346
case KubeadmControlPlane:
@@ -51,7 +54,7 @@ func (r *rollout) ObjectRestarter(proxy cluster.Proxy, ref corev1.ObjectReferenc
5154
if kcp.Spec.RolloutAfter != nil && kcp.Spec.RolloutAfter.After(time.Now()) {
5255
return errors.Errorf("can't update KubeadmControlPlane (remove 'spec.rolloutAfter' first): %v/%v", ref.Kind, ref.Name)
5356
}
54-
if err := setRolloutAfter(proxy, ref.Name, ref.Namespace); err != nil {
57+
if err := setRolloutAfterOnKCP(proxy, ref.Name, ref.Namespace); err != nil {
5558
return err
5659
}
5760
default:

cmd/clusterctl/client/alpha/rollout_restarter_test.go

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func Test_ObjectRestarter(t *testing.T) {
4343
wantRollout bool
4444
}{
4545
{
46-
name: "machinedeployment should have restart annotation",
46+
name: "machinedeployment should have rolloutAfter",
4747
fields: fields{
4848
objs: []client.Object{
4949
&clusterv1.MachineDeployment{
@@ -67,7 +67,7 @@ func Test_ObjectRestarter(t *testing.T) {
6767
wantRollout: true,
6868
},
6969
{
70-
name: "paused machinedeployment should not have restart annotation",
70+
name: "paused machinedeployment should not have rolloutAfter",
7171
fields: fields{
7272
objs: []client.Object{
7373
&clusterv1.MachineDeployment{
@@ -93,6 +93,33 @@ func Test_ObjectRestarter(t *testing.T) {
9393
wantErr: true,
9494
wantRollout: false,
9595
},
96+
{
97+
name: "machinedeployment with spec.rolloutAfter should not be updatable",
98+
fields: fields{
99+
objs: []client.Object{
100+
&clusterv1.MachineDeployment{
101+
TypeMeta: metav1.TypeMeta{
102+
Kind: "MachineDeployment",
103+
APIVersion: "cluster.x-k8s.io/v1beta1",
104+
},
105+
ObjectMeta: metav1.ObjectMeta{
106+
Namespace: "default",
107+
Name: "md-1",
108+
},
109+
Spec: clusterv1.MachineDeploymentSpec{
110+
RolloutAfter: &metav1.Time{Time: time.Now().Local().Add(time.Hour)},
111+
},
112+
},
113+
},
114+
ref: corev1.ObjectReference{
115+
Kind: MachineDeployment,
116+
Name: "md-1",
117+
Namespace: "default",
118+
},
119+
},
120+
wantErr: true,
121+
wantRollout: false,
122+
},
96123
{
97124
name: "kubeadmcontrolplane should have rolloutAfter",
98125
fields: fields{
@@ -193,9 +220,9 @@ func Test_ObjectRestarter(t *testing.T) {
193220
err = cl.Get(context.TODO(), key, md)
194221
g.Expect(err).ToNot(HaveOccurred())
195222
if tt.wantRollout {
196-
g.Expect(md.Spec.Template.Annotations).To(HaveKey("cluster.x-k8s.io/restartedAt"))
223+
g.Expect(md.Spec.RolloutAfter).NotTo(BeNil())
197224
} else {
198-
g.Expect(md.Spec.Template.Annotations).ToNot(HaveKey("cluster.x-k8s.io/restartedAt"))
225+
g.Expect(md.Spec.RolloutAfter).To(BeNil())
199226
}
200227
case *controlplanev1.KubeadmControlPlane:
201228
kcp := &controlplanev1.KubeadmControlPlane{}
@@ -204,7 +231,7 @@ func Test_ObjectRestarter(t *testing.T) {
204231
if tt.wantRollout {
205232
g.Expect(kcp.Spec.RolloutAfter).NotTo(BeNil())
206233
} else {
207-
g.Expect(kcp.Spec.RolloutAfter).To(nil)
234+
g.Expect(kcp.Spec.RolloutAfter).To(BeNil())
208235
}
209236
}
210237
}

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

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

docs/book/src/tasks/upgrading-clusters.md

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ and then both the `Version` and `InfrastructureTemplate` should be modified in a
4949

5050
#### How to schedule a machine rollout
5151

52-
A `KubeadmControlPlane` resource has a field `RolloutAfter` that can be set to a timestamp
53-
(RFC-3339) after which a rollout should be triggered regardless of whether there were any changes
54-
to the `KubeadmControlPlane.Spec` or not. This would roll out replacement control plane nodes
55-
which can be useful e.g. to perform certificate rotation, reflect changes to machine templates,
56-
move to new machines, etc.
52+
The `KubeadmControlPlane` and `MachineDepoyment` resources have a field `RolloutAfter` that can be
53+
set to a timestamp (RFC-3339) after which a rollout should be triggered regardless of whether there
54+
were any changes to `KubeadmControlPlane.Spec`/`MachineDeployment.Spec.Template` or not. This would
55+
roll out replacement nodes which can be useful e.g. to perform certificate rotation, reflect changes
56+
to machine templates, move to new machines, etc.
5757

5858
Note that this field can only be used for triggering a rollout, not for delaying one. Specifically,
5959
a rollout can also happen before the time specified in `RolloutAfter` if any changes are made to
@@ -62,19 +62,13 @@ the spec before that time.
6262
The rollout can be triggered by running the following command:
6363

6464
```shell
65+
# Trigger a KubeadmControlPlane rollout.
6566
clusterctl alpha rollout restart kubeadmcontrollplane/my-kcp
66-
```
67-
68-
To do the same for machines managed by a `MachineDeployment` it's enough to make an arbitrary
69-
change to its `Spec.Template`, one common approach is to run:
7067

71-
``` shell
68+
# Trigger a MachineDeployment rollout.
7269
clusterctl alpha rollout restart machinedeployment/my-md-0
7370
```
7471

75-
This will modify the template by setting an `cluster.x-k8s.io/restartedAt` annotation which will
76-
trigger a rollout.
77-
7872
### Upgrading machines managed by a `MachineDeployment`
7973

8074
Upgrades are not limited to just the control plane. This section is not related to Kubeadm control plane specifically,

0 commit comments

Comments
 (0)