diff --git a/pkg/api/v1/defaults.go b/pkg/api/v1/defaults.go index a29563c232c..da67af2b1b5 100644 --- a/pkg/api/v1/defaults.go +++ b/pkg/api/v1/defaults.go @@ -93,6 +93,24 @@ func addDefaultingFuncs() { } } }, + func(obj *Pod) { + // If limits are specified, but requests are not, default requests to limits + // This is done here rather than a more specific defaulting pass on ResourceRequirements + // because we only want this defaulting semantic to take place on a Pod and not a PodTemplate + for i := range obj.Spec.Containers { + // set requests to limits if requests are not specified, but limits are + if obj.Spec.Containers[i].Resources.Limits != nil { + if obj.Spec.Containers[i].Resources.Requests == nil { + obj.Spec.Containers[i].Resources.Requests = make(ResourceList) + } + for key, value := range obj.Spec.Containers[i].Resources.Limits { + if _, exists := obj.Spec.Containers[i].Resources.Requests[key]; !exists { + obj.Spec.Containers[i].Resources.Requests[key] = *(value.Copy()) + } + } + } + } + }, func(obj *PodSpec) { if obj.DNSPolicy == "" { obj.DNSPolicy = DNSClusterFirst @@ -165,19 +183,6 @@ func addDefaultingFuncs() { obj.APIVersion = "v1" } }, - func(obj *ResourceRequirements) { - // Set requests to limits if requests are not specified (but limits are). - if obj.Limits != nil { - if obj.Requests == nil { - obj.Requests = make(ResourceList) - } - for key, value := range obj.Limits { - if _, exists := obj.Requests[key]; !exists { - obj.Requests[key] = *(value.Copy()) - } - } - } - }, func(obj *LimitRangeItem) { // for container limits, we apply default values if obj.Type == LimitTypeContainer { diff --git a/pkg/api/v1/defaults_test.go b/pkg/api/v1/defaults_test.go index 7a60866fb34..7ce9c8efa57 100644 --- a/pkg/api/v1/defaults_test.go +++ b/pkg/api/v1/defaults_test.go @@ -433,6 +433,77 @@ func TestSetDefaultObjectFieldSelectorAPIVersion(t *testing.T) { } } +func TestSetDefaultRequestsPod(t *testing.T) { + // verify we default if limits are specified + s := versioned.PodSpec{} + s.Containers = []versioned.Container{ + { + Resources: versioned.ResourceRequirements{ + Limits: versioned.ResourceList{ + versioned.ResourceCPU: resource.MustParse("100m"), + }, + }, + }, + } + pod := &versioned.Pod{ + Spec: s, + } + output := roundTrip(t, runtime.Object(pod)) + pod2 := output.(*versioned.Pod) + defaultRequest := pod2.Spec.Containers[0].Resources.Requests + requestValue := defaultRequest[versioned.ResourceCPU] + if requestValue.String() != "100m" { + t.Errorf("Expected request cpu: %s, got: %s", "100m", requestValue.String()) + } + + // verify we do nothing if no limits are specified + s = versioned.PodSpec{} + s.Containers = []versioned.Container{{}} + pod = &versioned.Pod{ + Spec: s, + } + output = roundTrip(t, runtime.Object(pod)) + pod2 = output.(*versioned.Pod) + defaultRequest = pod2.Spec.Containers[0].Resources.Requests + requestValue = defaultRequest[versioned.ResourceCPU] + if requestValue.String() != "0" { + t.Errorf("Expected 0 request value, got: %s", requestValue.String()) + } +} + +func TestDefaultRequestIsNotSetForReplicationController(t *testing.T) { + s := versioned.PodSpec{} + s.Containers = []versioned.Container{ + { + Resources: versioned.ResourceRequirements{ + Limits: versioned.ResourceList{ + versioned.ResourceCPU: resource.MustParse("100m"), + }, + }, + }, + } + rc := &versioned.ReplicationController{ + Spec: versioned.ReplicationControllerSpec{ + Replicas: newInt(3), + Template: &versioned.PodTemplateSpec{ + ObjectMeta: versioned.ObjectMeta{ + Labels: map[string]string{ + "foo": "bar", + }, + }, + Spec: s, + }, + }, + } + output := roundTrip(t, runtime.Object(rc)) + rc2 := output.(*versioned.ReplicationController) + defaultRequest := rc2.Spec.Template.Spec.Containers[0].Resources.Requests + requestValue := defaultRequest[versioned.ResourceCPU] + if requestValue.String() != "0" { + t.Errorf("Expected 0 request value, got: %s", requestValue.String()) + } +} + func TestSetDefaultLimitRangeItem(t *testing.T) { limitRange := &versioned.LimitRange{ ObjectMeta: versioned.ObjectMeta{