From 27e6ceed88d2aee09c77b7d37c65cadb5ae01071 Mon Sep 17 00:00:00 2001 From: Anirudh Date: Fri, 4 Aug 2017 15:03:14 -0700 Subject: [PATCH] Change default update strategy to rolling update --- pkg/apis/apps/v1beta2/defaults.go | 22 +-- pkg/apis/apps/v1beta2/defaults_test.go | 150 ++++++++++++++++++- staging/src/k8s.io/api/apps/v1beta2/types.go | 8 +- 3 files changed, 163 insertions(+), 17 deletions(-) diff --git a/pkg/apis/apps/v1beta2/defaults.go b/pkg/apis/apps/v1beta2/defaults.go index f1046b16ff5..db73c3e73ec 100644 --- a/pkg/apis/apps/v1beta2/defaults.go +++ b/pkg/apis/apps/v1beta2/defaults.go @@ -43,7 +43,7 @@ func SetDefaults_DaemonSet(obj *appsv1beta2.DaemonSet) { } updateStrategy := &obj.Spec.UpdateStrategy if updateStrategy.Type == "" { - updateStrategy.Type = appsv1beta2.OnDeleteDaemonSetStrategyType + updateStrategy.Type = appsv1beta2.RollingUpdateDaemonSetStrategyType } if updateStrategy.Type == appsv1beta2.RollingUpdateDaemonSetStrategyType { if updateStrategy.RollingUpdate == nil { @@ -68,8 +68,19 @@ func SetDefaults_StatefulSet(obj *appsv1beta2.StatefulSet) { } if obj.Spec.UpdateStrategy.Type == "" { - obj.Spec.UpdateStrategy.Type = appsv1beta2.OnDeleteStatefulSetStrategyType + obj.Spec.UpdateStrategy.Type = appsv1beta2.RollingUpdateStatefulSetStrategyType + + // UpdateStrategy.RollingUpdate will take default values below. + obj.Spec.UpdateStrategy.RollingUpdate = &appsv1beta2.RollingUpdateStatefulSetStrategy{} } + + if obj.Spec.UpdateStrategy.Type == appsv1beta2.RollingUpdateStatefulSetStrategyType && + obj.Spec.UpdateStrategy.RollingUpdate != nil && + obj.Spec.UpdateStrategy.RollingUpdate.Partition == nil { + obj.Spec.UpdateStrategy.RollingUpdate.Partition = new(int32) + *obj.Spec.UpdateStrategy.RollingUpdate.Partition = 0 + } + labels := obj.Spec.Template.Labels if labels != nil { if obj.Spec.Selector == nil { @@ -89,13 +100,6 @@ func SetDefaults_StatefulSet(obj *appsv1beta2.StatefulSet) { obj.Spec.RevisionHistoryLimit = new(int32) *obj.Spec.RevisionHistoryLimit = 10 } - if obj.Spec.UpdateStrategy.Type == appsv1beta2.RollingUpdateStatefulSetStrategyType && - obj.Spec.UpdateStrategy.RollingUpdate != nil && - obj.Spec.UpdateStrategy.RollingUpdate.Partition == nil { - obj.Spec.UpdateStrategy.RollingUpdate.Partition = new(int32) - *obj.Spec.UpdateStrategy.RollingUpdate.Partition = 0 - } - } // SetDefaults_Deployment sets additional defaults compared to its counterpart diff --git a/pkg/apis/apps/v1beta2/defaults_test.go b/pkg/apis/apps/v1beta2/defaults_test.go index d017a52688c..3a24c811b73 100644 --- a/pkg/apis/apps/v1beta2/defaults_test.go +++ b/pkg/apis/apps/v1beta2/defaults_test.go @@ -21,7 +21,6 @@ import ( "testing" appsv1beta2 "k8s.io/api/apps/v1beta2" - "k8s.io/api/core/v1" apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/resource" @@ -36,6 +35,7 @@ import ( func TestSetDefaultDaemonSetSpec(t *testing.T) { defaultLabels := map[string]string{"foo": "bar"} + maxUnavailable := intstr.FromInt(1) period := int64(v1.DefaultTerminationGracePeriodSeconds) defaultTemplate := v1.PodTemplateSpec{ Spec: v1.PodSpec{ @@ -78,7 +78,10 @@ func TestSetDefaultDaemonSetSpec(t *testing.T) { }, Template: defaultTemplate, UpdateStrategy: appsv1beta2.DaemonSetUpdateStrategy{ - Type: appsv1beta2.OnDeleteDaemonSetStrategyType, + Type: appsv1beta2.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1beta2.RollingUpdateDaemonSet{ + MaxUnavailable: &maxUnavailable, + }, }, RevisionHistoryLimit: newInt32(10), }, @@ -108,14 +111,24 @@ func TestSetDefaultDaemonSetSpec(t *testing.T) { }, Template: defaultTemplate, UpdateStrategy: appsv1beta2.DaemonSetUpdateStrategy{ - Type: appsv1beta2.OnDeleteDaemonSetStrategyType, + Type: appsv1beta2.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1beta2.RollingUpdateDaemonSet{ + MaxUnavailable: &maxUnavailable, + }, }, RevisionHistoryLimit: newInt32(1), }, }, }, - { // Update strategy. - original: &appsv1beta2.DaemonSet{}, + { // OnDeleteDaemonSetStrategyType update strategy. + original: &appsv1beta2.DaemonSet{ + Spec: appsv1beta2.DaemonSetSpec{ + Template: templateNoLabel, + UpdateStrategy: appsv1beta2.DaemonSetUpdateStrategy{ + Type: appsv1beta2.OnDeleteDaemonSetStrategyType, + }, + }, + }, expected: &appsv1beta2.DaemonSet{ Spec: appsv1beta2.DaemonSetSpec{ Template: templateNoLabel, @@ -134,7 +147,10 @@ func TestSetDefaultDaemonSetSpec(t *testing.T) { Spec: appsv1beta2.DaemonSetSpec{ Template: templateNoLabel, UpdateStrategy: appsv1beta2.DaemonSetUpdateStrategy{ - Type: appsv1beta2.OnDeleteDaemonSetStrategyType, + Type: appsv1beta2.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1beta2.RollingUpdateDaemonSet{ + MaxUnavailable: &maxUnavailable, + }, }, RevisionHistoryLimit: newInt32(10), }, @@ -157,6 +173,128 @@ func TestSetDefaultDaemonSetSpec(t *testing.T) { } } +func TestSetDefaultStatefulSet(t *testing.T) { + defaultLabels := map[string]string{"foo": "bar"} + var defaultPartition int32 = 0 + var defaultReplicas int32 = 1 + + period := int64(v1.DefaultTerminationGracePeriodSeconds) + defaultTemplate := v1.PodTemplateSpec{ + Spec: v1.PodSpec{ + DNSPolicy: v1.DNSClusterFirst, + RestartPolicy: v1.RestartPolicyAlways, + SecurityContext: &v1.PodSecurityContext{}, + TerminationGracePeriodSeconds: &period, + SchedulerName: api.DefaultSchedulerName, + }, + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + } + + tests := []struct { + original *appsv1beta2.StatefulSet + expected *appsv1beta2.StatefulSet + }{ + { // Selector, labels and default update strategy + original: &appsv1beta2.StatefulSet{ + Spec: appsv1beta2.StatefulSetSpec{ + Template: defaultTemplate, + }, + }, + expected: &appsv1beta2.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + Spec: appsv1beta2.StatefulSetSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: defaultLabels, + }, + Replicas: &defaultReplicas, + Template: defaultTemplate, + PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement, + UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{ + Type: appsv1beta2.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{ + Partition: &defaultPartition, + }, + }, + RevisionHistoryLimit: newInt32(10), + }, + }, + }, + { // Alternate update strategy + original: &appsv1beta2.StatefulSet{ + Spec: appsv1beta2.StatefulSetSpec{ + Template: defaultTemplate, + UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{ + Type: appsv1beta2.OnDeleteStatefulSetStrategyType, + }, + }, + }, + expected: &appsv1beta2.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + Spec: appsv1beta2.StatefulSetSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: defaultLabels, + }, + Replicas: &defaultReplicas, + Template: defaultTemplate, + PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement, + UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{ + Type: appsv1beta2.OnDeleteStatefulSetStrategyType, + }, + RevisionHistoryLimit: newInt32(10), + }, + }, + }, + { // Parallel pod management policy. + original: &appsv1beta2.StatefulSet{ + Spec: appsv1beta2.StatefulSetSpec{ + Template: defaultTemplate, + PodManagementPolicy: appsv1beta2.ParallelPodManagement, + }, + }, + expected: &appsv1beta2.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + Spec: appsv1beta2.StatefulSetSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: defaultLabels, + }, + Replicas: &defaultReplicas, + Template: defaultTemplate, + PodManagementPolicy: appsv1beta2.ParallelPodManagement, + UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{ + Type: appsv1beta2.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{ + Partition: &defaultPartition, + }, + }, + RevisionHistoryLimit: newInt32(10), + }, + }, + }, + } + + for i, test := range tests { + original := test.original + expected := test.expected + obj2 := roundTrip(t, runtime.Object(original)) + got, ok := obj2.(*appsv1beta2.StatefulSet) + if !ok { + t.Errorf("(%d) unexpected object: %v", i, got) + t.FailNow() + } + if !apiequality.Semantic.DeepEqual(got.Spec, expected.Spec) { + t.Errorf("(%d) got different than expected\ngot:\n\t%+v\nexpected:\n\t%+v", i, got.Spec, expected.Spec) + } + } +} + func TestSetDefaultDeployment(t *testing.T) { defaultIntOrString := intstr.FromString("25%") differentIntOrString := intstr.FromInt(5) diff --git a/staging/src/k8s.io/api/apps/v1beta2/types.go b/staging/src/k8s.io/api/apps/v1beta2/types.go index 84244b46408..f9ab8cc0b7c 100644 --- a/staging/src/k8s.io/api/apps/v1beta2/types.go +++ b/staging/src/k8s.io/api/apps/v1beta2/types.go @@ -122,8 +122,11 @@ const ( // necessary to perform the update for the indicated strategy. type StatefulSetUpdateStrategy struct { // Type indicates the type of the StatefulSetUpdateStrategy. + // Default is RollingUpdate. + // +optional Type StatefulSetUpdateStrategyType `json:"type,omitempty" protobuf:"bytes,1,opt,name=type,casttype=StatefulSetStrategyType"` // RollingUpdate is used to communicate parameters when Type is RollingUpdateStatefulSetStrategyType. + // +optional RollingUpdate *RollingUpdateStatefulSetStrategy `json:"rollingUpdate,omitempty" protobuf:"bytes,2,opt,name=rollingUpdate"` } @@ -151,6 +154,8 @@ const ( type RollingUpdateStatefulSetStrategy struct { // Partition indicates the ordinal at which the StatefulSet should be // partitioned. + // Default value is 0. + // +optional Partition *int32 `json:"partition,omitempty" protobuf:"varint,1,opt,name=partition"` } @@ -504,8 +509,7 @@ type DeploymentList struct { // WIP: This is not ready to be used and we plan to make breaking changes to it. type DaemonSetUpdateStrategy struct { - // Type of daemon set update. Can be "RollingUpdate" or "OnDelete". - // Default is OnDelete. + // Type of daemon set update. Can be "RollingUpdate" or "OnDelete". Default is RollingUpdate. // +optional Type DaemonSetUpdateStrategyType `json:"type,omitempty" protobuf:"bytes,1,opt,name=type"`