Adding defaults to Deployment

pull/6/head
nikhiljindal 2015-09-01 02:48:53 -07:00
parent f7123ac8c6
commit 30a58321e8
13 changed files with 253 additions and 77 deletions

View File

@ -17,6 +17,7 @@ limitations under the License.
package testing
import (
"fmt"
"math/rand"
"reflect"
"strconv"
@ -120,8 +121,23 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
c.FuzzNoCustom(j) // fuzz self without calling this function again
//j.TemplateRef = nil // this is required for round trip
},
func(j *expapi.DaemonSpec, c fuzz.Continue) {
func(j *expapi.DeploymentStrategy, c fuzz.Continue) {
c.FuzzNoCustom(j) // fuzz self without calling this function again
// Ensure that strategyType is one of valid values.
strategyTypes := []expapi.DeploymentType{expapi.DeploymentRecreate, expapi.DeploymentRollingUpdate}
j.Type = strategyTypes[c.Rand.Intn(len(strategyTypes))]
if j.Type != expapi.DeploymentRollingUpdate {
j.RollingUpdate = nil
} else {
rollingUpdate := expapi.RollingUpdateDeployment{}
if c.RandBool() {
rollingUpdate.MaxUnavailable = util.NewIntOrStringFromInt(int(c.RandUint64()))
rollingUpdate.MaxSurge = util.NewIntOrStringFromInt(int(c.RandUint64()))
} else {
rollingUpdate.MaxSurge = util.NewIntOrStringFromString(fmt.Sprintf("%d%%", c.RandUint64()))
}
j.RollingUpdate = &rollingUpdate
}
},
func(j *api.List, c fuzz.Continue) {
c.FuzzNoCustom(j) // fuzz self without calling this function again

View File

@ -822,12 +822,7 @@ func deepCopy_expapi_DeploymentSpec(in DeploymentSpec, out *DeploymentSpec, c *c
if err := deepCopy_expapi_DeploymentStrategy(in.Strategy, &out.Strategy, c); err != nil {
return err
}
if in.UniqueLabelKey != nil {
out.UniqueLabelKey = new(string)
*out.UniqueLabelKey = *in.UniqueLabelKey
} else {
out.UniqueLabelKey = nil
}
out.UniqueLabelKey = in.UniqueLabelKey
return nil
}

View File

@ -199,7 +199,7 @@ type DeploymentSpec struct {
// not add any selector and label. If unspecified, system uses
// "deployment.kubernetes.io/podTemplateHash".
// Value of this key is hash of DeploymentSpec.PodTemplateSpec.
UniqueLabelKey *string `json:"uniqueLabel,omitempty"`
UniqueLabelKey string `json:"uniqueLabelKey,omitempty"`
}
type DeploymentStrategy struct {

View File

@ -23,6 +23,7 @@ import (
v1 "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/conversion"
"k8s.io/kubernetes/pkg/expapi"
"k8s.io/kubernetes/pkg/util"
)
func addConversionFuncs() {
@ -32,7 +33,10 @@ func addConversionFuncs() {
convert_v1_PodSpec_To_api_PodSpec,
convert_expapi_DeploymentSpec_To_v1_DeploymentSpec,
convert_v1_DeploymentSpec_To_expapi_DeploymentSpec,
convert_expapi_DeploymentStrategy_To_v1_DeploymentStrategy,
convert_v1_DeploymentStrategy_To_expapi_DeploymentStrategy,
convert_expapi_RollingUpdateDeployment_To_v1_RollingUpdateDeployment,
convert_v1_RollingUpdateDeployment_To_expapi_RollingUpdateDeployment,
)
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
@ -199,12 +203,8 @@ func convert_expapi_DeploymentSpec_To_v1_DeploymentSpec(in *expapi.DeploymentSpe
if err := convert_expapi_DeploymentStrategy_To_v1_DeploymentStrategy(&in.Strategy, &out.Strategy, s); err != nil {
return err
}
if in.UniqueLabelKey != nil {
out.UniqueLabelKey = new(string)
*out.UniqueLabelKey = *in.UniqueLabelKey
} else {
out.UniqueLabelKey = nil
}
*out.UniqueLabelKey = in.UniqueLabelKey
return nil
}
@ -235,10 +235,23 @@ func convert_v1_DeploymentSpec_To_expapi_DeploymentSpec(in *DeploymentSpec, out
return err
}
if in.UniqueLabelKey != nil {
out.UniqueLabelKey = new(string)
*out.UniqueLabelKey = *in.UniqueLabelKey
out.UniqueLabelKey = *in.UniqueLabelKey
}
return nil
}
func convert_expapi_DeploymentStrategy_To_v1_DeploymentStrategy(in *expapi.DeploymentStrategy, out *DeploymentStrategy, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*expapi.DeploymentStrategy))(in)
}
out.Type = DeploymentType(in.Type)
if in.RollingUpdate != nil {
out.RollingUpdate = new(RollingUpdateDeployment)
if err := convert_expapi_RollingUpdateDeployment_To_v1_RollingUpdateDeployment(in.RollingUpdate, out.RollingUpdate, s); err != nil {
return err
}
} else {
out.UniqueLabelKey = nil
out.RollingUpdate = nil
}
return nil
}
@ -258,3 +271,37 @@ func convert_v1_DeploymentStrategy_To_expapi_DeploymentStrategy(in *DeploymentSt
}
return nil
}
func convert_expapi_RollingUpdateDeployment_To_v1_RollingUpdateDeployment(in *expapi.RollingUpdateDeployment, out *RollingUpdateDeployment, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*expapi.RollingUpdateDeployment))(in)
}
if out.MaxUnavailable == nil {
out.MaxUnavailable = &util.IntOrString{}
}
if err := s.Convert(&in.MaxUnavailable, out.MaxUnavailable, 0); err != nil {
return err
}
if out.MaxSurge == nil {
out.MaxSurge = &util.IntOrString{}
}
if err := s.Convert(&in.MaxSurge, out.MaxSurge, 0); err != nil {
return err
}
out.MinReadySeconds = in.MinReadySeconds
return nil
}
func convert_v1_RollingUpdateDeployment_To_expapi_RollingUpdateDeployment(in *RollingUpdateDeployment, out *expapi.RollingUpdateDeployment, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*RollingUpdateDeployment))(in)
}
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
}
out.MinReadySeconds = in.MinReadySeconds
return nil
}

View File

@ -1557,22 +1557,6 @@ func convert_expapi_DeploymentStatus_To_v1_DeploymentStatus(in *expapi.Deploymen
return nil
}
func convert_expapi_DeploymentStrategy_To_v1_DeploymentStrategy(in *expapi.DeploymentStrategy, out *DeploymentStrategy, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*expapi.DeploymentStrategy))(in)
}
out.Type = DeploymentType(in.Type)
if in.RollingUpdate != nil {
out.RollingUpdate = new(RollingUpdateDeployment)
if err := convert_expapi_RollingUpdateDeployment_To_v1_RollingUpdateDeployment(in.RollingUpdate, out.RollingUpdate, s); err != nil {
return err
}
} else {
out.RollingUpdate = nil
}
return nil
}
func convert_expapi_HorizontalPodAutoscaler_To_v1_HorizontalPodAutoscaler(in *expapi.HorizontalPodAutoscaler, out *HorizontalPodAutoscaler, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*expapi.HorizontalPodAutoscaler))(in)
@ -1685,20 +1669,6 @@ func convert_expapi_ResourceConsumption_To_v1_ResourceConsumption(in *expapi.Res
return nil
}
func convert_expapi_RollingUpdateDeployment_To_v1_RollingUpdateDeployment(in *expapi.RollingUpdateDeployment, out *RollingUpdateDeployment, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*expapi.RollingUpdateDeployment))(in)
}
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
}
out.MinReadySeconds = in.MinReadySeconds
return nil
}
func convert_expapi_Scale_To_v1_Scale(in *expapi.Scale, out *Scale, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*expapi.Scale))(in)
@ -2048,20 +2018,6 @@ func convert_v1_ResourceConsumption_To_expapi_ResourceConsumption(in *ResourceCo
return nil
}
func convert_v1_RollingUpdateDeployment_To_expapi_RollingUpdateDeployment(in *RollingUpdateDeployment, out *expapi.RollingUpdateDeployment, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*RollingUpdateDeployment))(in)
}
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
}
out.MinReadySeconds = in.MinReadySeconds
return nil
}
func convert_v1_Scale_To_expapi_Scale(in *Scale, out *expapi.Scale, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*Scale))(in)
@ -2208,7 +2164,6 @@ func init() {
convert_expapi_Daemon_To_v1_Daemon,
convert_expapi_DeploymentList_To_v1_DeploymentList,
convert_expapi_DeploymentStatus_To_v1_DeploymentStatus,
convert_expapi_DeploymentStrategy_To_v1_DeploymentStrategy,
convert_expapi_Deployment_To_v1_Deployment,
convert_expapi_HorizontalPodAutoscalerList_To_v1_HorizontalPodAutoscalerList,
convert_expapi_HorizontalPodAutoscalerSpec_To_v1_HorizontalPodAutoscalerSpec,
@ -2216,7 +2171,6 @@ func init() {
convert_expapi_HorizontalPodAutoscaler_To_v1_HorizontalPodAutoscaler,
convert_expapi_ReplicationControllerDummy_To_v1_ReplicationControllerDummy,
convert_expapi_ResourceConsumption_To_v1_ResourceConsumption,
convert_expapi_RollingUpdateDeployment_To_v1_RollingUpdateDeployment,
convert_expapi_ScaleSpec_To_v1_ScaleSpec,
convert_expapi_ScaleStatus_To_v1_ScaleStatus,
convert_expapi_Scale_To_v1_Scale,
@ -2264,7 +2218,6 @@ func init() {
convert_v1_ReplicationControllerDummy_To_expapi_ReplicationControllerDummy,
convert_v1_ResourceConsumption_To_expapi_ResourceConsumption,
convert_v1_ResourceRequirements_To_api_ResourceRequirements,
convert_v1_RollingUpdateDeployment_To_expapi_RollingUpdateDeployment,
convert_v1_SELinuxOptions_To_api_SELinuxOptions,
convert_v1_ScaleSpec_To_expapi_ScaleSpec,
convert_v1_ScaleStatus_To_expapi_ScaleStatus,

View File

@ -953,12 +953,22 @@ func deepCopy_v1_ResourceConsumption(in ResourceConsumption, out *ResourceConsum
}
func deepCopy_v1_RollingUpdateDeployment(in RollingUpdateDeployment, out *RollingUpdateDeployment, c *conversion.Cloner) error {
if err := deepCopy_util_IntOrString(in.MaxUnavailable, &out.MaxUnavailable, c); err != nil {
if in.MaxUnavailable != nil {
out.MaxUnavailable = new(util.IntOrString)
if err := deepCopy_util_IntOrString(*in.MaxUnavailable, out.MaxUnavailable, c); err != nil {
return err
}
if err := deepCopy_util_IntOrString(in.MaxSurge, &out.MaxSurge, c); err != nil {
} else {
out.MaxUnavailable = nil
}
if in.MaxSurge != nil {
out.MaxSurge = new(util.IntOrString)
if err := deepCopy_util_IntOrString(*in.MaxSurge, out.MaxSurge, c); err != nil {
return err
}
} else {
out.MaxSurge = nil
}
out.MinReadySeconds = in.MinReadySeconds
return nil
}

View File

@ -16,7 +16,10 @@ limitations under the License.
package v1
import "k8s.io/kubernetes/pkg/api"
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/util"
)
func addDefaultingFuncs() {
api.Scheme.AddDefaultingFuncs(
@ -40,5 +43,37 @@ func addDefaultingFuncs() {
}
}
},
func(obj *Deployment) {
// Set DeploymentSpec.Replicas to 1 if it is not set.
if obj.Spec.Replicas == nil {
obj.Spec.Replicas = new(int)
*obj.Spec.Replicas = 1
}
strategy := &obj.Spec.Strategy
// Set default DeploymentType as RollingUpdate.
if strategy.Type == "" {
strategy.Type = DeploymentRollingUpdate
}
if strategy.Type == DeploymentRollingUpdate {
if strategy.RollingUpdate == nil {
rollingUpdate := RollingUpdateDeployment{}
strategy.RollingUpdate = &rollingUpdate
}
if strategy.RollingUpdate.MaxUnavailable == nil {
// Set default MaxUnavailable as 1 by default.
maxUnavailable := util.NewIntOrStringFromInt(1)
strategy.RollingUpdate.MaxUnavailable = &maxUnavailable
}
if strategy.RollingUpdate.MaxSurge == nil {
// Set default MaxSurge as 1 by default.
maxSurge := util.NewIntOrStringFromInt(1)
strategy.RollingUpdate.MaxSurge = &maxSurge
}
}
if obj.Spec.UniqueLabelKey == nil {
obj.Spec.UniqueLabelKey = new(string)
*obj.Spec.UniqueLabelKey = "deployment.kubernetes.io/podTemplateHash"
}
},
)
}

View File

@ -23,6 +23,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util"
)
func TestSetDefaultDaemon(t *testing.T) {
@ -83,6 +84,111 @@ func TestSetDefaultDaemon(t *testing.T) {
}
}
func TestSetDefaultDeployment(t *testing.T) {
defaultIntOrString := util.NewIntOrStringFromInt(1)
differentIntOrString := util.NewIntOrStringFromInt(5)
deploymentLabelKey := "deployment.kubernetes.io/podTemplateHash"
tests := []struct {
original *Deployment
expected *Deployment
}{
{
original: &Deployment{},
expected: &Deployment{
Spec: DeploymentSpec{
Replicas: newInt(1),
Strategy: DeploymentStrategy{
Type: DeploymentRollingUpdate,
RollingUpdate: &RollingUpdateDeployment{
MaxSurge: &defaultIntOrString,
MaxUnavailable: &defaultIntOrString,
},
},
UniqueLabelKey: newString(deploymentLabelKey),
},
},
},
{
original: &Deployment{
Spec: DeploymentSpec{
Replicas: newInt(5),
Strategy: DeploymentStrategy{
RollingUpdate: &RollingUpdateDeployment{
MaxSurge: &differentIntOrString,
},
},
},
},
expected: &Deployment{
Spec: DeploymentSpec{
Replicas: newInt(5),
Strategy: DeploymentStrategy{
Type: DeploymentRollingUpdate,
RollingUpdate: &RollingUpdateDeployment{
MaxSurge: &differentIntOrString,
MaxUnavailable: &defaultIntOrString,
},
},
UniqueLabelKey: newString(deploymentLabelKey),
},
},
},
{
original: &Deployment{
Spec: DeploymentSpec{
Replicas: newInt(5),
Strategy: DeploymentStrategy{
Type: DeploymentRecreate,
},
},
},
expected: &Deployment{
Spec: DeploymentSpec{
Replicas: newInt(5),
Strategy: DeploymentStrategy{
Type: DeploymentRecreate,
},
UniqueLabelKey: newString(deploymentLabelKey),
},
},
},
{
original: &Deployment{
Spec: DeploymentSpec{
Replicas: newInt(5),
Strategy: DeploymentStrategy{
Type: DeploymentRecreate,
},
UniqueLabelKey: newString("customDeploymentKey"),
},
},
expected: &Deployment{
Spec: DeploymentSpec{
Replicas: newInt(5),
Strategy: DeploymentStrategy{
Type: DeploymentRecreate,
},
UniqueLabelKey: newString("customDeploymentKey"),
},
},
},
}
for _, test := range tests {
original := test.original
expected := test.expected
obj2 := roundTrip(t, runtime.Object(original))
got, ok := obj2.(*Deployment)
if !ok {
t.Errorf("unexpected object: %v", got)
t.FailNow()
}
if !reflect.DeepEqual(got.Spec, expected.Spec) {
t.Errorf("got different than expected: %v, %v", got, expected)
}
}
}
func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
data, err := v1.Codec.Encode(obj)
if err != nil {
@ -102,3 +208,15 @@ func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
}
return obj3
}
func newInt(val int) *int {
p := new(int)
*p = val
return p
}
func newString(val string) *string {
p := new(string)
*p = val
return p
}

View File

@ -186,7 +186,7 @@ type DeploymentSpec struct {
// not add any selector and label. If unspecified, system uses
// "deployment.kubernetes.io/podTemplateHash".
// Value of this key is hash of DeploymentSpec.PodTemplateSpec.
UniqueLabelKey *string `json:"uniqueLabel,omitempty" description:"key of the label that is added to existing pods to distinguish them from new ones; deployment.kubernetes.io/podTemplateHash is used by default; value of this label is hash of pod template spec; no label is added if this is set to empty string"`
UniqueLabelKey *string `json:"uniqueLabelKey,omitempty" description:"key of the label that is added to existing pods to distinguish them from new ones; deployment.kubernetes.io/podTemplateHash is used by default; value of this label is hash of pod template spec; no label is added if this is set to empty string"`
}
type DeploymentStrategy struct {
@ -222,7 +222,7 @@ type RollingUpdateDeployment struct {
// can be scaled down further, followed by scaling up the new RC, ensuring
// that at least 70% of original number of pods are available at all times
// during the update.
MaxUnavailable util.IntOrString `json:"maxUnavailable,omitempty" description:"max number of pods that can be unavailable during the update; value can be an absolute number or a percentage of total pods at start of update"`
MaxUnavailable *util.IntOrString `json:"maxUnavailable,omitempty" description:"max number of pods that can be unavailable during the update; value can be an absolute number or a percentage of total pods at start of update"`
// The maximum number of pods that can be scheduled above the original number of
// pods.
@ -234,7 +234,7 @@ type RollingUpdateDeployment struct {
// immediately when the rolling update starts. Once old pods have been killed,
// new RC can be scaled up further, ensuring that total number of pods running
// at any time during the update is atmost 130% of original pods.
MaxSurge util.IntOrString `json:"maxSurge,omitempty" description:"max number of pods that can be scheduled above the original number of pods; value can be an absolute number or a percentage of total pods at start of update"`
MaxSurge *util.IntOrString `json:"maxSurge,omitempty" description:"max number of pods that can be scheduled above the original number of pods; value can be an absolute number or a percentage of total pods at start of update"`
// Minimum number of seconds for which a newly created pod should be ready
// without any of its container crashing, for it to be considered available.

View File

@ -238,9 +238,7 @@ func ValidateDeploymentSpec(spec *expapi.DeploymentSpec) errs.ValidationErrorLis
allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(spec.Replicas), "replicas")...)
allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpecForRC(spec.Template, spec.Selector, spec.Replicas, "template")...)
allErrs = append(allErrs, ValidateDeploymentStrategy(&spec.Strategy, "strategy")...)
if spec.UniqueLabelKey != nil {
allErrs = append(allErrs, apivalidation.ValidateLabelName(*spec.UniqueLabelKey, "uniqueLabel")...)
}
allErrs = append(allErrs, apivalidation.ValidateLabelName(spec.UniqueLabelKey, "uniqueLabel")...)
return allErrs
}

View File

@ -572,6 +572,7 @@ func validDeployment() *expapi.Deployment {
},
},
},
UniqueLabelKey: "my-label",
},
}
}
@ -606,8 +607,7 @@ func TestValidateDeployment(t *testing.T) {
// invalid unique label key.
invalidUniqueLabelDeployment := validDeployment()
invalidUniqueLabel := "abc/def/ghi"
invalidUniqueLabelDeployment.Spec.UniqueLabelKey = &invalidUniqueLabel
invalidUniqueLabelDeployment.Spec.UniqueLabelKey = "abc/def/ghi"
errorCases["spec.uniqueLabel: invalid value"] = invalidUniqueLabelDeployment
// rollingUpdate should be nil for recreate.

View File

@ -69,6 +69,7 @@ func validNewDeployment() *expapi.Deployment {
DNSPolicy: api.DNSClusterFirst,
},
},
UniqueLabelKey: "my-label",
},
}
}

View File

@ -172,6 +172,9 @@ func (intstr IntOrString) MarshalJSON() ([]byte, error) {
}
func (intstr *IntOrString) Fuzz(c fuzz.Continue) {
if intstr == nil {
return
}
if c.RandBool() {
intstr.Kind = IntstrInt
c.Fuzz(&intstr.IntVal)