Skip to content

Commit

Permalink
Merge pull request #8216 from ykakarap/machinedeployment-rollout-after
Browse files Browse the repository at this point in the history
✨ MachineDeployment rolloutAfter support
  • Loading branch information
k8s-ci-robot authored Mar 9, 2023
2 parents a8841fb + 99d7559 commit ad11058
Show file tree
Hide file tree
Showing 19 changed files with 215 additions and 69 deletions.
5 changes: 5 additions & 0 deletions api/v1alpha3/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ func (src *MachineDeployment) ConvertTo(dstRaw conversion.Hub) error {

dst.Spec.Template.Spec.NodeDeletionTimeout = restored.Spec.Template.Spec.NodeDeletionTimeout
dst.Spec.Template.Spec.NodeVolumeDetachTimeout = restored.Spec.Template.Spec.NodeVolumeDetachTimeout
dst.Spec.RolloutAfter = restored.Spec.RolloutAfter
dst.Status.Conditions = restored.Status.Conditions
return nil
}
Expand Down Expand Up @@ -316,6 +317,10 @@ func Convert_v1beta1_MachineSpec_To_v1alpha3_MachineSpec(in *clusterv1.MachineSp
return autoConvert_v1beta1_MachineSpec_To_v1alpha3_MachineSpec(in, out, s)
}

func Convert_v1beta1_MachineDeploymentSpec_To_v1alpha3_MachineDeploymentSpec(in *clusterv1.MachineDeploymentSpec, out *MachineDeploymentSpec, s apiconversion.Scope) error {
return autoConvert_v1beta1_MachineDeploymentSpec_To_v1alpha3_MachineDeploymentSpec(in, out, s)
}

func Convert_v1beta1_MachineDeploymentStatus_To_v1alpha3_MachineDeploymentStatus(in *clusterv1.MachineDeploymentStatus, out *MachineDeploymentStatus, s apiconversion.Scope) error {
// 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
return autoConvert_v1beta1_MachineDeploymentStatus_To_v1alpha3_MachineDeploymentStatus(in, out, s)
Expand Down
16 changes: 6 additions & 10 deletions api/v1alpha3/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions api/v1alpha4/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ func (src *MachineDeployment) ConvertTo(dstRaw conversion.Hub) error {

dst.Spec.Template.Spec.NodeDeletionTimeout = restored.Spec.Template.Spec.NodeDeletionTimeout
dst.Spec.Template.Spec.NodeVolumeDetachTimeout = restored.Spec.Template.Spec.NodeVolumeDetachTimeout
dst.Spec.RolloutAfter = restored.Spec.RolloutAfter
return nil
}

Expand Down Expand Up @@ -335,6 +336,10 @@ func Convert_v1beta1_MachineSpec_To_v1alpha4_MachineSpec(in *clusterv1.MachineSp
return autoConvert_v1beta1_MachineSpec_To_v1alpha4_MachineSpec(in, out, s)
}

func Convert_v1beta1_MachineDeploymentSpec_To_v1alpha4_MachineDeploymentSpec(in *clusterv1.MachineDeploymentSpec, out *MachineDeploymentSpec, s apiconversion.Scope) error {
return autoConvert_v1beta1_MachineDeploymentSpec_To_v1alpha4_MachineDeploymentSpec(in, out, s)
}

func Convert_v1beta1_Topology_To_v1alpha4_Topology(in *clusterv1.Topology, out *Topology, s apiconversion.Scope) error {
// spec.topology.variables has been added with v1beta1.
return autoConvert_v1beta1_Topology_To_v1alpha4_Topology(in, out, s)
Expand Down
16 changes: 6 additions & 10 deletions api/v1alpha4/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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

Expand Down Expand Up @@ -97,6 +99,15 @@ type MachineDeploymentSpec struct {
// +optional
Replicas *int32 `json:"replicas,omitempty"`

// RolloutAfter is a field to indicate a rollout should be performed
// after the specified time even if no changes have been made to the
// MachineDeployment.
// Example: In the YAML the time can be specified in the RFC3339 format.
// To specify the rolloutAfter target as March 9, 2023, at 9 am UTC
// use "2023-03-09T09:00:00Z".
// +optional
RolloutAfter *metav1.Time `json:"rolloutAfter,omitempty"`

// Label selector for machines. Existing MachineSets whose machines are
// selected by this will be the ones affected by this deployment.
// It must match the machine template's labels.
Expand Down
4 changes: 4 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion api/v1beta1/zz_generated.openapi.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions cmd/clusterctl/client/alpha/kubeadmcontrolplane.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ func getKubeadmControlPlane(proxy cluster.Proxy, name, namespace string) (*contr
return kcpObj, nil
}

// setRolloutAfter sets KubeadmControlPlane.spec.rolloutAfter.
func setRolloutAfter(proxy cluster.Proxy, name, namespace string) error {
// setRolloutAfterOnKCP sets KubeadmControlPlane.spec.rolloutAfter.
func setRolloutAfterOnKCP(proxy cluster.Proxy, name, namespace string) error {
patch := client.RawPatch(types.MergePatchType, []byte(fmt.Sprintf(`{"spec":{"rolloutAfter":"%v"}}`, time.Now().Format(time.RFC3339))))
return patchKubeadmControlPlane(proxy, name, namespace, patch)
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/clusterctl/client/alpha/machinedeployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ func getMachineDeployment(proxy cluster.Proxy, name, namespace string) (*cluster
return mdObj, nil
}

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

Expand Down
7 changes: 5 additions & 2 deletions cmd/clusterctl/client/alpha/rollout_restarter.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ func (r *rollout) ObjectRestarter(proxy cluster.Proxy, ref corev1.ObjectReferenc
if deployment.Spec.Paused {
return errors.Errorf("can't restart paused MachineDeployment (run rollout resume first): %v/%v", ref.Kind, ref.Name)
}
if err := setRestartedAtAnnotation(proxy, ref.Name, ref.Namespace); err != nil {
if deployment.Spec.RolloutAfter != nil && deployment.Spec.RolloutAfter.After(time.Now()) {
return errors.Errorf("can't update MachineDeployment (remove 'spec.rolloutAfter' first): %v/%v", ref.Kind, ref.Name)
}
if err := setRolloutAfterOnMachineDeployment(proxy, ref.Name, ref.Namespace); err != nil {
return err
}
case KubeadmControlPlane:
Expand All @@ -51,7 +54,7 @@ func (r *rollout) ObjectRestarter(proxy cluster.Proxy, ref corev1.ObjectReferenc
if kcp.Spec.RolloutAfter != nil && kcp.Spec.RolloutAfter.After(time.Now()) {
return errors.Errorf("can't update KubeadmControlPlane (remove 'spec.rolloutAfter' first): %v/%v", ref.Kind, ref.Name)
}
if err := setRolloutAfter(proxy, ref.Name, ref.Namespace); err != nil {
if err := setRolloutAfterOnKCP(proxy, ref.Name, ref.Namespace); err != nil {
return err
}
default:
Expand Down
37 changes: 32 additions & 5 deletions cmd/clusterctl/client/alpha/rollout_restarter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func Test_ObjectRestarter(t *testing.T) {
wantRollout bool
}{
{
name: "machinedeployment should have restart annotation",
name: "machinedeployment should have rolloutAfter",
fields: fields{
objs: []client.Object{
&clusterv1.MachineDeployment{
Expand All @@ -67,7 +67,7 @@ func Test_ObjectRestarter(t *testing.T) {
wantRollout: true,
},
{
name: "paused machinedeployment should not have restart annotation",
name: "paused machinedeployment should not have rolloutAfter",
fields: fields{
objs: []client.Object{
&clusterv1.MachineDeployment{
Expand All @@ -93,6 +93,33 @@ func Test_ObjectRestarter(t *testing.T) {
wantErr: true,
wantRollout: false,
},
{
name: "machinedeployment with spec.rolloutAfter should not be updatable",
fields: fields{
objs: []client.Object{
&clusterv1.MachineDeployment{
TypeMeta: metav1.TypeMeta{
Kind: "MachineDeployment",
APIVersion: "cluster.x-k8s.io/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "md-1",
},
Spec: clusterv1.MachineDeploymentSpec{
RolloutAfter: &metav1.Time{Time: time.Now().Local().Add(time.Hour)},
},
},
},
ref: corev1.ObjectReference{
Kind: MachineDeployment,
Name: "md-1",
Namespace: "default",
},
},
wantErr: true,
wantRollout: false,
},
{
name: "kubeadmcontrolplane should have rolloutAfter",
fields: fields{
Expand Down Expand Up @@ -193,9 +220,9 @@ func Test_ObjectRestarter(t *testing.T) {
err = cl.Get(context.TODO(), key, md)
g.Expect(err).ToNot(HaveOccurred())
if tt.wantRollout {
g.Expect(md.Spec.Template.Annotations).To(HaveKey("cluster.x-k8s.io/restartedAt"))
g.Expect(md.Spec.RolloutAfter).NotTo(BeNil())
} else {
g.Expect(md.Spec.Template.Annotations).ToNot(HaveKey("cluster.x-k8s.io/restartedAt"))
g.Expect(md.Spec.RolloutAfter).To(BeNil())
}
case *controlplanev1.KubeadmControlPlane:
kcp := &controlplanev1.KubeadmControlPlane{}
Expand All @@ -204,7 +231,7 @@ func Test_ObjectRestarter(t *testing.T) {
if tt.wantRollout {
g.Expect(kcp.Spec.RolloutAfter).NotTo(BeNil())
} else {
g.Expect(kcp.Spec.RolloutAfter).To(nil)
g.Expect(kcp.Spec.RolloutAfter).To(BeNil())
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions config/crd/bases/cluster.x-k8s.io_machinedeployments.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ type KubeadmControlPlaneSpec struct {
// RolloutAfter is a field to indicate a rollout should be performed
// after the specified time even if no changes have been made to the
// KubeadmControlPlane.
// Example: In the YAML the time can be specified in the RFC3339 format.
// To specify the rolloutAfter target as March 9, 2023, at 9 am UTC
// use "2023-03-09T09:00:00Z".
// +optional
RolloutAfter *metav1.Time `json:"rolloutAfter,omitempty"`

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit ad11058

Please sign in to comment.