diff --git a/pkg/apis/apps/validation/validation_test.go b/pkg/apis/apps/validation/validation_test.go index 07b4ae0818a..0cbb1349686 100644 --- a/pkg/apis/apps/validation/validation_test.go +++ b/pkg/apis/apps/validation/validation_test.go @@ -42,6 +42,162 @@ func intStrAddr(intOrStr intstr.IntOrString) *intstr.IntOrString { return &intOrStr } +type statefulSetTweak func(ss *apps.StatefulSet) + +func mkStatefulSet(template *api.PodTemplate, tweaks ...statefulSetTweak) apps.StatefulSet { + ss := apps.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, + Spec: apps.StatefulSetSpec{ + PodManagementPolicy: apps.OrderedReadyPodManagement, + Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}}, + Template: template.Template, + UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, + }, + } + + for _, tw := range tweaks { + tw(&ss) + } + + return ss +} + +func tweakName(name string) statefulSetTweak { + return func(ss *apps.StatefulSet) { + ss.ObjectMeta.Name = name + } +} + +func tweakNamespace(ns string) statefulSetTweak { + return func(ss *apps.StatefulSet) { + ss.ObjectMeta.Namespace = ns + } +} + +func tweakLabels(key string, value string) statefulSetTweak { + return func(ss *apps.StatefulSet) { + if ss.ObjectMeta.Labels == nil { + ss.ObjectMeta.Labels = map[string]string{} + } + ss.ObjectMeta.Labels[key] = value + } +} + +func tweakAnnotations(key string, value string) statefulSetTweak { + return func(ss *apps.StatefulSet) { + if ss.ObjectMeta.Annotations == nil { + ss.ObjectMeta.Annotations = map[string]string{} + } + ss.ObjectMeta.Annotations[key] = value + } +} + +func tweakFinalizers(finalizers ...string) statefulSetTweak { + return func(ss *apps.StatefulSet) { + ss.ObjectMeta.Finalizers = finalizers + } +} + +func tweakPodManagementPolicy(policy apps.PodManagementPolicyType) statefulSetTweak { + return func(ss *apps.StatefulSet) { + ss.Spec.PodManagementPolicy = policy + } +} + +func tweakReplicas(replicas int32) statefulSetTweak { + return func(ss *apps.StatefulSet) { + ss.Spec.Replicas = replicas + } +} + +func tweakSelectorLabels(labels map[string]string) statefulSetTweak { + return func(ss *apps.StatefulSet) { + if labels == nil { + ss.Spec.Selector = nil + } else { + ss.Spec.Selector = &metav1.LabelSelector{MatchLabels: labels} + } + } +} + +func tweakTemplateRestartPolicy(rp api.RestartPolicy) statefulSetTweak { + return func(ss *apps.StatefulSet) { + ss.Spec.Template.Spec.RestartPolicy = rp + } +} + +func tweakMinReadySeconds(t int32) statefulSetTweak { + return func(ss *apps.StatefulSet) { + ss.Spec.MinReadySeconds = t + } +} + +func tweakOrdinalsStart(s int32) statefulSetTweak { + return func(ss *apps.StatefulSet) { + ss.Spec.Ordinals = &apps.StatefulSetOrdinals{Start: s} + } +} + +func tweakPVCTemplate(pvc ...api.PersistentVolumeClaim) statefulSetTweak { + return func(ss *apps.StatefulSet) { + ss.Spec.VolumeClaimTemplates = pvc + } +} + +func tweakUpdateStrategyType(t apps.StatefulSetUpdateStrategyType) statefulSetTweak { + return func(ss *apps.StatefulSet) { + ss.Spec.UpdateStrategy.Type = t + } +} + +func tweakRollingUpdatePartition(partition int32) statefulSetTweak { + return func(ss *apps.StatefulSet) { + if ss.Spec.UpdateStrategy.RollingUpdate == nil { + ss.Spec.UpdateStrategy.RollingUpdate = &apps.RollingUpdateStatefulSetStrategy{} + } + ss.Spec.UpdateStrategy.RollingUpdate.Partition = partition + } +} + +func tweakMaxUnavailable(mu intstr.IntOrString) statefulSetTweak { + return func(ss *apps.StatefulSet) { + if ss.Spec.UpdateStrategy.RollingUpdate == nil { + ss.Spec.UpdateStrategy.RollingUpdate = &apps.RollingUpdateStatefulSetStrategy{} + } + ss.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable = intStrAddr(mu) + } +} + +func tweakPVCPolicy(policy *apps.StatefulSetPersistentVolumeClaimRetentionPolicy) statefulSetTweak { + return func(ss *apps.StatefulSet) { + ss.Spec.PersistentVolumeClaimRetentionPolicy = policy + } +} + +type pvcPolicyTweak func(policy *apps.StatefulSetPersistentVolumeClaimRetentionPolicy) + +func mkPVCPolicy(tweaks ...pvcPolicyTweak) *apps.StatefulSetPersistentVolumeClaimRetentionPolicy { + policy := &apps.StatefulSetPersistentVolumeClaimRetentionPolicy{} + + for _, tw := range tweaks { + tw(policy) + } + + return policy +} + +func tweakPVCDeletedPolicy(t apps.PersistentVolumeClaimRetentionPolicyType) pvcPolicyTweak { + return func(policy *apps.StatefulSetPersistentVolumeClaimRetentionPolicy) { + policy.WhenDeleted = t + } +} + +func tweakPVCScalePolicy(t apps.PersistentVolumeClaimRetentionPolicyType) pvcPolicyTweak { + return func(policy *apps.StatefulSetPersistentVolumeClaimRetentionPolicy) { + policy.WhenScaled = t + } +} + func TestValidateStatefulSet(t *testing.T) { validLabels := map[string]string{"a": "b"} validPodTemplate := api.PodTemplate{ @@ -95,191 +251,87 @@ func TestValidateStatefulSet(t *testing.T) { successCases := []testCase{ { name: "alpha name", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakName("abc")), }, { name: "alphanumeric name", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakName("abc-123")), }, { name: "parallel pod management", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.ParallelPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakPodManagementPolicy(apps.ParallelPodManagement)), }, { name: "ordered ready pod management", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.OnDeleteStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakPodManagementPolicy(apps.OrderedReadyPodManagement)), }, { name: "update strategy", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - Replicas: 3, - UpdateStrategy: apps.StatefulSetUpdateStrategy{ - Type: apps.RollingUpdateStatefulSetStrategyType, - RollingUpdate: func() *apps.RollingUpdateStatefulSetStrategy { - return &apps.RollingUpdateStatefulSetStrategy{Partition: 2} - }()}, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakReplicas(3), + tweakUpdateStrategyType(apps.RollingUpdateStatefulSetStrategyType), + tweakRollingUpdatePartition(2), + ), }, { name: "PVC policy " + enableStatefulSetAutoDeletePVC, - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - PersistentVolumeClaimRetentionPolicy: &apps.StatefulSetPersistentVolumeClaimRetentionPolicy{ - WhenDeleted: apps.DeletePersistentVolumeClaimRetentionPolicyType, - WhenScaled: apps.RetainPersistentVolumeClaimRetentionPolicyType, - }, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakPVCPolicy(mkPVCPolicy( + tweakPVCDeletedPolicy(apps.DeletePersistentVolumeClaimRetentionPolicyType), + tweakPVCScalePolicy(apps.RetainPersistentVolumeClaimRetentionPolicyType), + )), + ), }, { name: "maxUnavailable with parallel pod management", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.ParallelPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - Replicas: 3, - UpdateStrategy: apps.StatefulSetUpdateStrategy{ - Type: apps.RollingUpdateStatefulSetStrategyType, - RollingUpdate: &apps.RollingUpdateStatefulSetStrategy{ - Partition: 2, - MaxUnavailable: intStrAddr(intstr.FromInt(2)), - }, - }, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakReplicas(3), + tweakUpdateStrategyType(apps.RollingUpdateStatefulSetStrategyType), + tweakRollingUpdatePartition(2), + tweakMaxUnavailable(intstr.FromInt(2)), + ), }, { name: "ordinals.start positive value", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.ParallelPodManagement, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - Replicas: 3, - Ordinals: &apps.StatefulSetOrdinals{Start: 2}, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakReplicas(3), + tweakOrdinalsStart(2), + ), }, } errorCases := []testCase{ { name: "zero-length name", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakName("")), errs: field.ErrorList{ field.Required(field.NewPath("metadata", "name"), ""), }, }, { name: "name-with-dots", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc.123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakName("abc.123")), errs: field.ErrorList{ field.Invalid(field.NewPath("metadata", "name"), "abc.123", ""), }, }, { name: "long name", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: strings.Repeat("a", 64), Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakName(strings.Repeat("a", 64))), errs: field.ErrorList{ field.Invalid(field.NewPath("metadata", "name"), strings.Repeat("a", 64), ""), }, }, { name: "missing-namespace", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123"}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakNamespace("")), errs: field.ErrorList{ field.Required(field.NewPath("metadata", "namespace"), ""), }, }, { name: "empty selector", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakSelectorLabels(nil)), errs: field.ErrorList{ field.Required(field.NewPath("spec", "selector"), ""), field.Invalid(field.NewPath("spec", "template", "metadata", "labels"), nil, ""), // selector is empty, labels are not, so select doesn't match labels @@ -287,73 +339,33 @@ func TestValidateStatefulSet(t *testing.T) { }, { name: "selector_doesnt_match", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakSelectorLabels(map[string]string{"foo": "bar"})), errs: field.ErrorList{ field.Invalid(field.NewPath("spec", "template", "metadata", "labels"), nil, ""), }, }, { name: "negative_replicas", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Replicas: -1, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakReplicas(-1)), errs: field.ErrorList{ field.Invalid(field.NewPath("spec", "replicas"), nil, ""), }, }, { name: "invalid_label", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "abc-123", - Namespace: metav1.NamespaceDefault, - Labels: map[string]string{ - "NoUppercaseOrSpecialCharsLike=Equals": "bar", - }, - }, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakLabels("NoUppercaseOrSpecialCharsLike=Equals", "bar"), + ), errs: field.ErrorList{ field.Invalid(field.NewPath("metadata", "labels"), nil, ""), }, }, { name: "invalid_label 2", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "abc-123", - Namespace: metav1.NamespaceDefault, - Labels: map[string]string{ - "NoUppercaseOrSpecialCharsLike=Equals": "bar", - }, - }, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: invalidLabels}, - Template: invalidPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&invalidPodTemplate, + tweakLabels("NoUppercaseOrSpecialCharsLike=Equals", "bar"), + tweakSelectorLabels(invalidLabels), + ), errs: field.ErrorList{ field.Invalid(field.NewPath("metadata", "labels"), nil, ""), field.Invalid(field.NewPath("spec", "selector"), nil, ""), @@ -362,235 +374,104 @@ func TestValidateStatefulSet(t *testing.T) { }, { name: "invalid_annotation", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "abc-123", - Namespace: metav1.NamespaceDefault, - Annotations: map[string]string{ - "NoUppercaseOrSpecialCharsLike=Equals": "bar", - }, - }, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakAnnotations("NoUppercaseOrSpecialCharsLike=Equals", "bar"), + ), errs: field.ErrorList{ field.Invalid(field.NewPath("metadata", "annotations"), nil, ""), }, }, { name: "invalid restart policy 1", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "abc-123", - Namespace: metav1.NamespaceDefault, - }, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyOnFailure, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, - }, - ObjectMeta: metav1.ObjectMeta{ - Labels: validLabels, - }, - }, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakTemplateRestartPolicy(api.RestartPolicyOnFailure)), errs: field.ErrorList{ field.NotSupported(field.NewPath("spec", "template", "spec", "restartPolicy"), nil, nil), }, }, { name: "invalid restart policy 2", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "abc-123", - Namespace: metav1.NamespaceDefault, - }, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyNever, - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, - }, - ObjectMeta: metav1.ObjectMeta{ - Labels: validLabels, - }, - }, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakTemplateRestartPolicy(api.RestartPolicyNever)), errs: field.ErrorList{ field.NotSupported(field.NewPath("spec", "template", "spec", "restartPolicy"), nil, nil), }, }, { name: "empty restart policy", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "abc-123", - Namespace: metav1.NamespaceDefault, - }, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, - }, - ObjectMeta: metav1.ObjectMeta{ - Labels: validLabels, - }, - }, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakTemplateRestartPolicy("")), errs: field.ErrorList{ field.NotSupported(field.NewPath("spec", "template", "spec", "restartPolicy"), nil, nil), }, }, { name: "invalid update strategy", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - Replicas: 3, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: "foo"}, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakReplicas(3), + tweakUpdateStrategyType("foo"), + ), errs: field.ErrorList{ field.Invalid(field.NewPath("spec", "updateStrategy"), nil, ""), }, }, { name: "empty update strategy", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - Replicas: 3, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: ""}, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakReplicas(3), + tweakUpdateStrategyType(""), + ), errs: field.ErrorList{ field.Required(field.NewPath("spec", "updateStrategy"), ""), }, }, { name: "invalid rolling update", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - Replicas: 3, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.OnDeleteStatefulSetStrategyType, - RollingUpdate: func() *apps.RollingUpdateStatefulSetStrategy { - return &apps.RollingUpdateStatefulSetStrategy{Partition: 1} - }()}, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakReplicas(3), + tweakUpdateStrategyType(apps.OnDeleteStatefulSetStrategyType), + tweakRollingUpdatePartition(1), + ), errs: field.ErrorList{ field.Invalid(field.NewPath("spec", "updateStrategy", "rollingUpdate"), nil, ""), }, }, { name: "negative parition", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - Replicas: 3, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType, - RollingUpdate: func() *apps.RollingUpdateStatefulSetStrategy { - return &apps.RollingUpdateStatefulSetStrategy{Partition: -1} - }()}, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakReplicas(3), + tweakRollingUpdatePartition(-1), + ), errs: field.ErrorList{ field.Invalid(field.NewPath("spec", "updateStrategy", "rollingUpdate", "partition"), nil, ""), }, }, { name: "empty pod management policy", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: "", - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - Replicas: 3, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakPodManagementPolicy(""), + tweakReplicas(3), + ), errs: field.ErrorList{ field.Required(field.NewPath("spec", "podManagementPolicy"), ""), }, }, { name: "invalid pod management policy", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: "foo", - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - Replicas: 3, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, tweakPodManagementPolicy("foo")), errs: field.ErrorList{ field.Invalid(field.NewPath("spec", "podManagementPolicy"), nil, ""), }, }, { name: "set active deadline seconds", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: invalidPodTemplate2.Template, - Replicas: 3, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&invalidPodTemplate2, tweakReplicas(3)), errs: field.ErrorList{ field.Forbidden(field.NewPath("spec", "template", "spec", "activeDeadlineSeconds"), ""), }, }, { name: "empty PersistentVolumeClaimRetentionPolicy " + enableStatefulSetAutoDeletePVC, - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PersistentVolumeClaimRetentionPolicy: &apps.StatefulSetPersistentVolumeClaimRetentionPolicy{}, - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakPVCPolicy(mkPVCPolicy()), + ), errs: field.ErrorList{ field.NotSupported(field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenDeleted"), nil, nil), field.NotSupported(field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenScaled"), nil, nil), @@ -598,19 +479,12 @@ func TestValidateStatefulSet(t *testing.T) { }, { name: "invalid PersistentVolumeClaimRetentionPolicy " + enableStatefulSetAutoDeletePVC, - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PersistentVolumeClaimRetentionPolicy: &apps.StatefulSetPersistentVolumeClaimRetentionPolicy{ - WhenScaled: apps.PersistentVolumeClaimRetentionPolicyType("invalid-retention-policy"), - WhenDeleted: apps.PersistentVolumeClaimRetentionPolicyType("invalid-retention-policy"), - }, - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakPVCPolicy(mkPVCPolicy( + tweakPVCDeletedPolicy("invalid-retention-policy"), + tweakPVCScalePolicy("invalid-retention-policy"), + )), + ), errs: field.ErrorList{ field.NotSupported(field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenDeleted"), nil, nil), field.NotSupported(field.NewPath("spec", "persistentVolumeClaimRetentionPolicy", "whenScaled"), nil, nil), @@ -618,80 +492,43 @@ func TestValidateStatefulSet(t *testing.T) { }, { name: "zero maxUnavailable", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - Replicas: 3, - UpdateStrategy: apps.StatefulSetUpdateStrategy{ - Type: apps.RollingUpdateStatefulSetStrategyType, - RollingUpdate: &apps.RollingUpdateStatefulSetStrategy{ - MaxUnavailable: intStrAddr(intstr.FromInt(0)), - }, - }, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakReplicas(3), + tweakUpdateStrategyType(apps.RollingUpdateStatefulSetStrategyType), + tweakMaxUnavailable(intstr.FromInt(0)), + ), errs: field.ErrorList{ field.Invalid(field.NewPath("spec", "updateStrategy", "rollingUpdate", "maxUnavailable"), nil, ""), }, }, { name: "zero percent maxUnavailable", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.ParallelPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - Replicas: 3, - UpdateStrategy: apps.StatefulSetUpdateStrategy{ - Type: apps.RollingUpdateStatefulSetStrategyType, - RollingUpdate: &apps.RollingUpdateStatefulSetStrategy{ - MaxUnavailable: intStrAddr(intstr.FromString("0%")), - }, - }, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakReplicas(3), + tweakUpdateStrategyType(apps.RollingUpdateStatefulSetStrategyType), + tweakMaxUnavailable(intstr.FromString("0%")), + ), errs: field.ErrorList{ field.Invalid(field.NewPath("spec", "updateStrategy", "rollingUpdate", "maxUnavailable"), nil, ""), }, }, { name: "greater than 100 percent maxUnavailable", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.ParallelPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - Replicas: 3, - UpdateStrategy: apps.StatefulSetUpdateStrategy{ - Type: apps.RollingUpdateStatefulSetStrategyType, - RollingUpdate: &apps.RollingUpdateStatefulSetStrategy{ - MaxUnavailable: intStrAddr(intstr.FromString("101%")), - }, - }, - }, - }, + set: mkStatefulSet(&validPodTemplate, + tweakReplicas(3), + tweakUpdateStrategyType(apps.RollingUpdateStatefulSetStrategyType), + tweakMaxUnavailable(intstr.FromString("101%")), + ), errs: field.ErrorList{ field.Invalid(field.NewPath("spec", "updateStrategy", "rollingUpdate", "maxUnavailable"), nil, ""), }, }, { - name: "invalid ordinals.start ", - set: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.ParallelPodManagement, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - Replicas: 3, - Ordinals: &apps.StatefulSetOrdinals{Start: -2}, - }, - }, + name: "invalid ordinals.start", + set: mkStatefulSet(&validPodTemplate, + tweakReplicas(3), + tweakOrdinalsStart(-2), + ), errs: field.ErrorList{ field.Invalid(field.NewPath("spec", "ordinals.start"), nil, ""), }, @@ -1007,450 +844,139 @@ func TestValidateStatefulSetUpdate(t *testing.T) { successCases := []testCase{ { - name: "update replica count", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Replicas: 3, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + name: "update replica count", + old: mkStatefulSet(&validPodTemplate), + update: mkStatefulSet(&validPodTemplate, tweakReplicas(3)), }, { - name: "update containers 1", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: addContainersValidTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + name: "update containers 1", + old: mkStatefulSet(&validPodTemplate), + update: mkStatefulSet(addContainersValidTemplate), }, { - name: "update containers 2", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: addContainersValidTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + name: "update containers 2", + old: mkStatefulSet(addContainersValidTemplate), + update: mkStatefulSet(&validPodTemplate), }, { name: "update containers and pvc retention policy 1", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: addContainersValidTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - PersistentVolumeClaimRetentionPolicy: &apps.StatefulSetPersistentVolumeClaimRetentionPolicy{ - WhenDeleted: apps.RetainPersistentVolumeClaimRetentionPolicyType, - WhenScaled: apps.RetainPersistentVolumeClaimRetentionPolicyType, - }, - }, - }, + old: mkStatefulSet(addContainersValidTemplate), + update: mkStatefulSet(&validPodTemplate, + tweakPVCPolicy(mkPVCPolicy( + tweakPVCDeletedPolicy(apps.RetainPersistentVolumeClaimRetentionPolicyType), + tweakPVCScalePolicy(apps.RetainPersistentVolumeClaimRetentionPolicyType), + )), + ), }, { name: "update containers and pvc retention policy 2", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: addContainersValidTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - PersistentVolumeClaimRetentionPolicy: &apps.StatefulSetPersistentVolumeClaimRetentionPolicy{ - WhenScaled: apps.RetainPersistentVolumeClaimRetentionPolicyType, - }, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + old: mkStatefulSet(&validPodTemplate, + tweakPVCPolicy(mkPVCPolicy( + tweakPVCScalePolicy(apps.RetainPersistentVolumeClaimRetentionPolicyType), + )), + ), + update: mkStatefulSet(&validPodTemplate), }, { name: "update update strategy", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.OnDeleteStatefulSetStrategyType}, - }, - }, + old: mkStatefulSet(&validPodTemplate), + update: mkStatefulSet(&validPodTemplate, + tweakUpdateStrategyType(apps.OnDeleteStatefulSetStrategyType), + ), }, { - name: "update min ready seconds 1", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - MinReadySeconds: 10, - }, - }, + name: "update min ready seconds 1", + old: mkStatefulSet(&validPodTemplate), + update: mkStatefulSet(&validPodTemplate, tweakMinReadySeconds(10)), }, { - name: "update min ready seconds 2", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - MinReadySeconds: 5, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - MinReadySeconds: 10, - }, - }, + name: "update min ready seconds 2", + old: mkStatefulSet(&validPodTemplate, tweakMinReadySeconds(5)), + update: mkStatefulSet(&validPodTemplate, tweakMinReadySeconds(10)), }, { - name: "update existing instance with now-invalid name", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc.123.example", Namespace: metav1.NamespaceDefault, Finalizers: []string{"final"}}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc.123.example", Namespace: metav1.NamespaceDefault, Finalizers: []string{}}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + name: "update existing instance with now-invalid name", + old: mkStatefulSet(&validPodTemplate, tweakFinalizers("final")), + update: mkStatefulSet(&validPodTemplate, tweakFinalizers()), }, { - name: "update existing instance with .spec.ordinals.start", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc.123.example", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc.123.example", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - Ordinals: &apps.StatefulSetOrdinals{ - Start: 3, - }, - }, - }, + name: "update existing instance with .spec.ordinals.start", + old: mkStatefulSet(&validPodTemplate), + update: mkStatefulSet(&validPodTemplate, tweakOrdinalsStart(3)), }, } errorCases := []testCase{ { - name: "update name", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc2", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + name: "update name", + old: mkStatefulSet(&validPodTemplate, tweakName("abc")), + update: mkStatefulSet(&validPodTemplate, tweakName("abc2")), errs: field.ErrorList{ field.Invalid(field.NewPath("metadata", "name"), nil, ""), }, }, { - name: "update namespace", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault + "1"}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + name: "update namespace", + old: mkStatefulSet(&validPodTemplate, tweakNamespace(metav1.NamespaceDefault)), + update: mkStatefulSet(&validPodTemplate, tweakNamespace(metav1.NamespaceDefault+"1")), errs: field.ErrorList{ field.Invalid(field.NewPath("metadata", "namespace"), nil, ""), }, }, { name: "update selector", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels2}, - Template: validPodTemplate2.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + old: mkStatefulSet(&validPodTemplate, tweakSelectorLabels(validLabels)), + update: mkStatefulSet(&validPodTemplate2, + tweakSelectorLabels(validLabels2), + ), errs: field.ErrorList{ field.Forbidden(field.NewPath("spec"), ""), }, }, { - name: "update pod management policy 1", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + name: "update pod management policy 1", + old: mkStatefulSet(&validPodTemplate, tweakPodManagementPolicy("")), + update: mkStatefulSet(&validPodTemplate, tweakPodManagementPolicy(apps.OrderedReadyPodManagement)), errs: field.ErrorList{ field.Forbidden(field.NewPath("spec"), ""), }, }, { - name: "update pod management policy 2", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.ParallelPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + name: "update pod management policy 2", + old: mkStatefulSet(&validPodTemplate, tweakPodManagementPolicy(apps.ParallelPodManagement)), + update: mkStatefulSet(&validPodTemplate, tweakPodManagementPolicy(apps.OrderedReadyPodManagement)), errs: field.ErrorList{ field.Forbidden(field.NewPath("spec"), ""), }, }, { - name: "update to negative replicas", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Replicas: -1, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - }, - }, + name: "update to negative replicas", + old: mkStatefulSet(&validPodTemplate), + update: mkStatefulSet(&validPodTemplate, tweakReplicas(-1)), errs: field.ErrorList{ field.Invalid(field.NewPath("spec", "replicas"), nil, ""), }, }, { - name: "update pvc template size", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - VolumeClaimTemplates: []api.PersistentVolumeClaim{validPVCTemplate}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - VolumeClaimTemplates: []api.PersistentVolumeClaim{validPVCTemplateChangedSize}, - }, - }, + name: "update pvc template size", + old: mkStatefulSet(&validPodTemplate, tweakPVCTemplate(validPVCTemplate)), + update: mkStatefulSet(&validPodTemplate, tweakPVCTemplate(validPVCTemplateChangedSize)), errs: field.ErrorList{ field.Forbidden(field.NewPath("spec"), ""), }, }, { - name: "update pvc template storage class", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - VolumeClaimTemplates: []api.PersistentVolumeClaim{validPVCTemplate}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - VolumeClaimTemplates: []api.PersistentVolumeClaim{validPVCTemplateChangedClass}, - }, - }, + name: "update pvc template storage class", + old: mkStatefulSet(&validPodTemplate, tweakPVCTemplate(validPVCTemplate)), + update: mkStatefulSet(&validPodTemplate, tweakPVCTemplate(validPVCTemplateChangedClass)), errs: field.ErrorList{ field.Forbidden(field.NewPath("spec"), ""), }, }, { - name: "add new pvc template", - old: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - VolumeClaimTemplates: []api.PersistentVolumeClaim{validPVCTemplate}, - }, - }, - update: apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - PodManagementPolicy: apps.OrderedReadyPodManagement, - Selector: &metav1.LabelSelector{MatchLabels: validLabels}, - Template: validPodTemplate.Template, - UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, - VolumeClaimTemplates: []api.PersistentVolumeClaim{validPVCTemplate, validPVCTemplate2}, - }, - }, + name: "add new pvc template", + old: mkStatefulSet(&validPodTemplate, tweakPVCTemplate(validPVCTemplate)), + update: mkStatefulSet(&validPodTemplate, tweakPVCTemplate(validPVCTemplate, validPVCTemplate2)), errs: field.ErrorList{ field.Forbidden(field.NewPath("spec"), ""), }, @@ -1496,22 +1022,20 @@ func TestValidateControllerRevision(t *testing.T) { } } - ss := apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}}, - Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - }, - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"foo": "bar"}, - }, + podTemplate := api.PodTemplate{ + Template: api.PodTemplateSpec{ + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + }, + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"a": "b"}, }, }, } + ss := mkStatefulSet(&podTemplate) + var ( valid = newControllerRevision("validname", "validns", &ss, 0) badRevision = newControllerRevision("validname", "validns", &ss, -1) @@ -1561,37 +1085,21 @@ func TestValidateControllerRevisionUpdate(t *testing.T) { } } - ss := apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}}, - Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - }, - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"foo": "bar"}, - }, - }, - }, - } - modifiedss := apps.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{Name: "cdf", Namespace: metav1.NamespaceDefault}, - Spec: apps.StatefulSetSpec{ - Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}}, - Template: api.PodTemplateSpec{ - Spec: api.PodSpec{ - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - }, - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"foo": "bar"}, - }, + podTemplate := api.PodTemplate{ + Template: api.PodTemplateSpec{ + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + }, + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"a": "b"}, }, }, } + ss := mkStatefulSet(&podTemplate, tweakName("abc")) + modifiedss := mkStatefulSet(&podTemplate, tweakName("cdf")) + var ( valid = newControllerRevision("1", "validname", "validns", &ss, 0) noVersion = newControllerRevision("", "validname", "validns", &ss, 0)