Promotes the StatefulSet, ControllerRevision, Deployment, and ReplicaSet kinds to the apps/v1 group version.

This commit is contained in:
Kenneth Owens
2017-10-10 14:30:02 -07:00
parent dc35709eee
commit 26bf978c07
12 changed files with 1948 additions and 3 deletions

View File

@@ -17,13 +17,18 @@ limitations under the License.
package v1
import (
"fmt"
"strconv"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/kubernetes/pkg/api"
k8s_api_v1 "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/apps"
"k8s.io/kubernetes/pkg/apis/extensions"
)
@@ -33,14 +38,33 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
// it, but a plain int32 is more convenient in the internal type. These
// functions are the same as the autogenerated ones in every other way.
err := scheme.AddConversionFuncs(
Convert_v1_StatefulSetSpec_To_apps_StatefulSetSpec,
Convert_apps_StatefulSetSpec_To_v1_StatefulSetSpec,
Convert_v1_StatefulSetUpdateStrategy_To_apps_StatefulSetUpdateStrategy,
Convert_apps_StatefulSetUpdateStrategy_To_v1_StatefulSetUpdateStrategy,
Convert_extensions_RollingUpdateDaemonSet_To_v1_RollingUpdateDaemonSet,
Convert_v1_RollingUpdateDaemonSet_To_extensions_RollingUpdateDaemonSet,
Convert_v1_StatefulSetStatus_To_apps_StatefulSetStatus,
Convert_apps_StatefulSetStatus_To_v1_StatefulSetStatus,
Convert_v1_Deployment_To_extensions_Deployment,
Convert_extensions_Deployment_To_v1_Deployment,
Convert_extensions_DaemonSet_To_v1_DaemonSet,
Convert_v1_DaemonSet_To_extensions_DaemonSet,
Convert_extensions_DaemonSetSpec_To_v1_DaemonSetSpec,
Convert_v1_DaemonSetSpec_To_extensions_DaemonSetSpec,
Convert_extensions_DaemonSetUpdateStrategy_To_v1_DaemonSetUpdateStrategy,
Convert_v1_DaemonSetUpdateStrategy_To_extensions_DaemonSetUpdateStrategy,
// extensions
// TODO: below conversions should be dropped in favor of auto-generated
// ones, see https://github.com/kubernetes/kubernetes/issues/39865
Convert_v1_DeploymentSpec_To_extensions_DeploymentSpec,
Convert_extensions_DeploymentSpec_To_v1_DeploymentSpec,
Convert_v1_DeploymentStrategy_To_extensions_DeploymentStrategy,
Convert_extensions_DeploymentStrategy_To_v1_DeploymentStrategy,
Convert_v1_RollingUpdateDeployment_To_extensions_RollingUpdateDeployment,
Convert_extensions_RollingUpdateDeployment_To_v1_RollingUpdateDeployment,
Convert_extensions_ReplicaSetSpec_To_v1_ReplicaSetSpec,
Convert_v1_ReplicaSetSpec_To_extensions_ReplicaSetSpec,
)
if err != nil {
return err
@@ -48,6 +72,150 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
return nil
}
func Convert_v1_DeploymentSpec_To_extensions_DeploymentSpec(in *appsv1.DeploymentSpec, out *extensions.DeploymentSpec, s conversion.Scope) error {
if in.Replicas != nil {
out.Replicas = *in.Replicas
}
out.Selector = in.Selector
if err := k8s_api_v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(&in.Template, &out.Template, s); err != nil {
return err
}
if err := Convert_v1_DeploymentStrategy_To_extensions_DeploymentStrategy(&in.Strategy, &out.Strategy, s); err != nil {
return err
}
out.RevisionHistoryLimit = in.RevisionHistoryLimit
out.MinReadySeconds = in.MinReadySeconds
out.Paused = in.Paused
if in.ProgressDeadlineSeconds != nil {
out.ProgressDeadlineSeconds = new(int32)
*out.ProgressDeadlineSeconds = *in.ProgressDeadlineSeconds
}
return nil
}
func Convert_extensions_DeploymentSpec_To_v1_DeploymentSpec(in *extensions.DeploymentSpec, out *appsv1.DeploymentSpec, s conversion.Scope) error {
out.Replicas = &in.Replicas
out.Selector = in.Selector
if err := k8s_api_v1.Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(&in.Template, &out.Template, s); err != nil {
return err
}
if err := Convert_extensions_DeploymentStrategy_To_v1_DeploymentStrategy(&in.Strategy, &out.Strategy, s); err != nil {
return err
}
if in.RevisionHistoryLimit != nil {
out.RevisionHistoryLimit = new(int32)
*out.RevisionHistoryLimit = int32(*in.RevisionHistoryLimit)
}
out.MinReadySeconds = int32(in.MinReadySeconds)
out.Paused = in.Paused
if in.ProgressDeadlineSeconds != nil {
out.ProgressDeadlineSeconds = new(int32)
*out.ProgressDeadlineSeconds = *in.ProgressDeadlineSeconds
}
return nil
}
func Convert_extensions_DeploymentStrategy_To_v1_DeploymentStrategy(in *extensions.DeploymentStrategy, out *appsv1.DeploymentStrategy, s conversion.Scope) error {
out.Type = appsv1.DeploymentStrategyType(in.Type)
if in.RollingUpdate != nil {
out.RollingUpdate = new(appsv1.RollingUpdateDeployment)
if err := Convert_extensions_RollingUpdateDeployment_To_v1_RollingUpdateDeployment(in.RollingUpdate, out.RollingUpdate, s); err != nil {
return err
}
} else {
out.RollingUpdate = nil
}
return nil
}
func Convert_v1_DeploymentStrategy_To_extensions_DeploymentStrategy(in *appsv1.DeploymentStrategy, out *extensions.DeploymentStrategy, s conversion.Scope) error {
out.Type = extensions.DeploymentStrategyType(in.Type)
if in.RollingUpdate != nil {
out.RollingUpdate = new(extensions.RollingUpdateDeployment)
if err := Convert_v1_RollingUpdateDeployment_To_extensions_RollingUpdateDeployment(in.RollingUpdate, out.RollingUpdate, s); err != nil {
return err
}
} else {
out.RollingUpdate = nil
}
return nil
}
func Convert_v1_RollingUpdateDeployment_To_extensions_RollingUpdateDeployment(in *appsv1.RollingUpdateDeployment, out *extensions.RollingUpdateDeployment, s conversion.Scope) error {
if err := s.Convert(in.MaxUnavailable, &out.MaxUnavailable, 0); err != nil {
return err
}
if err := s.Convert(in.MaxSurge, &out.MaxSurge, 0); err != nil {
return err
}
return nil
}
func Convert_extensions_RollingUpdateDeployment_To_v1_RollingUpdateDeployment(in *extensions.RollingUpdateDeployment, out *appsv1.RollingUpdateDeployment, s conversion.Scope) error {
if out.MaxUnavailable == nil {
out.MaxUnavailable = &intstr.IntOrString{}
}
if err := s.Convert(&in.MaxUnavailable, out.MaxUnavailable, 0); err != nil {
return err
}
if out.MaxSurge == nil {
out.MaxSurge = &intstr.IntOrString{}
}
if err := s.Convert(&in.MaxSurge, out.MaxSurge, 0); err != nil {
return err
}
return nil
}
func Convert_v1_Deployment_To_extensions_Deployment(in *appsv1.Deployment, out *extensions.Deployment, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1_DeploymentSpec_To_extensions_DeploymentSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
// Copy annotation to deprecated rollbackTo field for roundtrip
// TODO: remove this conversion after we delete extensions/v1beta1 and apps/v1beta1 Deployment
if revision, _ := in.Annotations[appsv1.DeprecatedRollbackTo]; revision != "" {
if revision64, err := strconv.ParseInt(revision, 10, 64); err != nil {
return fmt.Errorf("failed to parse annotation[%s]=%s as int64: %v", appsv1.DeprecatedRollbackTo, revision, err)
} else {
out.Spec.RollbackTo = new(extensions.RollbackConfig)
out.Spec.RollbackTo.Revision = revision64
}
delete(out.Annotations, appsv1.DeprecatedRollbackTo)
} else {
out.Spec.RollbackTo = nil
}
if err := Convert_v1_DeploymentStatus_To_extensions_DeploymentStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_extensions_Deployment_To_v1_Deployment(in *extensions.Deployment, out *appsv1.Deployment, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_extensions_DeploymentSpec_To_v1_DeploymentSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
// Copy deprecated rollbackTo field to annotation for roundtrip
// TODO: remove this conversion after we delete extensions/v1beta1 and apps/v1beta1 Deployment
if in.Spec.RollbackTo != nil {
if out.Annotations == nil {
out.Annotations = make(map[string]string)
}
out.Annotations[appsv1.DeprecatedRollbackTo] = strconv.FormatInt(in.Spec.RollbackTo.Revision, 10)
} else {
delete(out.Annotations, appsv1.DeprecatedRollbackTo)
}
if err := Convert_extensions_DeploymentStatus_To_v1_DeploymentStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_extensions_RollingUpdateDaemonSet_To_v1_RollingUpdateDaemonSet(in *extensions.RollingUpdateDaemonSet, out *appsv1.RollingUpdateDaemonSet, s conversion.Scope) error {
if out.MaxUnavailable == nil {
out.MaxUnavailable = &intstr.IntOrString{}
@@ -156,3 +324,163 @@ func Convert_v1_DaemonSetUpdateStrategy_To_extensions_DaemonSetUpdateStrategy(in
}
return nil
}
func Convert_extensions_ReplicaSetSpec_To_v1_ReplicaSetSpec(in *extensions.ReplicaSetSpec, out *appsv1.ReplicaSetSpec, s conversion.Scope) error {
out.Replicas = new(int32)
*out.Replicas = int32(in.Replicas)
out.MinReadySeconds = in.MinReadySeconds
out.Selector = in.Selector
if err := k8s_api_v1.Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(&in.Template, &out.Template, s); err != nil {
return err
}
return nil
}
func Convert_v1_ReplicaSetSpec_To_extensions_ReplicaSetSpec(in *appsv1.ReplicaSetSpec, out *extensions.ReplicaSetSpec, s conversion.Scope) error {
if in.Replicas != nil {
out.Replicas = *in.Replicas
}
out.MinReadySeconds = in.MinReadySeconds
out.Selector = in.Selector
if err := k8s_api_v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(&in.Template, &out.Template, s); err != nil {
return err
}
return nil
}
func Convert_v1_StatefulSetSpec_To_apps_StatefulSetSpec(in *appsv1.StatefulSetSpec, out *apps.StatefulSetSpec, s conversion.Scope) error {
if in.Replicas != nil {
out.Replicas = *in.Replicas
}
if in.Selector != nil {
in, out := &in.Selector, &out.Selector
*out = new(metav1.LabelSelector)
if err := s.Convert(*in, *out, 0); err != nil {
return err
}
} else {
out.Selector = nil
}
if err := k8s_api_v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(&in.Template, &out.Template, s); err != nil {
return err
}
if in.VolumeClaimTemplates != nil {
in, out := &in.VolumeClaimTemplates, &out.VolumeClaimTemplates
*out = make([]api.PersistentVolumeClaim, len(*in))
for i := range *in {
if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil {
return err
}
}
} else {
out.VolumeClaimTemplates = nil
}
if err := Convert_v1_StatefulSetUpdateStrategy_To_apps_StatefulSetUpdateStrategy(&in.UpdateStrategy, &out.UpdateStrategy, s); err != nil {
return err
}
if in.RevisionHistoryLimit != nil {
out.RevisionHistoryLimit = new(int32)
*out.RevisionHistoryLimit = *in.RevisionHistoryLimit
} else {
out.RevisionHistoryLimit = nil
}
out.ServiceName = in.ServiceName
out.PodManagementPolicy = apps.PodManagementPolicyType(in.PodManagementPolicy)
return nil
}
func Convert_apps_StatefulSetSpec_To_v1_StatefulSetSpec(in *apps.StatefulSetSpec, out *appsv1.StatefulSetSpec, s conversion.Scope) error {
out.Replicas = new(int32)
*out.Replicas = in.Replicas
if in.Selector != nil {
in, out := &in.Selector, &out.Selector
*out = new(metav1.LabelSelector)
if err := s.Convert(*in, *out, 0); err != nil {
return err
}
} else {
out.Selector = nil
}
if err := k8s_api_v1.Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(&in.Template, &out.Template, s); err != nil {
return err
}
if in.VolumeClaimTemplates != nil {
in, out := &in.VolumeClaimTemplates, &out.VolumeClaimTemplates
*out = make([]v1.PersistentVolumeClaim, len(*in))
for i := range *in {
if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil {
return err
}
}
} else {
out.VolumeClaimTemplates = nil
}
if in.RevisionHistoryLimit != nil {
out.RevisionHistoryLimit = new(int32)
*out.RevisionHistoryLimit = *in.RevisionHistoryLimit
} else {
out.RevisionHistoryLimit = nil
}
out.ServiceName = in.ServiceName
out.PodManagementPolicy = appsv1.PodManagementPolicyType(in.PodManagementPolicy)
if err := Convert_apps_StatefulSetUpdateStrategy_To_v1_StatefulSetUpdateStrategy(&in.UpdateStrategy, &out.UpdateStrategy, s); err != nil {
return err
}
return nil
}
func Convert_v1_StatefulSetUpdateStrategy_To_apps_StatefulSetUpdateStrategy(in *appsv1.StatefulSetUpdateStrategy, out *apps.StatefulSetUpdateStrategy, s conversion.Scope) error {
out.Type = apps.StatefulSetUpdateStrategyType(in.Type)
if in.RollingUpdate != nil {
out.RollingUpdate = new(apps.RollingUpdateStatefulSetStrategy)
out.RollingUpdate.Partition = *in.RollingUpdate.Partition
} else {
out.RollingUpdate = nil
}
return nil
}
func Convert_apps_StatefulSetUpdateStrategy_To_v1_StatefulSetUpdateStrategy(in *apps.StatefulSetUpdateStrategy, out *appsv1.StatefulSetUpdateStrategy, s conversion.Scope) error {
out.Type = appsv1.StatefulSetUpdateStrategyType(in.Type)
if in.RollingUpdate != nil {
out.RollingUpdate = new(appsv1.RollingUpdateStatefulSetStrategy)
out.RollingUpdate.Partition = new(int32)
*out.RollingUpdate.Partition = in.RollingUpdate.Partition
} else {
out.RollingUpdate = nil
}
return nil
}
func Convert_v1_StatefulSetStatus_To_apps_StatefulSetStatus(in *appsv1.StatefulSetStatus, out *apps.StatefulSetStatus, s conversion.Scope) error {
out.ObservedGeneration = new(int64)
*out.ObservedGeneration = in.ObservedGeneration
out.Replicas = in.Replicas
out.ReadyReplicas = in.ReadyReplicas
out.CurrentReplicas = in.CurrentReplicas
out.UpdatedReplicas = in.UpdatedReplicas
out.CurrentRevision = in.CurrentRevision
out.UpdateRevision = in.UpdateRevision
if in.CollisionCount != nil {
out.CollisionCount = new(int32)
*out.CollisionCount = *in.CollisionCount
}
return nil
}
func Convert_apps_StatefulSetStatus_To_v1_StatefulSetStatus(in *apps.StatefulSetStatus, out *appsv1.StatefulSetStatus, s conversion.Scope) error {
if in.ObservedGeneration != nil {
out.ObservedGeneration = *in.ObservedGeneration
}
out.Replicas = in.Replicas
out.ReadyReplicas = in.ReadyReplicas
out.CurrentReplicas = in.CurrentReplicas
out.UpdatedReplicas = in.UpdatedReplicas
out.CurrentRevision = in.CurrentRevision
out.UpdateRevision = in.UpdateRevision
if in.CollisionCount != nil {
out.CollisionCount = new(int32)
*out.CollisionCount = *in.CollisionCount
}
return nil
}

View File

@@ -20,13 +20,211 @@ import (
"testing"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/apps"
"k8s.io/kubernetes/pkg/apis/extensions"
apiequality "k8s.io/apimachinery/pkg/api/equality"
)
func TestV12StatefulSetSpecConversion(t *testing.T) {
replicas := newInt32(2)
selector := &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}}
appsv1Template := v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Spec: v1.PodSpec{
RestartPolicy: v1.RestartPolicy("bar"),
SecurityContext: new(v1.PodSecurityContext),
},
}
apiTemplate := api.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicy("bar"),
SecurityContext: new(api.PodSecurityContext),
},
}
testcases := map[string]struct {
stsSpec1 *apps.StatefulSetSpec
stsSepc2 *appsv1.StatefulSetSpec
}{
"StatefulSetSpec Conversion 1": {
stsSpec1: &apps.StatefulSetSpec{
Replicas: *replicas,
Template: apiTemplate,
},
stsSepc2: &appsv1.StatefulSetSpec{
Replicas: replicas,
Template: appsv1Template,
},
},
"StatefulSetSpec Conversion 2": {
stsSpec1: &apps.StatefulSetSpec{
Replicas: *replicas,
Selector: selector,
Template: apiTemplate,
ServiceName: "foo",
PodManagementPolicy: apps.PodManagementPolicyType("bar"),
},
stsSepc2: &appsv1.StatefulSetSpec{
Replicas: replicas,
Selector: selector,
Template: appsv1Template,
ServiceName: "foo",
PodManagementPolicy: appsv1.PodManagementPolicyType("bar"),
},
},
}
for k, tc := range testcases {
// apps -> appsv1
internal1 := &appsv1.StatefulSetSpec{}
if err := legacyscheme.Scheme.Convert(tc.stsSpec1, internal1, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", k, "from extensions to appsv1", err)
}
if !apiequality.Semantic.DeepEqual(internal1, tc.stsSepc2) {
t.Errorf("%q - %q: expected\n\t%#v, got \n\t%#v", k, "from extensions to appsv1", tc.stsSepc2, internal1)
}
// appsv1 -> apps
internal2 := &apps.StatefulSetSpec{}
if err := legacyscheme.Scheme.Convert(tc.stsSepc2, internal2, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", k, "from appsv1 to extensions", err)
}
if !apiequality.Semantic.DeepEqual(internal2, tc.stsSpec1) {
t.Errorf("%q- %q: expected\n\t%#v, got \n\t%#v", k, "from appsv1 to extensions", tc.stsSpec1, internal2)
}
}
}
func TestV1StatefulSetStatusConversion(t *testing.T) {
observedGeneration := new(int64)
*observedGeneration = 2
collisionCount := new(int32)
*collisionCount = 1
testcases := map[string]struct {
stsStatus1 *apps.StatefulSetStatus
stsStatus2 *appsv1.StatefulSetStatus
}{
"StatefulSetStatus Conversion 1": {
stsStatus1: &apps.StatefulSetStatus{
Replicas: int32(3),
ReadyReplicas: int32(1),
CurrentReplicas: int32(3),
UpdatedReplicas: int32(3),
CurrentRevision: "12345",
UpdateRevision: "23456",
ObservedGeneration: observedGeneration,
},
stsStatus2: &appsv1.StatefulSetStatus{
Replicas: int32(3),
ReadyReplicas: int32(1),
CurrentReplicas: int32(3),
UpdatedReplicas: int32(3),
CurrentRevision: "12345",
UpdateRevision: "23456",
ObservedGeneration: *observedGeneration,
},
},
"StatefulSetStatus Conversion 2": {
stsStatus1: &apps.StatefulSetStatus{
ObservedGeneration: observedGeneration,
Replicas: int32(3),
ReadyReplicas: int32(1),
CurrentReplicas: int32(3),
UpdatedReplicas: int32(3),
CurrentRevision: "12345",
UpdateRevision: "23456",
CollisionCount: collisionCount,
},
stsStatus2: &appsv1.StatefulSetStatus{
ObservedGeneration: *observedGeneration,
Replicas: int32(3),
ReadyReplicas: int32(1),
CurrentReplicas: int32(3),
UpdatedReplicas: int32(3),
CurrentRevision: "12345",
UpdateRevision: "23456",
CollisionCount: collisionCount,
},
},
}
for k, tc := range testcases {
// apps -> appsv1
internal1 := &appsv1.StatefulSetStatus{}
if err := legacyscheme.Scheme.Convert(tc.stsStatus1, internal1, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", k, "from apps to appsv1", err)
}
if !apiequality.Semantic.DeepEqual(internal1, tc.stsStatus2) {
t.Errorf("%q - %q: expected\n\t%#v, got \n\t%#v", k, "from apps to appsv1", tc.stsStatus2, internal1)
}
// appsv1 -> apps
internal2 := &apps.StatefulSetStatus{}
if err := legacyscheme.Scheme.Convert(tc.stsStatus2, internal2, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", k, "from appsv1 to apps", err)
}
if !apiequality.Semantic.DeepEqual(internal2, tc.stsStatus1) {
t.Errorf("%q - %q: expected\n\t%#v, got \n\t%#v", k, "from appsv1 to apps", tc.stsStatus1, internal2)
}
}
}
func TestV1StatefulSetUpdateStrategyConversion(t *testing.T) {
partition := newInt32(2)
appsv1rollingUpdate := new(appsv1.RollingUpdateStatefulSetStrategy)
appsv1rollingUpdate.Partition = partition
appsrollingUpdate := new(apps.RollingUpdateStatefulSetStrategy)
appsrollingUpdate.Partition = *partition
testcases := map[string]struct {
stsUpdateStrategy1 *apps.StatefulSetUpdateStrategy
stsUpdateStrategy2 *appsv1.StatefulSetUpdateStrategy
}{
"StatefulSetUpdateStrategy Conversion 1": {
stsUpdateStrategy1: &apps.StatefulSetUpdateStrategy{Type: apps.StatefulSetUpdateStrategyType("foo")},
stsUpdateStrategy2: &appsv1.StatefulSetUpdateStrategy{Type: appsv1.StatefulSetUpdateStrategyType("foo")},
},
"StatefulSetUpdateStrategy Conversion 2": {
stsUpdateStrategy1: &apps.StatefulSetUpdateStrategy{
Type: apps.StatefulSetUpdateStrategyType("foo"),
RollingUpdate: appsrollingUpdate,
},
stsUpdateStrategy2: &appsv1.StatefulSetUpdateStrategy{
Type: appsv1.StatefulSetUpdateStrategyType("foo"),
RollingUpdate: appsv1rollingUpdate,
},
},
}
for k, tc := range testcases {
// apps -> appsv1
internal1 := &appsv1.StatefulSetUpdateStrategy{}
if err := legacyscheme.Scheme.Convert(tc.stsUpdateStrategy1, internal1, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", "apps -> appsv1", k, err)
}
if !apiequality.Semantic.DeepEqual(internal1, tc.stsUpdateStrategy2) {
t.Errorf("%q - %q: expected\n\t%#v, got \n\t%#v", "apps -> appsv1", k, tc.stsUpdateStrategy2, internal1)
}
// appsv1 -> apps
internal2 := &apps.StatefulSetUpdateStrategy{}
if err := legacyscheme.Scheme.Convert(tc.stsUpdateStrategy2, internal2, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", "appsv1 -> apps", k, err)
}
if !apiequality.Semantic.DeepEqual(internal2, tc.stsUpdateStrategy1) {
t.Errorf("%q - %q: expected\n\t%#v, got \n\t%#v", "appsv1 -> apps", k, tc.stsUpdateStrategy1, internal2)
}
}
}
func TestV1RollingUpdateDaemonSetConversion(t *testing.T) {
intorstr := intstr.FromInt(1)
testcases := map[string]struct {
@@ -59,3 +257,344 @@ func TestV1RollingUpdateDaemonSetConversion(t *testing.T) {
}
}
}
func TestV1DeploymentConversion(t *testing.T) {
replica := newInt32(2)
rollbackTo := new(extensions.RollbackConfig)
rollbackTo.Revision = int64(2)
testcases := map[string]struct {
deployment1 *extensions.Deployment
deployment2 *appsv1.Deployment
}{
"Deployment Conversion 1": {
deployment1: &extensions.Deployment{
Spec: extensions.DeploymentSpec{
Replicas: *replica,
RollbackTo: rollbackTo,
Template: api.PodTemplateSpec{
Spec: api.PodSpec{
SecurityContext: new(api.PodSecurityContext),
},
},
},
},
deployment2: &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{appsv1.DeprecatedRollbackTo: "2"},
},
Spec: appsv1.DeploymentSpec{
Replicas: replica,
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
SecurityContext: new(v1.PodSecurityContext),
},
},
},
},
},
"Deployment Conversion 2": {
deployment1: &extensions.Deployment{
Spec: extensions.DeploymentSpec{
Replicas: *replica,
Template: api.PodTemplateSpec{
Spec: api.PodSpec{
SecurityContext: new(api.PodSecurityContext),
},
},
},
},
deployment2: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Replicas: replica,
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
SecurityContext: new(v1.PodSecurityContext),
},
},
},
},
},
}
for k, tc := range testcases {
// extensions -> v1beta2
internal1 := &appsv1.Deployment{}
if err := legacyscheme.Scheme.Convert(tc.deployment1, internal1, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", k, "from extensions to v1beta2", err)
}
if !apiequality.Semantic.DeepEqual(internal1, tc.deployment2) {
t.Errorf("%q - %q: expected\n\t%#v, got \n\t%#v", k, "from extensions to v1beta2", tc.deployment2, internal1)
}
// v1beta2 -> extensions
internal2 := &extensions.Deployment{}
if err := legacyscheme.Scheme.Convert(tc.deployment2, internal2, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", k, "from v1beta2 to extensions", err)
}
if !apiequality.Semantic.DeepEqual(internal2, tc.deployment1) {
t.Errorf("%q - %q: expected\n\t%#v, got \n\t%#v", k, "from v1beta2 to extensions", tc.deployment1, internal2)
}
}
}
func TestV1DeploymentSpecConversion(t *testing.T) {
replica := newInt32(2)
revisionHistoryLimit := newInt32(2)
progressDeadlineSeconds := newInt32(2)
testcases := map[string]struct {
deploymentSpec1 *extensions.DeploymentSpec
deploymentSpec2 *appsv1.DeploymentSpec
}{
"DeploymentSpec Conversion 1": {
deploymentSpec1: &extensions.DeploymentSpec{
Replicas: *replica,
Template: api.PodTemplateSpec{
Spec: api.PodSpec{
SecurityContext: new(api.PodSecurityContext),
},
},
},
deploymentSpec2: &appsv1.DeploymentSpec{
Replicas: replica,
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
SecurityContext: new(v1.PodSecurityContext),
},
},
},
},
"DeploymentSpec Conversion 2": {
deploymentSpec1: &extensions.DeploymentSpec{
Replicas: *replica,
RevisionHistoryLimit: revisionHistoryLimit,
MinReadySeconds: 2,
Paused: true,
Template: api.PodTemplateSpec{
Spec: api.PodSpec{
SecurityContext: new(api.PodSecurityContext),
},
},
},
deploymentSpec2: &appsv1.DeploymentSpec{
Replicas: replica,
RevisionHistoryLimit: revisionHistoryLimit,
MinReadySeconds: 2,
Paused: true,
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
SecurityContext: new(v1.PodSecurityContext),
},
},
},
},
"DeploymentSpec Conversion 3": {
deploymentSpec1: &extensions.DeploymentSpec{
Replicas: *replica,
ProgressDeadlineSeconds: progressDeadlineSeconds,
Template: api.PodTemplateSpec{
Spec: api.PodSpec{
SecurityContext: new(api.PodSecurityContext),
},
},
},
deploymentSpec2: &appsv1.DeploymentSpec{
Replicas: replica,
ProgressDeadlineSeconds: progressDeadlineSeconds,
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
SecurityContext: new(v1.PodSecurityContext),
},
},
},
},
}
// extensions -> appsv1
for k, tc := range testcases {
internal := &appsv1.DeploymentSpec{}
if err := legacyscheme.Scheme.Convert(tc.deploymentSpec1, internal, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", "extensions -> appsv1", k, err)
}
if !apiequality.Semantic.DeepEqual(internal, tc.deploymentSpec2) {
t.Errorf("%q - %q: expected\n\t%+v, got \n\t%+v", "extensions -> appsv1", k, tc.deploymentSpec2, internal)
}
}
// appsv1 -> extensions
for k, tc := range testcases {
internal := &extensions.DeploymentSpec{}
if err := legacyscheme.Scheme.Convert(tc.deploymentSpec2, internal, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", "appsv1 -> extensions", k, err)
}
if !apiequality.Semantic.DeepEqual(internal, tc.deploymentSpec1) {
t.Errorf("%q - %q: expected\n\t%+v, got \n\t%+v", "appsv1 -> extensions", k, tc.deploymentSpec1, internal)
}
}
}
func TestV1DeploymentStrategyConversion(t *testing.T) {
maxUnavailable := intstr.FromInt(2)
maxSurge := intstr.FromInt(2)
extensionsRollingUpdate := extensions.RollingUpdateDeployment{MaxUnavailable: maxUnavailable, MaxSurge: maxSurge}
appsv1RollingUpdate := appsv1.RollingUpdateDeployment{MaxUnavailable: &maxUnavailable, MaxSurge: &maxSurge}
testcases := map[string]struct {
deploymentStrategy1 *extensions.DeploymentStrategy
deploymentStrategy2 *appsv1.DeploymentStrategy
}{
"DeploymentStrategy Conversion 1": {
deploymentStrategy1: &extensions.DeploymentStrategy{Type: extensions.DeploymentStrategyType("foo")},
deploymentStrategy2: &appsv1.DeploymentStrategy{Type: appsv1.DeploymentStrategyType("foo")},
},
"DeploymentStrategy Conversion 2": {
deploymentStrategy1: &extensions.DeploymentStrategy{Type: extensions.DeploymentStrategyType("foo"), RollingUpdate: &extensionsRollingUpdate},
deploymentStrategy2: &appsv1.DeploymentStrategy{Type: appsv1.DeploymentStrategyType("foo"), RollingUpdate: &appsv1RollingUpdate},
},
}
for k, tc := range testcases {
// extensions -> appsv1
internal1 := &appsv1.DeploymentStrategy{}
if err := legacyscheme.Scheme.Convert(tc.deploymentStrategy1, internal1, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", k, "extensions -> appsv1", err)
}
if !apiequality.Semantic.DeepEqual(internal1, tc.deploymentStrategy2) {
t.Errorf("%q - %q: expected\n\t%#v, got \n\t%#v", k, "extensions -> appsv1", tc.deploymentStrategy2, internal1)
}
// appsv1 -> extensions
internal2 := &extensions.DeploymentStrategy{}
if err := legacyscheme.Scheme.Convert(tc.deploymentStrategy2, internal2, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", k, "appsv1 -> extensions", err)
}
if !apiequality.Semantic.DeepEqual(internal2, tc.deploymentStrategy1) {
t.Errorf("%q - %q: expected\n\t%#v, got \n\t%#v", k, "appsv1 -> extensions", tc.deploymentStrategy1, internal2)
}
}
}
func TestV1RollingUpdateDeploymentConversion(t *testing.T) {
nilIntStr := intstr.IntOrString{}
maxUnavailable := intstr.FromInt(2)
maxSurge := intstr.FromInt(2)
testcases := map[string]struct {
rollingUpdateDeployment1 *extensions.RollingUpdateDeployment
rollingUpdateDeployment2 *appsv1.RollingUpdateDeployment
}{
"RollingUpdateDeployment Conversion 1": {
rollingUpdateDeployment1: &extensions.RollingUpdateDeployment{},
rollingUpdateDeployment2: &appsv1.RollingUpdateDeployment{MaxUnavailable: &nilIntStr, MaxSurge: &nilIntStr},
},
"RollingUpdateDeployment Conversion 2": {
rollingUpdateDeployment1: &extensions.RollingUpdateDeployment{MaxUnavailable: maxUnavailable},
rollingUpdateDeployment2: &appsv1.RollingUpdateDeployment{MaxUnavailable: &maxUnavailable, MaxSurge: &nilIntStr},
},
"RollingUpdateDeployment Conversion 3": {
rollingUpdateDeployment1: &extensions.RollingUpdateDeployment{MaxSurge: maxSurge},
rollingUpdateDeployment2: &appsv1.RollingUpdateDeployment{MaxSurge: &maxSurge, MaxUnavailable: &nilIntStr},
},
"RollingUpdateDeployment Conversion 4": {
rollingUpdateDeployment1: &extensions.RollingUpdateDeployment{MaxUnavailable: maxUnavailable, MaxSurge: maxSurge},
rollingUpdateDeployment2: &appsv1.RollingUpdateDeployment{MaxUnavailable: &maxUnavailable, MaxSurge: &maxSurge},
},
}
for k, tc := range testcases {
// extensions -> appsv1
internal1 := &appsv1.RollingUpdateDeployment{}
if err := legacyscheme.Scheme.Convert(tc.rollingUpdateDeployment1, internal1, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", k, "extensions -> appsv1", err)
}
if !apiequality.Semantic.DeepEqual(internal1, tc.rollingUpdateDeployment2) {
t.Errorf("%q - %q: expected\n\t%#v, got \n\t%#v", k, "extensions -> appsv1", tc.rollingUpdateDeployment2, internal1)
}
// appsv1 -> extensions
internal2 := &extensions.RollingUpdateDeployment{}
if err := legacyscheme.Scheme.Convert(tc.rollingUpdateDeployment2, internal2, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", k, "appsv1 -> extensions", err)
}
if !apiequality.Semantic.DeepEqual(internal2, tc.rollingUpdateDeployment1) {
t.Errorf("%q - %q: expected\n\t%#v, got \n\t%#v", k, "appsv1 -> extensions", tc.rollingUpdateDeployment1, internal2)
}
}
}
func TestV1ReplicaSetSpecConversion(t *testing.T) {
replicas := new(int32)
*replicas = 2
matchExpressions := []metav1.LabelSelectorRequirement{
{Key: "foo", Operator: metav1.LabelSelectorOpIn, Values: []string{"foo"}},
}
matchLabels := map[string]string{"foo": "bar"}
selector := &metav1.LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions}
testcases := map[string]struct {
replicaset1 *extensions.ReplicaSetSpec
replicaset2 *appsv1.ReplicaSetSpec
}{
"ReplicaSetSpec Conversion 1": {
replicaset1: &extensions.ReplicaSetSpec{
Replicas: *replicas,
MinReadySeconds: 2,
Template: api.PodTemplateSpec{
Spec: api.PodSpec{
SecurityContext: new(api.PodSecurityContext),
},
},
},
replicaset2: &appsv1.ReplicaSetSpec{
Replicas: replicas,
MinReadySeconds: 2,
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
SecurityContext: new(v1.PodSecurityContext),
},
},
},
},
"ReplicaSetSpec Conversion 2": {
replicaset1: &extensions.ReplicaSetSpec{
Replicas: *replicas,
Selector: selector,
Template: api.PodTemplateSpec{
Spec: api.PodSpec{
SecurityContext: new(api.PodSecurityContext),
},
},
},
replicaset2: &appsv1.ReplicaSetSpec{
Replicas: replicas,
Selector: selector,
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
SecurityContext: new(v1.PodSecurityContext),
},
},
},
},
}
for k, tc := range testcases {
// extensions -> appsv1
internal1 := &appsv1.ReplicaSetSpec{}
if err := legacyscheme.Scheme.Convert(tc.replicaset1, internal1, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", k, "extensions -> appsv1", err)
}
if !apiequality.Semantic.DeepEqual(internal1, tc.replicaset2) {
t.Errorf("%q - %q: expected\n\t%+v, got \n\t%+v", k, "extensions -> appsv1", tc.replicaset2, internal1)
}
// appsv1 -> extensions
internal2 := &extensions.ReplicaSetSpec{}
if err := legacyscheme.Scheme.Convert(tc.replicaset2, internal2, nil); err != nil {
t.Errorf("%q - %q: unexpected error: %v", k, "appsv1 -> extensions", err)
}
if !apiequality.Semantic.DeepEqual(internal2, tc.replicaset1) {
t.Errorf("%q - %q: expected\n\t%+v, got \n\t%+v", k, "appsv1 -> extensions", tc.replicaset1, internal2)
}
}
}

View File

@@ -26,6 +26,49 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error {
return RegisterDefaults(scheme)
}
// SetDefaults_Deployment sets additional defaults compared to its counterpart
// in extensions. These addons are:
// - MaxUnavailable during rolling update set to 25% (1 in extensions)
// - MaxSurge value during rolling update set to 25% (1 in extensions)
// - RevisionHistoryLimit set to 10 (not set in extensions)
// - ProgressDeadlineSeconds set to 600s (not set in extensions)
func SetDefaults_Deployment(obj *appsv1.Deployment) {
// Set DeploymentSpec.Replicas to 1 if it is not set.
if obj.Spec.Replicas == nil {
obj.Spec.Replicas = new(int32)
*obj.Spec.Replicas = 1
}
strategy := &obj.Spec.Strategy
// Set default DeploymentStrategyType as RollingUpdate.
if strategy.Type == "" {
strategy.Type = appsv1.RollingUpdateDeploymentStrategyType
}
if strategy.Type == appsv1.RollingUpdateDeploymentStrategyType {
if strategy.RollingUpdate == nil {
rollingUpdate := appsv1.RollingUpdateDeployment{}
strategy.RollingUpdate = &rollingUpdate
}
if strategy.RollingUpdate.MaxUnavailable == nil {
// Set default MaxUnavailable as 25% by default.
maxUnavailable := intstr.FromString("25%")
strategy.RollingUpdate.MaxUnavailable = &maxUnavailable
}
if strategy.RollingUpdate.MaxSurge == nil {
// Set default MaxSurge as 25% by default.
maxSurge := intstr.FromString("25%")
strategy.RollingUpdate.MaxSurge = &maxSurge
}
}
if obj.Spec.RevisionHistoryLimit == nil {
obj.Spec.RevisionHistoryLimit = new(int32)
*obj.Spec.RevisionHistoryLimit = 10
}
if obj.Spec.ProgressDeadlineSeconds == nil {
obj.Spec.ProgressDeadlineSeconds = new(int32)
*obj.Spec.ProgressDeadlineSeconds = 600
}
}
func SetDefaults_DaemonSet(obj *appsv1.DaemonSet) {
updateStrategy := &obj.Spec.UpdateStrategy
if updateStrategy.Type == "" {
@@ -47,3 +90,38 @@ func SetDefaults_DaemonSet(obj *appsv1.DaemonSet) {
*obj.Spec.RevisionHistoryLimit = 10
}
}
func SetDefaults_StatefulSet(obj *appsv1.StatefulSet) {
if len(obj.Spec.PodManagementPolicy) == 0 {
obj.Spec.PodManagementPolicy = appsv1.OrderedReadyPodManagement
}
if obj.Spec.UpdateStrategy.Type == "" {
obj.Spec.UpdateStrategy.Type = appsv1.RollingUpdateStatefulSetStrategyType
// UpdateStrategy.RollingUpdate will take default values below.
obj.Spec.UpdateStrategy.RollingUpdate = &appsv1.RollingUpdateStatefulSetStrategy{}
}
if obj.Spec.UpdateStrategy.Type == appsv1.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
}
if obj.Spec.Replicas == nil {
obj.Spec.Replicas = new(int32)
*obj.Spec.Replicas = 1
}
if obj.Spec.RevisionHistoryLimit == nil {
obj.Spec.RevisionHistoryLimit = new(int32)
*obj.Spec.RevisionHistoryLimit = 10
}
}
func SetDefaults_ReplicaSet(obj *appsv1.ReplicaSet) {
if obj.Spec.Replicas == nil {
obj.Spec.Replicas = new(int32)
*obj.Spec.Replicas = 1
}
}

View File

@@ -23,6 +23,7 @@ import (
appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
@@ -167,6 +168,382 @@ 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 *appsv1.StatefulSet
expected *appsv1.StatefulSet
}{
{ // labels and default update strategy
original: &appsv1.StatefulSet{
Spec: appsv1.StatefulSetSpec{
Template: defaultTemplate,
},
},
expected: &appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Labels: defaultLabels,
},
Spec: appsv1.StatefulSetSpec{
Replicas: &defaultReplicas,
Template: defaultTemplate,
PodManagementPolicy: appsv1.OrderedReadyPodManagement,
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
Type: appsv1.RollingUpdateStatefulSetStrategyType,
RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{
Partition: &defaultPartition,
},
},
RevisionHistoryLimit: newInt32(10),
},
},
},
{ // Alternate update strategy
original: &appsv1.StatefulSet{
Spec: appsv1.StatefulSetSpec{
Template: defaultTemplate,
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
Type: appsv1.OnDeleteStatefulSetStrategyType,
},
},
},
expected: &appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Labels: defaultLabels,
},
Spec: appsv1.StatefulSetSpec{
Replicas: &defaultReplicas,
Template: defaultTemplate,
PodManagementPolicy: appsv1.OrderedReadyPodManagement,
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
Type: appsv1.OnDeleteStatefulSetStrategyType,
},
RevisionHistoryLimit: newInt32(10),
},
},
},
{ // Parallel pod management policy.
original: &appsv1.StatefulSet{
Spec: appsv1.StatefulSetSpec{
Template: defaultTemplate,
PodManagementPolicy: appsv1.ParallelPodManagement,
},
},
expected: &appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Labels: defaultLabels,
},
Spec: appsv1.StatefulSetSpec{
Replicas: &defaultReplicas,
Template: defaultTemplate,
PodManagementPolicy: appsv1.ParallelPodManagement,
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
Type: appsv1.RollingUpdateStatefulSetStrategyType,
RollingUpdate: &appsv1.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.(*appsv1.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)
period := int64(v1.DefaultTerminationGracePeriodSeconds)
defaultTemplate := v1.PodTemplateSpec{
Spec: v1.PodSpec{
DNSPolicy: v1.DNSClusterFirst,
RestartPolicy: v1.RestartPolicyAlways,
SecurityContext: &v1.PodSecurityContext{},
TerminationGracePeriodSeconds: &period,
SchedulerName: api.DefaultSchedulerName,
},
}
tests := []struct {
original *appsv1.Deployment
expected *appsv1.Deployment
}{
{
original: &appsv1.Deployment{},
expected: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Replicas: newInt32(1),
Strategy: appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: &defaultIntOrString,
MaxUnavailable: &defaultIntOrString,
},
},
RevisionHistoryLimit: newInt32(10),
ProgressDeadlineSeconds: newInt32(600),
Template: defaultTemplate,
},
},
},
{
original: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Replicas: newInt32(5),
Strategy: appsv1.DeploymentStrategy{
RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: &differentIntOrString,
},
},
},
},
expected: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Replicas: newInt32(5),
Strategy: appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: &differentIntOrString,
MaxUnavailable: &defaultIntOrString,
},
},
RevisionHistoryLimit: newInt32(10),
ProgressDeadlineSeconds: newInt32(600),
Template: defaultTemplate,
},
},
},
{
original: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Replicas: newInt32(3),
Strategy: appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: nil,
},
},
},
expected: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Replicas: newInt32(3),
Strategy: appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: &defaultIntOrString,
MaxUnavailable: &defaultIntOrString,
},
},
RevisionHistoryLimit: newInt32(10),
ProgressDeadlineSeconds: newInt32(600),
Template: defaultTemplate,
},
},
},
{
original: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Replicas: newInt32(5),
Strategy: appsv1.DeploymentStrategy{
Type: appsv1.RecreateDeploymentStrategyType,
},
RevisionHistoryLimit: newInt32(0),
},
},
expected: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Replicas: newInt32(5),
Strategy: appsv1.DeploymentStrategy{
Type: appsv1.RecreateDeploymentStrategyType,
},
RevisionHistoryLimit: newInt32(0),
ProgressDeadlineSeconds: newInt32(600),
Template: defaultTemplate,
},
},
},
{
original: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Replicas: newInt32(5),
Strategy: appsv1.DeploymentStrategy{
Type: appsv1.RecreateDeploymentStrategyType,
},
ProgressDeadlineSeconds: newInt32(30),
RevisionHistoryLimit: newInt32(2),
},
},
expected: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Replicas: newInt32(5),
Strategy: appsv1.DeploymentStrategy{
Type: appsv1.RecreateDeploymentStrategyType,
},
ProgressDeadlineSeconds: newInt32(30),
RevisionHistoryLimit: newInt32(2),
Template: defaultTemplate,
},
},
},
}
for _, test := range tests {
original := test.original
expected := test.expected
obj2 := roundTrip(t, runtime.Object(original))
got, ok := obj2.(*appsv1.Deployment)
if !ok {
t.Errorf("unexpected object: %v", got)
t.FailNow()
}
if !apiequality.Semantic.DeepEqual(got.Spec, expected.Spec) {
t.Errorf("object mismatch!\nexpected:\n\t%+v\ngot:\n\t%+v", got.Spec, expected.Spec)
}
}
}
func TestDefaultDeploymentAvailability(t *testing.T) {
d := roundTrip(t, runtime.Object(&appsv1.Deployment{})).(*appsv1.Deployment)
maxUnavailable, err := intstr.GetValueFromIntOrPercent(d.Spec.Strategy.RollingUpdate.MaxUnavailable, int(*(d.Spec.Replicas)), false)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if *(d.Spec.Replicas)-int32(maxUnavailable) <= 0 {
t.Fatalf("the default value of maxUnavailable can lead to no active replicas during rolling update")
}
}
func TestSetDefaultReplicaSetReplicas(t *testing.T) {
tests := []struct {
rs appsv1.ReplicaSet
expectReplicas int32
}{
{
rs: appsv1.ReplicaSet{
Spec: appsv1.ReplicaSetSpec{
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectReplicas: 1,
},
{
rs: appsv1.ReplicaSet{
Spec: appsv1.ReplicaSetSpec{
Replicas: newInt32(0),
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectReplicas: 0,
},
{
rs: appsv1.ReplicaSet{
Spec: appsv1.ReplicaSetSpec{
Replicas: newInt32(3),
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectReplicas: 3,
},
}
for _, test := range tests {
rs := &test.rs
obj2 := roundTrip(t, runtime.Object(rs))
rs2, ok := obj2.(*appsv1.ReplicaSet)
if !ok {
t.Errorf("unexpected object: %v", rs2)
t.FailNow()
}
if rs2.Spec.Replicas == nil {
t.Errorf("unexpected nil Replicas")
} else if test.expectReplicas != *rs2.Spec.Replicas {
t.Errorf("expected: %d replicas, got: %d", test.expectReplicas, *rs2.Spec.Replicas)
}
}
}
func TestDefaultRequestIsNotSetForReplicaSet(t *testing.T) {
s := v1.PodSpec{}
s.Containers = []v1.Container{
{
Resources: v1.ResourceRequirements{
Limits: v1.ResourceList{
v1.ResourceCPU: resource.MustParse("100m"),
},
},
},
}
rs := &appsv1.ReplicaSet{
Spec: appsv1.ReplicaSetSpec{
Replicas: newInt32(3),
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
Spec: s,
},
},
}
output := roundTrip(t, runtime.Object(rs))
rs2 := output.(*appsv1.ReplicaSet)
defaultRequest := rs2.Spec.Template.Spec.Containers[0].Resources.Requests
requestValue := defaultRequest[v1.ResourceCPU]
if requestValue.String() != "0" {
t.Errorf("Expected 0 request value, got: %s", requestValue.String())
}
}
func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
data, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(SchemeGroupVersion), obj)
if err != nil {