mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
Merge pull request #3841 from vishh/api_resources
Adding an extensible resource spec to the API.
This commit is contained in:
commit
ce164f67fd
42
pkg/api/resource_helpers.go
Normal file
42
pkg/api/resource_helpers.go
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
)
|
||||
|
||||
// Returns string version of ResourceName.
|
||||
func (self ResourceName) String() string {
|
||||
return string(self)
|
||||
}
|
||||
|
||||
// Returns the CPU limit if specified.
|
||||
func (self *ResourceList) Cpu() *resource.Quantity {
|
||||
if val, ok := (*self)[ResourceCPU]; ok {
|
||||
return &val
|
||||
}
|
||||
return &resource.Quantity{}
|
||||
}
|
||||
|
||||
// Returns the Memory limit if specified.
|
||||
func (self *ResourceList) Memory() *resource.Quantity {
|
||||
if val, ok := (*self)[ResourceMemory]; ok {
|
||||
return &val
|
||||
}
|
||||
return &resource.Quantity{}
|
||||
}
|
53
pkg/api/resource_helpers_test.go
Normal file
53
pkg/api/resource_helpers_test.go
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
)
|
||||
|
||||
func TestResourceHelpers(t *testing.T) {
|
||||
cpuLimit := resource.MustParse("10")
|
||||
memoryLimit := resource.MustParse("10G")
|
||||
resourceSpec := ResourceRequirementSpec{
|
||||
Limits: ResourceList{
|
||||
"cpu": cpuLimit,
|
||||
"memory": memoryLimit,
|
||||
"kube.io/storage": memoryLimit,
|
||||
},
|
||||
}
|
||||
if res := resourceSpec.Limits.Cpu(); *res != cpuLimit {
|
||||
t.Errorf("expected cpulimit %d, got %d", cpuLimit, res)
|
||||
}
|
||||
if res := resourceSpec.Limits.Memory(); *res != memoryLimit {
|
||||
t.Errorf("expected memorylimit %d, got %d", memoryLimit, res)
|
||||
}
|
||||
resourceSpec = ResourceRequirementSpec{
|
||||
Limits: ResourceList{
|
||||
"memory": memoryLimit,
|
||||
"kube.io/storage": memoryLimit,
|
||||
},
|
||||
}
|
||||
if res := resourceSpec.Limits.Cpu(); res.Value() != 0 {
|
||||
t.Errorf("expected cpulimit %d, got %d", 0, res)
|
||||
}
|
||||
if res := resourceSpec.Limits.Memory(); *res != memoryLimit {
|
||||
t.Errorf("expected memorylimit %d, got %d", memoryLimit, res)
|
||||
}
|
||||
}
|
@ -304,6 +304,12 @@ type Capabilities struct {
|
||||
Drop []CapabilityType `json:"drop,omitempty"`
|
||||
}
|
||||
|
||||
// ResourceRequirementSpec describes the compute resource requirements.
|
||||
type ResourceRequirementSpec struct {
|
||||
// Limits describes the maximum amount of compute resources required.
|
||||
Limits ResourceList `json:"limits,omitempty"`
|
||||
}
|
||||
|
||||
// Container represents a single container that is expected to be run on the host.
|
||||
type Container struct {
|
||||
// Required: This must be a DNS_LABEL. Each container in a pod must
|
||||
@ -317,13 +323,11 @@ type Container struct {
|
||||
WorkingDir string `json:"workingDir,omitempty"`
|
||||
Ports []Port `json:"ports,omitempty"`
|
||||
Env []EnvVar `json:"env,omitempty"`
|
||||
// Optional: Defaults to unlimited.
|
||||
Memory resource.Quantity `json:"memory,omitempty"`
|
||||
// Optional: Defaults to unlimited.
|
||||
CPU resource.Quantity `json:"cpu,omitempty"`
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||
LivenessProbe *Probe `json:"livenessProbe,omitempty"`
|
||||
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
||||
// Compute resource requirements.
|
||||
Resources ResourceRequirementSpec `json:"resources,omitempty"`
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||
LivenessProbe *Probe `json:"livenessProbe,omitempty"`
|
||||
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
||||
// Optional: Defaults to /dev/termination-log
|
||||
TerminationMessagePath string `json:"terminationMessagePath,omitempty"`
|
||||
// Optional: Default to false.
|
||||
@ -775,8 +779,6 @@ type NodeResources struct {
|
||||
type ResourceName string
|
||||
|
||||
const (
|
||||
// The default compute resource namespace for all standard resource types.
|
||||
DefaultResourceNamespace = "kubernetes.io"
|
||||
// CPU, in cores. (500m = .5 cores)
|
||||
ResourceCPU ResourceName = "cpu"
|
||||
// Memory, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
|
||||
|
@ -444,7 +444,140 @@ func init() {
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
||||
// Converts internal Container to v1beta1.Container.
|
||||
// Fields 'CPU' and 'Memory' are not present in the internal Container object.
|
||||
// Hence the need for a custom conversion function.
|
||||
func(in *newer.Container, out *Container, s conversion.Scope) error {
|
||||
if err := s.Convert(&in.Name, &out.Name, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Command, &out.Command, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.WorkingDir, &out.WorkingDir, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Ports, &out.Ports, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Env, &out.Env, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(in.Resources.Limits.Cpu(), &out.CPU, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(in.Resources.Limits.Memory(), &out.Memory, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.VolumeMounts, &out.VolumeMounts, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Privileged, &out.Privileged, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
// Internal API does not support CPU to be specified via an explicit field.
|
||||
// Hence it must be stored in Container.Resources.
|
||||
func(in *int, out *newer.ResourceList, s conversion.Scope) error {
|
||||
if *in <= 0 {
|
||||
return nil
|
||||
}
|
||||
quantity := resource.Quantity{}
|
||||
if err := s.Convert(in, &quantity, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[newer.ResourceCPU] = quantity
|
||||
return nil
|
||||
},
|
||||
// Internal API does not support Memory to be specified via an explicit field.
|
||||
// Hence it must be stored in Container.Resources.
|
||||
func(in *int64, out *newer.ResourceList, s conversion.Scope) error {
|
||||
if *in <= 0 {
|
||||
return nil
|
||||
}
|
||||
quantity := resource.Quantity{}
|
||||
if err := s.Convert(in, &quantity, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[newer.ResourceMemory] = quantity
|
||||
return nil
|
||||
},
|
||||
// Converts v1beta1.Container to internal Container.
|
||||
// Fields 'CPU' and 'Memory' are not present in the internal Container object.
|
||||
// Hence the need for a custom conversion function.
|
||||
func(in *Container, out *newer.Container, s conversion.Scope) error {
|
||||
if err := s.Convert(&in.Name, &out.Name, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Command, &out.Command, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.WorkingDir, &out.WorkingDir, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Ports, &out.Ports, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Env, &out.Env, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.CPU, &out.Resources.Limits, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Memory, &out.Resources.Limits, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.VolumeMounts, &out.VolumeMounts, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Privileged, &out.Privileged, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func(in *newer.PodSpec, out *ContainerManifest, s conversion.Scope) error {
|
||||
if err := s.Convert(&in.Volumes, &out.Volumes, 0); err != nil {
|
||||
return err
|
||||
|
@ -22,7 +22,9 @@ import (
|
||||
"testing"
|
||||
|
||||
newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
current "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
var Convert = newer.Scheme.Convert
|
||||
@ -316,3 +318,67 @@ func TestPullPolicyConversion(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getResourceRequirements(cpu, memory resource.Quantity) current.ResourceRequirementSpec {
|
||||
res := current.ResourceRequirementSpec{}
|
||||
res.Limits = current.ResourceList{}
|
||||
if cpu.Value() > 0 {
|
||||
res.Limits[current.ResourceCPU] = util.NewIntOrStringFromInt(int(cpu.Value()))
|
||||
}
|
||||
if memory.Value() > 0 {
|
||||
res.Limits[current.ResourceMemory] = util.NewIntOrStringFromInt(int(memory.Value()))
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func TestContainerConversion(t *testing.T) {
|
||||
cpuLimit := resource.MustParse("10")
|
||||
memoryLimit := resource.MustParse("10M")
|
||||
null := resource.Quantity{}
|
||||
testCases := []current.Container{
|
||||
{
|
||||
Name: "container",
|
||||
Resources: getResourceRequirements(cpuLimit, memoryLimit),
|
||||
},
|
||||
{
|
||||
Name: "container",
|
||||
CPU: int(cpuLimit.MilliValue()),
|
||||
Resources: getResourceRequirements(null, memoryLimit),
|
||||
},
|
||||
{
|
||||
Name: "container",
|
||||
Memory: memoryLimit.Value(),
|
||||
Resources: getResourceRequirements(cpuLimit, null),
|
||||
},
|
||||
{
|
||||
Name: "container",
|
||||
CPU: int(cpuLimit.MilliValue()),
|
||||
Memory: memoryLimit.Value(),
|
||||
},
|
||||
{
|
||||
Name: "container",
|
||||
Memory: memoryLimit.Value(),
|
||||
Resources: getResourceRequirements(cpuLimit, resource.MustParse("100M")),
|
||||
},
|
||||
{
|
||||
Name: "container",
|
||||
CPU: int(cpuLimit.MilliValue()),
|
||||
Resources: getResourceRequirements(resource.MustParse("500"), memoryLimit),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
got := newer.Container{}
|
||||
if err := Convert(&tc, &got); err != nil {
|
||||
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if cpu := got.Resources.Limits.Cpu(); cpu.Value() != cpuLimit.Value() {
|
||||
t.Errorf("[Case: %d] Expected cpu: %v, got: %v", i, cpuLimit, *cpu)
|
||||
}
|
||||
if memory := got.Resources.Limits.Memory(); memory.Value() != memoryLimit.Value() {
|
||||
t.Errorf("[Case: %d] Expected memory: %v, got: %v", i, memoryLimit, *memory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -252,6 +252,11 @@ type Capabilities struct {
|
||||
Drop []CapabilityType `json:"drop,omitempty" description:"droped capabilities"`
|
||||
}
|
||||
|
||||
type ResourceRequirementSpec struct {
|
||||
// Limits describes the maximum amount of compute resources required.
|
||||
Limits ResourceList `json:"limits,omitempty" description:"Maximum amount of compute resources allowed"`
|
||||
}
|
||||
|
||||
// Container represents a single container that is expected to be run on the host.
|
||||
type Container struct {
|
||||
// Required: This must be a DNS_LABEL. Each container in a pod must
|
||||
@ -262,13 +267,14 @@ type Container struct {
|
||||
// Optional: Defaults to whatever is defined in the image.
|
||||
Command []string `json:"command,omitempty" description:"command argv array; not executed within a shell; defaults to entrypoint or command in the image"`
|
||||
// Optional: Defaults to Docker's default.
|
||||
WorkingDir string `json:"workingDir,omitempty" description:"container's working directory; defaults to image's default"`
|
||||
Ports []Port `json:"ports,omitempty" description:"list of ports to expose from the container"`
|
||||
Env []EnvVar `json:"env,omitempty" description:"list of environment variables to set in the container"`
|
||||
WorkingDir string `json:"workingDir,omitempty" description:"container's working directory; defaults to image's default"`
|
||||
Ports []Port `json:"ports,omitempty" description:"list of ports to expose from the container"`
|
||||
Env []EnvVar `json:"env,omitempty" description:"list of environment variables to set in the container"`
|
||||
Resources ResourceRequirementSpec `json:"resources,omitempty" description:"Compute Resources required by this container"`
|
||||
// Optional: Defaults to unlimited.
|
||||
Memory int64 `json:"memory,omitempty" description:"memory limit in bytes; defaults to unlimited"`
|
||||
CPU int `json:"cpu,omitempty" description:"CPU share in thousandths of a core"`
|
||||
// Optional: Defaults to unlimited.
|
||||
CPU int `json:"cpu,omitempty" description:"CPU share in thousandths of a core"`
|
||||
Memory int64 `json:"memory,omitempty" description:"memory limit in bytes; defaults to unlimited"`
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" description:"pod volumes to mount into the container's filesystem"`
|
||||
LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty" description:"periodic probe of container liveness; container will be restarted if the probe fails"`
|
||||
Lifecycle *Lifecycle `json:"lifecycle,omitempty" description:"actions that the management system should take in response to container lifecycle events"`
|
||||
|
@ -295,7 +295,143 @@ func init() {
|
||||
}
|
||||
return nil
|
||||
},
|
||||
// Converts internal Container to v1beta1.Container.
|
||||
// Fields 'CPU' and 'Memory' are not present in the internal Container object.
|
||||
// Hence the need for a custom conversion function.
|
||||
func(in *newer.Container, out *Container, s conversion.Scope) error {
|
||||
if err := s.Convert(&in.Name, &out.Name, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Command, &out.Command, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.WorkingDir, &out.WorkingDir, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.Convert(&in.Ports, &out.Ports, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Env, &out.Env, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(in.Resources.Limits.Cpu(), &out.CPU, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(in.Resources.Limits.Memory(), &out.Memory, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.VolumeMounts, &out.VolumeMounts, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Privileged, &out.Privileged, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
// Internal API does not support CPU to be specified via an explicit field.
|
||||
// Hence it must be stored in Container.Resources.
|
||||
func(in *int, out *newer.ResourceList, s conversion.Scope) error {
|
||||
if *in == 0 {
|
||||
return nil
|
||||
}
|
||||
quantity := resource.Quantity{}
|
||||
if err := s.Convert(in, &quantity, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[newer.ResourceCPU] = quantity
|
||||
|
||||
return nil
|
||||
},
|
||||
// Internal API does not support Memory to be specified via an explicit field.
|
||||
// Hence it must be stored in Container.Resources.
|
||||
func(in *int64, out *newer.ResourceList, s conversion.Scope) error {
|
||||
if *in == 0 {
|
||||
return nil
|
||||
}
|
||||
quantity := resource.Quantity{}
|
||||
if err := s.Convert(in, &quantity, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[newer.ResourceMemory] = quantity
|
||||
|
||||
return nil
|
||||
},
|
||||
// Converts v1beta1.Container to internal newer.Container.
|
||||
// Fields 'CPU' and 'Memory' are not present in the internal newer.Container object.
|
||||
// Hence the need for a custom conversion function.
|
||||
func(in *Container, out *newer.Container, s conversion.Scope) error {
|
||||
if err := s.Convert(&in.Name, &out.Name, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Command, &out.Command, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.WorkingDir, &out.WorkingDir, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Ports, &out.Ports, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Env, &out.Env, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.CPU, &out.Resources.Limits, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Memory, &out.Resources.Limits, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.VolumeMounts, &out.VolumeMounts, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Privileged, &out.Privileged, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func(in *newer.PodSpec, out *ContainerManifest, s conversion.Scope) error {
|
||||
if err := s.Convert(&in.Volumes, &out.Volumes, 0); err != nil {
|
||||
return err
|
||||
|
@ -21,7 +21,9 @@ import (
|
||||
"testing"
|
||||
|
||||
newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
current "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
func TestServiceEmptySelector(t *testing.T) {
|
||||
@ -146,3 +148,67 @@ func TestPullPolicyConversion(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getResourceRequirements(cpu, memory resource.Quantity) current.ResourceRequirementSpec {
|
||||
res := current.ResourceRequirementSpec{}
|
||||
res.Limits = current.ResourceList{}
|
||||
if cpu.Value() > 0 {
|
||||
res.Limits[current.ResourceCPU] = util.NewIntOrStringFromInt(int(cpu.Value()))
|
||||
}
|
||||
if memory.Value() > 0 {
|
||||
res.Limits[current.ResourceMemory] = util.NewIntOrStringFromInt(int(memory.Value()))
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func TestContainerConversion(t *testing.T) {
|
||||
cpuLimit := resource.MustParse("10")
|
||||
memoryLimit := resource.MustParse("10M")
|
||||
null := resource.Quantity{}
|
||||
testCases := []current.Container{
|
||||
{
|
||||
Name: "container",
|
||||
Resources: getResourceRequirements(cpuLimit, memoryLimit),
|
||||
},
|
||||
{
|
||||
Name: "container",
|
||||
CPU: int(cpuLimit.MilliValue()),
|
||||
Resources: getResourceRequirements(null, memoryLimit),
|
||||
},
|
||||
{
|
||||
Name: "container",
|
||||
Memory: memoryLimit.Value(),
|
||||
Resources: getResourceRequirements(cpuLimit, null),
|
||||
},
|
||||
{
|
||||
Name: "container",
|
||||
CPU: int(cpuLimit.MilliValue()),
|
||||
Memory: memoryLimit.Value(),
|
||||
},
|
||||
{
|
||||
Name: "container",
|
||||
Memory: memoryLimit.Value(),
|
||||
Resources: getResourceRequirements(cpuLimit, resource.MustParse("100M")),
|
||||
},
|
||||
{
|
||||
Name: "container",
|
||||
CPU: int(cpuLimit.MilliValue()),
|
||||
Resources: getResourceRequirements(resource.MustParse("500"), memoryLimit),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
got := newer.Container{}
|
||||
if err := newer.Scheme.Convert(&tc, &got); err != nil {
|
||||
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if cpu := got.Resources.Limits.Cpu(); cpu.Value() != cpuLimit.Value() {
|
||||
t.Errorf("[Case: %d] Expected cpu: %v, got: %v", i, cpuLimit, *cpu)
|
||||
}
|
||||
if memory := got.Resources.Limits.Memory(); memory.Value() != memoryLimit.Value() {
|
||||
t.Errorf("[Case: %d] Expected memory: %v, got: %v", i, memoryLimit, *memory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -216,6 +216,11 @@ type Capabilities struct {
|
||||
Drop []CapabilityType `json:"drop,omitempty" description:"droped capabilities"`
|
||||
}
|
||||
|
||||
type ResourceRequirementSpec struct {
|
||||
// Limits describes the maximum amount of compute resources required.
|
||||
Limits ResourceList `json:"limits,omitempty" description:"Maximum amount of compute resources allowed"`
|
||||
}
|
||||
|
||||
// Container represents a single container that is expected to be run on the host.
|
||||
type Container struct {
|
||||
// Required: This must be a DNS_LABEL. Each container in a pod must
|
||||
@ -226,13 +231,14 @@ type Container struct {
|
||||
// Optional: Defaults to whatever is defined in the image.
|
||||
Command []string `json:"command,omitempty" description:"command argv array; not executed within a shell; defaults to entrypoint or command in the image"`
|
||||
// Optional: Defaults to Docker's default.
|
||||
WorkingDir string `json:"workingDir,omitempty" description:"container's working directory; defaults to image's default"`
|
||||
Ports []Port `json:"ports,omitempty" description:"list of ports to expose from the container"`
|
||||
Env []EnvVar `json:"env,omitempty" description:"list of environment variables to set in the container"`
|
||||
WorkingDir string `json:"workingDir,omitempty" description:"container's working directory; defaults to image's default"`
|
||||
Ports []Port `json:"ports,omitempty" description:"list of ports to expose from the container"`
|
||||
Env []EnvVar `json:"env,omitempty" description:"list of environment variables to set in the container"`
|
||||
Resources ResourceRequirementSpec `json:"resources,omitempty" description:"Compute Resources required by this container"`
|
||||
// Optional: Defaults to unlimited.
|
||||
Memory int64 `json:"memory,omitempty" description:"memory limit in bytes; defaults to unlimited"`
|
||||
CPU int `json:"cpu,omitempty" description:"CPU share in thousandths of a core"`
|
||||
// Optional: Defaults to unlimited.
|
||||
CPU int `json:"cpu,omitempty" description:"CPU share in thousandths of a core"`
|
||||
Memory int64 `json:"memory,omitempty" description:"memory limit in bytes; defaults to unlimited"`
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" description:"pod volumes to mount into the container's filesystem"`
|
||||
LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty" description:"periodic probe of container liveness; container will be restarted if the probe fails"`
|
||||
Lifecycle *Lifecycle `json:"lifecycle,omitempty" description:"actions that the management system should take in response to container lifecycle events"`
|
||||
|
@ -322,6 +322,12 @@ type Capabilities struct {
|
||||
Drop []CapabilityType `json:"drop,omitempty"`
|
||||
}
|
||||
|
||||
// ResourceRequirementSpec describes the compute resource requirements.
|
||||
type ResourceRequirementSpec struct {
|
||||
// Limits describes the maximum amount of compute resources required.
|
||||
Limits ResourceList `json:"limits,omitempty" description:"Maximum amount of compute resources allowed"`
|
||||
}
|
||||
|
||||
// Container represents a single container that is expected to be run on the host.
|
||||
type Container struct {
|
||||
// Required: This must be a DNS_LABEL. Each container in a pod must
|
||||
@ -332,16 +338,13 @@ type Container struct {
|
||||
// Optional: Defaults to whatever is defined in the image.
|
||||
Command []string `json:"command,omitempty"`
|
||||
// Optional: Defaults to Docker's default.
|
||||
WorkingDir string `json:"workingDir,omitempty"`
|
||||
Ports []Port `json:"ports,omitempty"`
|
||||
Env []EnvVar `json:"env,omitempty"`
|
||||
// Optional: Defaults to unlimited. Units: bytes.
|
||||
Memory resource.Quantity `json:"memory,omitempty"`
|
||||
// Optional: Defaults to unlimited. Units: Cores. (500m == 1/2 core)
|
||||
CPU resource.Quantity `json:"cpu,omitempty"`
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||
LivenessProbe *Probe `json:"livenessProbe,omitempty"`
|
||||
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
||||
WorkingDir string `json:"workingDir,omitempty"`
|
||||
Ports []Port `json:"ports,omitempty"`
|
||||
Env []EnvVar `json:"env,omitempty"`
|
||||
Resources ResourceRequirementSpec `json:"resources,omitempty" description:"Compute Resources required by this container"`
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||
LivenessProbe *Probe `json:"livenessProbe,omitempty"`
|
||||
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
||||
// Optional: Defaults to /dev/termination-log
|
||||
TerminationMessagePath string `json:"terminationMessagePath,omitempty"`
|
||||
// Optional: Default to false.
|
||||
@ -796,8 +799,6 @@ type NodeCondition struct {
|
||||
type ResourceName string
|
||||
|
||||
const (
|
||||
// The default compute resource namespace for all standard resource types.
|
||||
DefaultResourceNamespace = "kubernetes.io"
|
||||
// CPU, in cores. (500m = .5 cores)
|
||||
ResourceCPU ResourceName = "cpu"
|
||||
// Memory, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
errs "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/capabilities"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
@ -395,6 +396,7 @@ func validateContainers(containers []api.Container, volumes util.StringSet) errs
|
||||
cErrs = append(cErrs, validateEnv(ctr.Env).Prefix("env")...)
|
||||
cErrs = append(cErrs, validateVolumeMounts(ctr.VolumeMounts, volumes).Prefix("volumeMounts")...)
|
||||
cErrs = append(cErrs, validatePullPolicyWithDefault(ctr).Prefix("pullPolicy")...)
|
||||
cErrs = append(cErrs, validateResourceRequirements(ctr).Prefix("resources")...)
|
||||
allErrs = append(allErrs, cErrs.PrefixIndex(i)...)
|
||||
}
|
||||
// Check for colliding ports across all containers.
|
||||
@ -696,28 +698,17 @@ func ValidateMinionUpdate(oldMinion *api.Node, minion *api.Node) errs.Validation
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// Typename is a generic representation for all compute resource typenames.
|
||||
// Validate compute resource typename.
|
||||
// Refer to docs/resources.md for more details.
|
||||
func ValidateResourceName(str string) errs.ValidationErrorList {
|
||||
func validateResourceName(str string) errs.ValidationErrorList {
|
||||
if !util.IsQualifiedName(str) {
|
||||
return errs.ValidationErrorList{fmt.Errorf("invalid compute resource typename format %q", str)}
|
||||
}
|
||||
|
||||
parts := strings.Split(str, "/")
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
if !api.IsStandardResourceName(parts[0]) {
|
||||
if len(strings.Split(str, "/")) == 1 {
|
||||
if !api.IsStandardResourceName(str) {
|
||||
return errs.ValidationErrorList{fmt.Errorf("invalid compute resource typename. %q is neither a standard resource type nor is fully qualified", str)}
|
||||
}
|
||||
break
|
||||
case 2:
|
||||
if parts[0] == api.DefaultResourceNamespace {
|
||||
if !api.IsStandardResourceName(parts[1]) {
|
||||
return errs.ValidationErrorList{fmt.Errorf("invalid compute resource typename. %q contains a compute resource type not supported", str)}
|
||||
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return errs.ValidationErrorList{}
|
||||
@ -740,15 +731,37 @@ func ValidateLimitRange(limitRange *api.LimitRange) errs.ValidationErrorList {
|
||||
for i := range limitRange.Spec.Limits {
|
||||
limit := limitRange.Spec.Limits[i]
|
||||
for k := range limit.Max {
|
||||
allErrs = append(allErrs, ValidateResourceName(string(k))...)
|
||||
allErrs = append(allErrs, validateResourceName(string(k))...)
|
||||
}
|
||||
for k := range limit.Min {
|
||||
allErrs = append(allErrs, ValidateResourceName(string(k))...)
|
||||
allErrs = append(allErrs, validateResourceName(string(k))...)
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateBasicResource(quantity resource.Quantity) errs.ValidationErrorList {
|
||||
if quantity.Value() < 0 {
|
||||
return errs.ValidationErrorList{fmt.Errorf("%v is not a valid resource quantity", quantity.Value())}
|
||||
}
|
||||
return errs.ValidationErrorList{}
|
||||
}
|
||||
|
||||
// Validates resource requirement spec.
|
||||
func validateResourceRequirements(container *api.Container) errs.ValidationErrorList {
|
||||
allErrs := errs.ValidationErrorList{}
|
||||
for resourceName, quantity := range container.Resources.Limits {
|
||||
// Validate resource name.
|
||||
errs := validateResourceName(resourceName.String())
|
||||
if api.IsStandardResourceName(resourceName.String()) {
|
||||
errs = append(errs, validateBasicResource(quantity).Prefix(fmt.Sprintf("Resource %s: ", resourceName))...)
|
||||
}
|
||||
allErrs = append(allErrs, errs...)
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateResourceQuota tests if required fields in the ResourceQuota are set.
|
||||
func ValidateResourceQuota(resourceQuota *api.ResourceQuota) errs.ValidationErrorList {
|
||||
allErrs := errs.ValidationErrorList{}
|
||||
@ -763,13 +776,13 @@ func ValidateResourceQuota(resourceQuota *api.ResourceQuota) errs.ValidationErro
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("namespace", resourceQuota.Namespace, ""))
|
||||
}
|
||||
for k := range resourceQuota.Spec.Hard {
|
||||
allErrs = append(allErrs, ValidateResourceName(string(k))...)
|
||||
allErrs = append(allErrs, validateResourceName(string(k))...)
|
||||
}
|
||||
for k := range resourceQuota.Status.Hard {
|
||||
allErrs = append(allErrs, ValidateResourceName(string(k))...)
|
||||
allErrs = append(allErrs, validateResourceName(string(k))...)
|
||||
}
|
||||
for k := range resourceQuota.Status.Used {
|
||||
allErrs = append(allErrs, ValidateResourceName(string(k))...)
|
||||
allErrs = append(allErrs, validateResourceName(string(k))...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
@ -268,6 +268,13 @@ func TestValidatePullPolicy(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func getResourceLimits(cpu, memory string) api.ResourceList {
|
||||
res := api.ResourceList{}
|
||||
res[api.ResourceCPU] = resource.MustParse(cpu)
|
||||
res[api.ResourceMemory] = resource.MustParse(memory)
|
||||
return res
|
||||
}
|
||||
|
||||
func TestValidateContainers(t *testing.T) {
|
||||
volumes := util.StringSet{}
|
||||
capabilities.SetForTests(capabilities.Capabilities{
|
||||
@ -287,6 +294,17 @@ func TestValidateContainers(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "resources-test",
|
||||
Image: "image",
|
||||
Resources: api.ResourceRequirementSpec{
|
||||
Limits: api.ResourceList{
|
||||
api.ResourceName(api.ResourceCPU): resource.MustParse("10"),
|
||||
api.ResourceName(api.ResourceMemory): resource.MustParse("10G"),
|
||||
api.ResourceName("my.org/resource"): resource.MustParse("10m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "abc-1234", Image: "image", Privileged: true},
|
||||
}
|
||||
if errs := validateContainers(successCase, volumes); len(errs) != 0 {
|
||||
@ -349,6 +367,35 @@ func TestValidateContainers(t *testing.T) {
|
||||
"privilege disabled": {
|
||||
{Name: "abc", Image: "image", Privileged: true},
|
||||
},
|
||||
"invalid compute resource": {
|
||||
{
|
||||
Name: "abc-123",
|
||||
Image: "image",
|
||||
Resources: api.ResourceRequirementSpec{
|
||||
Limits: api.ResourceList{
|
||||
"disk": resource.MustParse("10G"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"Resource CPU invalid": {
|
||||
{
|
||||
Name: "abc-123",
|
||||
Image: "image",
|
||||
Resources: api.ResourceRequirementSpec{
|
||||
Limits: getResourceLimits("-10", "0"),
|
||||
},
|
||||
},
|
||||
},
|
||||
"Resource Memory invalid": {
|
||||
{
|
||||
Name: "abc-123",
|
||||
Image: "image",
|
||||
Resources: api.ResourceRequirementSpec{
|
||||
Limits: getResourceLimits("0", "-10"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
if errs := validateContainers(v, volumes); len(errs) == 0 {
|
||||
@ -422,8 +469,12 @@ func TestValidateManifest(t *testing.T) {
|
||||
Image: "image",
|
||||
Command: []string{"foo", "bar"},
|
||||
WorkingDir: "/tmp",
|
||||
Memory: resource.MustParse("1"),
|
||||
CPU: resource.MustParse("1"),
|
||||
Resources: api.ResourceRequirementSpec{
|
||||
Limits: api.ResourceList{
|
||||
"cpu": resource.MustParse("1"),
|
||||
"memory": resource.MustParse("1"),
|
||||
},
|
||||
},
|
||||
Ports: []api.Port{
|
||||
{Name: "p1", ContainerPort: 80, HostPort: 8080},
|
||||
{Name: "p2", ContainerPort: 81},
|
||||
@ -711,7 +762,9 @@ func TestValidatePodUpdate(t *testing.T) {
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "foo:V1",
|
||||
CPU: resource.MustParse("100m"),
|
||||
Resources: api.ResourceRequirementSpec{
|
||||
Limits: getResourceLimits("100m", "0"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -722,7 +775,9 @@ func TestValidatePodUpdate(t *testing.T) {
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "foo:V2",
|
||||
CPU: resource.MustParse("1000m"),
|
||||
Resources: api.ResourceRequirementSpec{
|
||||
Limits: getResourceLimits("1000m", "0"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1675,8 +1730,6 @@ func TestValidateResourceNames(t *testing.T) {
|
||||
{"", false},
|
||||
{".", false},
|
||||
{"..", false},
|
||||
{"kubernetes.io/cpu", true},
|
||||
{"kubernetes.io/disk", false},
|
||||
{"my.favorite.app.co/12345", true},
|
||||
{"my.favorite.app.co/_12345", false},
|
||||
{"my.favorite.app.co/12345_", false},
|
||||
@ -1687,7 +1740,7 @@ func TestValidateResourceNames(t *testing.T) {
|
||||
{"kubernetes.io/will/not/work/", false},
|
||||
}
|
||||
for _, item := range table {
|
||||
err := ValidateResourceName(item.input)
|
||||
err := validateResourceName(item.input)
|
||||
if len(err) != 0 && item.success {
|
||||
t.Errorf("expected no failure for input %q", item.input)
|
||||
} else if len(err) == 0 && !item.success {
|
||||
|
@ -649,8 +649,8 @@ func (kl *Kubelet) runContainer(pod *api.BoundPod, container *api.Container, pod
|
||||
ExposedPorts: exposedPorts,
|
||||
Hostname: pod.Name,
|
||||
Image: container.Image,
|
||||
Memory: container.Memory.Value(),
|
||||
CPUShares: milliCPUToShares(container.CPU.MilliValue()),
|
||||
Memory: container.Resources.Limits.Memory().Value(),
|
||||
CPUShares: milliCPUToShares(container.Resources.Limits.Cpu().MilliValue()),
|
||||
WorkingDir: container.WorkingDir,
|
||||
},
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ func (rm *ResourceQuotaManager) syncResourceQuota(quota api.ResourceQuota) (err
|
||||
func PodCPU(pod *api.Pod) *resource.Quantity {
|
||||
val := int64(0)
|
||||
for j := range pod.Spec.Containers {
|
||||
val = val + pod.Spec.Containers[j].CPU.MilliValue()
|
||||
val = val + pod.Spec.Containers[j].Resources.Limits.Cpu().MilliValue()
|
||||
}
|
||||
return resource.NewMilliQuantity(int64(val), resource.DecimalSI)
|
||||
}
|
||||
@ -188,7 +188,7 @@ func PodCPU(pod *api.Pod) *resource.Quantity {
|
||||
func PodMemory(pod *api.Pod) *resource.Quantity {
|
||||
val := int64(0)
|
||||
for j := range pod.Spec.Containers {
|
||||
val = val + pod.Spec.Containers[j].Memory.Value()
|
||||
val = val + pod.Spec.Containers[j].Resources.Limits.Memory().Value()
|
||||
}
|
||||
return resource.NewQuantity(int64(val), resource.DecimalSI)
|
||||
}
|
||||
|
@ -95,8 +95,9 @@ type resourceRequest struct {
|
||||
func getResourceRequest(pod *api.Pod) resourceRequest {
|
||||
result := resourceRequest{}
|
||||
for ix := range pod.Spec.Containers {
|
||||
result.memory += pod.Spec.Containers[ix].Memory.Value()
|
||||
result.milliCPU += pod.Spec.Containers[ix].CPU.MilliValue()
|
||||
limits := pod.Spec.Containers[ix].Resources.Limits
|
||||
result.memory += limits.Memory().Value()
|
||||
result.milliCPU += limits.Cpu().MilliValue()
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -120,8 +121,8 @@ func (r *ResourceFit) PodFitsResources(pod api.Pod, existingPods []api.Pod, node
|
||||
memoryRequested += existingRequest.memory
|
||||
}
|
||||
|
||||
totalMilliCPU := info.Spec.Capacity.Get(api.ResourceCPU).MilliValue()
|
||||
totalMemory := info.Spec.Capacity.Get(api.ResourceMemory).Value()
|
||||
totalMilliCPU := info.Spec.Capacity.Cpu().MilliValue()
|
||||
totalMemory := info.Spec.Capacity.Memory().Value()
|
||||
|
||||
fitsCPU := totalMilliCPU == 0 || (totalMilliCPU-milliCPURequested) >= podRequest.milliCPU
|
||||
fitsMemory := totalMemory == 0 || (totalMemory-memoryRequested) >= podRequest.memory
|
||||
|
@ -46,8 +46,8 @@ func (nodes FakeNodeListInfo) GetNodeInfo(nodeName string) (*api.Node, error) {
|
||||
func makeResources(milliCPU int64, memory int64) api.NodeResources {
|
||||
return api.NodeResources{
|
||||
Capacity: api.ResourceList{
|
||||
api.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI),
|
||||
api.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI),
|
||||
"cpu": *resource.NewMilliQuantity(milliCPU, resource.DecimalSI),
|
||||
"memory": *resource.NewQuantity(memory, resource.BinarySI),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -56,8 +56,12 @@ func newResourcePod(usage ...resourceRequest) api.Pod {
|
||||
containers := []api.Container{}
|
||||
for _, req := range usage {
|
||||
containers = append(containers, api.Container{
|
||||
Memory: *resource.NewQuantity(req.memory, resource.BinarySI),
|
||||
CPU: *resource.NewMilliQuantity(req.milliCPU, resource.DecimalSI),
|
||||
Resources: api.ResourceRequirementSpec{
|
||||
Limits: api.ResourceList{
|
||||
"cpu": *resource.NewMilliQuantity(req.milliCPU, resource.DecimalSI),
|
||||
"memory": *resource.NewQuantity(req.memory, resource.BinarySI),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
return api.Pod{
|
||||
|
@ -42,19 +42,19 @@ func calculateOccupancy(pod api.Pod, node api.Node, pods []api.Pod) HostPriority
|
||||
totalMemory := int64(0)
|
||||
for _, existingPod := range pods {
|
||||
for _, container := range existingPod.Spec.Containers {
|
||||
totalMilliCPU += container.CPU.MilliValue()
|
||||
totalMemory += container.Memory.Value()
|
||||
totalMilliCPU += container.Resources.Limits.Cpu().MilliValue()
|
||||
totalMemory += container.Resources.Limits.Memory().Value()
|
||||
}
|
||||
}
|
||||
// Add the resources requested by the current pod being scheduled.
|
||||
// This also helps differentiate between differently sized, but empty, minions.
|
||||
for _, container := range pod.Spec.Containers {
|
||||
totalMilliCPU += container.CPU.MilliValue()
|
||||
totalMemory += container.Memory.Value()
|
||||
totalMilliCPU += container.Resources.Limits.Cpu().MilliValue()
|
||||
totalMemory += container.Resources.Limits.Memory().Value()
|
||||
}
|
||||
|
||||
capacityMilliCPU := node.Spec.Capacity.Get(api.ResourceCPU).MilliValue()
|
||||
capacityMemory := node.Spec.Capacity.Get(api.ResourceMemory).Value()
|
||||
capacityMilliCPU := node.Spec.Capacity.Cpu().MilliValue()
|
||||
capacityMemory := node.Spec.Capacity.Memory().Value()
|
||||
|
||||
cpuScore := calculateScore(totalMilliCPU, capacityMilliCPU, node.Name)
|
||||
memoryScore := calculateScore(totalMemory, capacityMemory, node.Name)
|
||||
|
@ -30,8 +30,8 @@ func makeMinion(node string, milliCPU, memory int64) api.Node {
|
||||
ObjectMeta: api.ObjectMeta{Name: node},
|
||||
Spec: api.NodeSpec{
|
||||
Capacity: api.ResourceList{
|
||||
api.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI),
|
||||
api.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI),
|
||||
"cpu": *resource.NewMilliQuantity(milliCPU, resource.DecimalSI),
|
||||
"memory": *resource.NewQuantity(memory, resource.BinarySI),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -57,14 +57,40 @@ func TestLeastRequested(t *testing.T) {
|
||||
}
|
||||
cpuOnly := api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{CPU: resource.MustParse("1000m")},
|
||||
{CPU: resource.MustParse("2000m")},
|
||||
{
|
||||
Resources: api.ResourceRequirementSpec{
|
||||
Limits: api.ResourceList{
|
||||
"cpu": resource.MustParse("1000m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Resources: api.ResourceRequirementSpec{
|
||||
Limits: api.ResourceList{
|
||||
"cpu": resource.MustParse("2000m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
cpuAndMemory := api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{CPU: resource.MustParse("1000m"), Memory: resource.MustParse("2000")},
|
||||
{CPU: resource.MustParse("2000m"), Memory: resource.MustParse("3000")},
|
||||
{
|
||||
Resources: api.ResourceRequirementSpec{
|
||||
Limits: api.ResourceList{
|
||||
"cpu": resource.MustParse("1000m"),
|
||||
"memory": resource.MustParse("2000"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Resources: api.ResourceRequirementSpec{
|
||||
Limits: api.ResourceList{
|
||||
"cpu": resource.MustParse("2000m"),
|
||||
"memory": resource.MustParse("3000"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
tests := []struct {
|
||||
|
@ -103,8 +103,8 @@ func PodLimitFunc(limitRange *api.LimitRange, kind string, obj runtime.Object) e
|
||||
|
||||
for i := range pod.Spec.Containers {
|
||||
container := pod.Spec.Containers[i]
|
||||
containerCPU := container.CPU.MilliValue()
|
||||
containerMem := container.Memory.Value()
|
||||
containerCPU := container.Resources.Limits.Cpu().MilliValue()
|
||||
containerMem := container.Resources.Limits.Memory().Value()
|
||||
|
||||
if i == 0 {
|
||||
minContainerCPU = containerCPU
|
||||
@ -113,8 +113,8 @@ func PodLimitFunc(limitRange *api.LimitRange, kind string, obj runtime.Object) e
|
||||
maxContainerMem = containerMem
|
||||
}
|
||||
|
||||
podCPU = podCPU + container.CPU.MilliValue()
|
||||
podMem = podMem + container.Memory.Value()
|
||||
podCPU = podCPU + container.Resources.Limits.Cpu().MilliValue()
|
||||
podMem = podMem + container.Resources.Limits.Memory().Value()
|
||||
|
||||
minContainerCPU = Min(containerCPU, minContainerCPU)
|
||||
minContainerMem = Min(containerMem, minContainerMem)
|
||||
|
@ -23,6 +23,19 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
)
|
||||
|
||||
func getResourceRequirements(cpu, memory string) api.ResourceRequirementSpec {
|
||||
res := api.ResourceRequirementSpec{}
|
||||
res.Limits = api.ResourceList{}
|
||||
if cpu != "" {
|
||||
res.Limits[api.ResourceCPU] = resource.MustParse(cpu)
|
||||
}
|
||||
if memory != "" {
|
||||
res.Limits[api.ResourceMemory] = resource.MustParse(memory)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func TestPodLimitFunc(t *testing.T) {
|
||||
limitRange := &api.LimitRange{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
@ -32,25 +45,13 @@ func TestPodLimitFunc(t *testing.T) {
|
||||
Limits: []api.LimitRangeItem{
|
||||
{
|
||||
Type: api.LimitTypePod,
|
||||
Max: api.ResourceList{
|
||||
api.ResourceCPU: resource.MustParse("200m"),
|
||||
api.ResourceMemory: resource.MustParse("4Gi"),
|
||||
},
|
||||
Min: api.ResourceList{
|
||||
api.ResourceCPU: resource.MustParse("50m"),
|
||||
api.ResourceMemory: resource.MustParse("2Mi"),
|
||||
},
|
||||
Max: getResourceRequirements("200m", "4Gi").Limits,
|
||||
Min: getResourceRequirements("50m", "2Mi").Limits,
|
||||
},
|
||||
{
|
||||
Type: api.LimitTypeContainer,
|
||||
Max: api.ResourceList{
|
||||
api.ResourceCPU: resource.MustParse("100m"),
|
||||
api.ResourceMemory: resource.MustParse("2Gi"),
|
||||
},
|
||||
Min: api.ResourceList{
|
||||
api.ResourceCPU: resource.MustParse("25m"),
|
||||
api.ResourceMemory: resource.MustParse("1Mi"),
|
||||
},
|
||||
Max: getResourceRequirements("100m", "2Gi").Limits,
|
||||
Min: getResourceRequirements("25m", "1Mi").Limits,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -62,14 +63,12 @@ func TestPodLimitFunc(t *testing.T) {
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "foo:V1",
|
||||
CPU: resource.MustParse("100m"),
|
||||
Memory: resource.MustParse("2Gi"),
|
||||
Image: "foo:V1",
|
||||
Resources: getResourceRequirements("100m", "2Gi"),
|
||||
},
|
||||
{
|
||||
Image: "boo:V1",
|
||||
CPU: resource.MustParse("100m"),
|
||||
Memory: resource.MustParse("2Gi"),
|
||||
Image: "boo:V1",
|
||||
Resources: getResourceRequirements("100m", "2Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -79,9 +78,8 @@ func TestPodLimitFunc(t *testing.T) {
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "boo:V1",
|
||||
CPU: resource.MustParse("100m"),
|
||||
Memory: resource.MustParse("2Gi"),
|
||||
Image: "boo:V1",
|
||||
Resources: getResourceRequirements("100m", "2Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -94,9 +92,8 @@ func TestPodLimitFunc(t *testing.T) {
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "boo:V1",
|
||||
CPU: resource.MustParse("25m"),
|
||||
Memory: resource.MustParse("2Gi"),
|
||||
Image: "boo:V1",
|
||||
Resources: getResourceRequirements("25m", "2Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -106,9 +103,8 @@ func TestPodLimitFunc(t *testing.T) {
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "boo:V1",
|
||||
CPU: resource.MustParse("110m"),
|
||||
Memory: resource.MustParse("1Gi"),
|
||||
Image: "boo:V1",
|
||||
Resources: getResourceRequirements("110m", "1Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -118,9 +114,8 @@ func TestPodLimitFunc(t *testing.T) {
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "boo:V1",
|
||||
CPU: resource.MustParse("30m"),
|
||||
Memory: resource.MustParse("0"),
|
||||
Image: "boo:V1",
|
||||
Resources: getResourceRequirements("30m", "0"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -130,9 +125,8 @@ func TestPodLimitFunc(t *testing.T) {
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "boo:V1",
|
||||
CPU: resource.MustParse("30m"),
|
||||
Memory: resource.MustParse("3Gi"),
|
||||
Image: "boo:V1",
|
||||
Resources: getResourceRequirements("30m", "3Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -142,9 +136,8 @@ func TestPodLimitFunc(t *testing.T) {
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "boo:V1",
|
||||
CPU: resource.MustParse("40m"),
|
||||
Memory: resource.MustParse("2Gi"),
|
||||
Image: "boo:V1",
|
||||
Resources: getResourceRequirements("40m", "2Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -154,24 +147,20 @@ func TestPodLimitFunc(t *testing.T) {
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "boo:V1",
|
||||
CPU: resource.MustParse("60m"),
|
||||
Memory: resource.MustParse("1Mi"),
|
||||
Image: "boo:V1",
|
||||
Resources: getResourceRequirements("60m", "1Mi"),
|
||||
},
|
||||
{
|
||||
Image: "boo:V2",
|
||||
CPU: resource.MustParse("60m"),
|
||||
Memory: resource.MustParse("1Mi"),
|
||||
Image: "boo:V2",
|
||||
Resources: getResourceRequirements("60m", "1Mi"),
|
||||
},
|
||||
{
|
||||
Image: "boo:V3",
|
||||
CPU: resource.MustParse("60m"),
|
||||
Memory: resource.MustParse("1Mi"),
|
||||
Image: "boo:V3",
|
||||
Resources: getResourceRequirements("60m", "1Mi"),
|
||||
},
|
||||
{
|
||||
Image: "boo:V4",
|
||||
CPU: resource.MustParse("60m"),
|
||||
Memory: resource.MustParse("1Mi"),
|
||||
Image: "boo:V4",
|
||||
Resources: getResourceRequirements("60m", "1Mi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -181,19 +170,16 @@ func TestPodLimitFunc(t *testing.T) {
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "boo:V1",
|
||||
CPU: resource.MustParse("60m"),
|
||||
Memory: resource.MustParse("2Gi"),
|
||||
Image: "boo:V1",
|
||||
Resources: getResourceRequirements("60m", "2Gi"),
|
||||
},
|
||||
{
|
||||
Image: "boo:V2",
|
||||
CPU: resource.MustParse("60m"),
|
||||
Memory: resource.MustParse("2Gi"),
|
||||
Image: "boo:V2",
|
||||
Resources: getResourceRequirements("60m", "2Gi"),
|
||||
},
|
||||
{
|
||||
Image: "boo:V3",
|
||||
CPU: resource.MustParse("60m"),
|
||||
Memory: resource.MustParse("2Gi"),
|
||||
Image: "boo:V3",
|
||||
Resources: getResourceRequirements("60m", "2Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -203,19 +189,16 @@ func TestPodLimitFunc(t *testing.T) {
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "boo:V1",
|
||||
CPU: resource.MustParse("60m"),
|
||||
Memory: resource.MustParse("0"),
|
||||
Image: "boo:V1",
|
||||
Resources: getResourceRequirements("60m", "0"),
|
||||
},
|
||||
{
|
||||
Image: "boo:V2",
|
||||
CPU: resource.MustParse("60m"),
|
||||
Memory: resource.MustParse("0"),
|
||||
Image: "boo:V2",
|
||||
Resources: getResourceRequirements("60m", "0"),
|
||||
},
|
||||
{
|
||||
Image: "boo:V3",
|
||||
CPU: resource.MustParse("60m"),
|
||||
Memory: resource.MustParse("0"),
|
||||
Image: "boo:V3",
|
||||
Resources: getResourceRequirements("60m", "0"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -55,11 +55,12 @@ func (resourceDefaults) Admit(a admission.Attributes) (err error) {
|
||||
obj := a.GetObject()
|
||||
pod := obj.(*api.Pod)
|
||||
for index := range pod.Spec.Containers {
|
||||
if pod.Spec.Containers[index].Memory.Value() == 0 {
|
||||
pod.Spec.Containers[index].Memory = resource.MustParse(defaultMemory)
|
||||
pod.Spec.Containers[index].Resources.Limits = api.ResourceList{}
|
||||
if pod.Spec.Containers[index].Resources.Limits.Memory().Value() == 0 {
|
||||
pod.Spec.Containers[index].Resources.Limits[api.ResourceMemory] = resource.MustParse(defaultMemory)
|
||||
}
|
||||
if pod.Spec.Containers[index].CPU.Value() == 0 {
|
||||
pod.Spec.Containers[index].CPU = resource.MustParse(defaultCPU)
|
||||
if pod.Spec.Containers[index].Resources.Limits.Cpu().Value() == 0 {
|
||||
pod.Spec.Containers[index].Resources.Limits[api.ResourceCPU] = resource.MustParse(defaultCPU)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -41,11 +41,13 @@ func TestAdmission(t *testing.T) {
|
||||
}
|
||||
|
||||
for i := range pod.Spec.Containers {
|
||||
if pod.Spec.Containers[i].Memory.String() != "512Mi" {
|
||||
t.Errorf("Unexpected memory value %s", pod.Spec.Containers[i].Memory.String())
|
||||
memory := pod.Spec.Containers[i].Resources.Limits.Memory().String()
|
||||
cpu := pod.Spec.Containers[i].Resources.Limits.Cpu().String()
|
||||
if memory != "512Mi" {
|
||||
t.Errorf("Unexpected memory value %s", memory)
|
||||
}
|
||||
if pod.Spec.Containers[i].CPU.String() != "1" {
|
||||
t.Errorf("Unexpected cpu value %s", pod.Spec.Containers[i].CPU.String())
|
||||
if cpu != "1" {
|
||||
t.Errorf("Unexpected cpu value %s", cpu)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,19 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
)
|
||||
|
||||
func getResourceRequirements(cpu, memory string) api.ResourceRequirementSpec {
|
||||
res := api.ResourceRequirementSpec{}
|
||||
res.Limits = api.ResourceList{}
|
||||
if cpu != "" {
|
||||
res.Limits[api.ResourceCPU] = resource.MustParse(cpu)
|
||||
}
|
||||
if memory != "" {
|
||||
res.Limits[api.ResourceMemory] = resource.MustParse(memory)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func TestAdmissionIgnoresDelete(t *testing.T) {
|
||||
namespace := "default"
|
||||
handler := NewResourceQuota(&client.Fake{})
|
||||
@ -43,7 +56,7 @@ func TestIncrementUsagePods(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{{Name: "vol"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Memory: resource.MustParse("1Gi"), CPU: resource.MustParse("100m")}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "1Gi")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -78,7 +91,7 @@ func TestIncrementUsageMemory(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{{Name: "vol"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Memory: resource.MustParse("1Gi"), CPU: resource.MustParse("100m")}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "1Gi")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -96,7 +109,7 @@ func TestIncrementUsageMemory(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{{Name: "vol"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Memory: resource.MustParse("1Gi"), CPU: resource.MustParse("100m")}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "1Gi")}},
|
||||
}}
|
||||
dirty, err := IncrementUsage(admission.NewAttributesRecord(newPod, namespace, "pods", "CREATE"), status, client)
|
||||
if err != nil {
|
||||
@ -121,7 +134,7 @@ func TestExceedUsageMemory(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{{Name: "vol"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Memory: resource.MustParse("1Gi"), CPU: resource.MustParse("100m")}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "1Gi")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -139,7 +152,7 @@ func TestExceedUsageMemory(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{{Name: "vol"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Memory: resource.MustParse("3Gi"), CPU: resource.MustParse("100m")}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "3Gi")}},
|
||||
}}
|
||||
_, err := IncrementUsage(admission.NewAttributesRecord(newPod, namespace, "pods", "CREATE"), status, client)
|
||||
if err == nil {
|
||||
@ -156,7 +169,7 @@ func TestIncrementUsageCPU(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{{Name: "vol"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Memory: resource.MustParse("1Gi"), CPU: resource.MustParse("100m")}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "1Gi")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -174,7 +187,7 @@ func TestIncrementUsageCPU(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{{Name: "vol"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Memory: resource.MustParse("1Gi"), CPU: resource.MustParse("100m")}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "1Gi")}},
|
||||
}}
|
||||
dirty, err := IncrementUsage(admission.NewAttributesRecord(newPod, namespace, "pods", "CREATE"), status, client)
|
||||
if err != nil {
|
||||
@ -199,7 +212,7 @@ func TestExceedUsageCPU(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{{Name: "vol"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Memory: resource.MustParse("1Gi"), CPU: resource.MustParse("100m")}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "1Gi")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -217,7 +230,7 @@ func TestExceedUsageCPU(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{{Name: "vol"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Memory: resource.MustParse("1Gi"), CPU: resource.MustParse("500m")}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("500m", "1Gi")}},
|
||||
}}
|
||||
_, err := IncrementUsage(admission.NewAttributesRecord(newPod, namespace, "pods", "CREATE"), status, client)
|
||||
if err == nil {
|
||||
@ -234,7 +247,7 @@ func TestExceedUsagePods(t *testing.T) {
|
||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{{Name: "vol"}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Memory: resource.MustParse("1Gi"), CPU: resource.MustParse("100m")}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", Resources: getResourceRequirements("100m", "1Gi")}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user