Put quantity into packages

kubelet, GCE, validation, client
This commit is contained in:
Daniel Smith
2015-01-05 13:16:18 -08:00
parent 40d29f4f08
commit 7f49ba0dcf
8 changed files with 71 additions and 70 deletions

View File

@@ -22,6 +22,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "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/capabilities"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
@@ -372,8 +373,8 @@ func TestValidateManifest(t *testing.T) {
Image: "image", Image: "image",
Command: []string{"foo", "bar"}, Command: []string{"foo", "bar"},
WorkingDir: "/tmp", WorkingDir: "/tmp",
Memory: 1, Memory: *resource.Q("1"),
CPU: 1, CPU: *resource.Q("1"),
Ports: []api.Port{ Ports: []api.Port{
{Name: "p1", ContainerPort: 80, HostPort: 8080}, {Name: "p1", ContainerPort: 80, HostPort: 8080},
{Name: "p2", ContainerPort: 81}, {Name: "p2", ContainerPort: 81},
@@ -623,7 +624,7 @@ func TestValidatePodUpdate(t *testing.T) {
Containers: []api.Container{ Containers: []api.Container{
{ {
Image: "foo:V1", Image: "foo:V1",
CPU: 100, CPU: *resource.Q("100m"),
}, },
}, },
}, },
@@ -634,7 +635,7 @@ func TestValidatePodUpdate(t *testing.T) {
Containers: []api.Container{ Containers: []api.Container{
{ {
Image: "foo:V2", Image: "foo:V2",
CPU: 1000, CPU: *resource.Q("1000m"),
}, },
}, },
}, },
@@ -1300,8 +1301,8 @@ func TestValidateMinionUpdate(t *testing.T) {
}, },
Spec: api.NodeSpec{ Spec: api.NodeSpec{
Capacity: api.ResourceList{ Capacity: api.ResourceList{
"cpu": util.NewIntOrStringFromInt(10000), api.ResourceCPU: *resource.Q("10000"),
"memory": util.NewIntOrStringFromInt(100), api.ResourceMemory: *resource.Q("100"),
}, },
}, },
}, api.Node{ }, api.Node{
@@ -1310,8 +1311,8 @@ func TestValidateMinionUpdate(t *testing.T) {
}, },
Spec: api.NodeSpec{ Spec: api.NodeSpec{
Capacity: api.ResourceList{ Capacity: api.ResourceList{
"cpu": util.NewIntOrStringFromInt(100), api.ResourceCPU: *resource.Q("100"),
"memory": util.NewIntOrStringFromInt(10000), api.ResourceMemory: *resource.Q("10000"),
}, },
}, },
}, true}, }, true},
@@ -1322,8 +1323,8 @@ func TestValidateMinionUpdate(t *testing.T) {
}, },
Spec: api.NodeSpec{ Spec: api.NodeSpec{
Capacity: api.ResourceList{ Capacity: api.ResourceList{
"cpu": util.NewIntOrStringFromInt(10000), api.ResourceCPU: *resource.Q("10000"),
"memory": util.NewIntOrStringFromInt(100), api.ResourceMemory: *resource.Q("100"),
}, },
}, },
}, api.Node{ }, api.Node{
@@ -1333,8 +1334,8 @@ func TestValidateMinionUpdate(t *testing.T) {
}, },
Spec: api.NodeSpec{ Spec: api.NodeSpec{
Capacity: api.ResourceList{ Capacity: api.ResourceList{
"cpu": util.NewIntOrStringFromInt(100), api.ResourceCPU: *resource.Q("100"),
"memory": util.NewIntOrStringFromInt(10000), api.ResourceMemory: *resource.Q("10000"),
}, },
}, },
}, true}, }, true},

View File

@@ -28,9 +28,9 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/version" "github.com/GoogleCloudPlatform/kubernetes/pkg/version"
@@ -96,7 +96,7 @@ func (c *testClient) Setup() *testClient {
func (c *testClient) Validate(t *testing.T, received runtime.Object, err error) { func (c *testClient) Validate(t *testing.T, received runtime.Object, err error) {
c.ValidateCommon(t, err) c.ValidateCommon(t, err)
if c.Response.Body != nil && !reflect.DeepEqual(c.Response.Body, received) { if c.Response.Body != nil && !api.Semantic.DeepEqual(c.Response.Body, received) {
t.Errorf("bad response for request %#v: expected %#v, got %#v", c.Request, c.Response.Body, received) t.Errorf("bad response for request %#v: expected %#v, got %#v", c.Request, c.Response.Body, received)
} }
} }
@@ -734,8 +734,8 @@ func TestCreateMinion(t *testing.T) {
}, },
Spec: api.NodeSpec{ Spec: api.NodeSpec{
Capacity: api.ResourceList{ Capacity: api.ResourceList{
resources.CPU: util.NewIntOrStringFromInt(1000), api.ResourceCPU: *resource.Q("1000m"),
resources.Memory: util.NewIntOrStringFromInt(1024 * 1024), api.ResourceMemory: *resource.Q("1Mi"),
}, },
}, },
} }

View File

@@ -28,13 +28,13 @@ import (
"strings" "strings"
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
"code.google.com/p/goauth2/compute/serviceaccount" "code.google.com/p/goauth2/compute/serviceaccount"
compute "code.google.com/p/google-api-go-client/compute/v1" compute "code.google.com/p/google-api-go-client/compute/v1"
container "code.google.com/p/google-api-go-client/container/v1beta1" container "code.google.com/p/google-api-go-client/container/v1beta1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/golang/glog" "github.com/golang/glog"
) )
@@ -338,11 +338,12 @@ func (gce *GCECloud) List(filter string) ([]string, error) {
return instances, nil return instances, nil
} }
func makeResources(cpu float32, memory float32) *api.NodeResources { // cpu is in cores, memory is in GiB
func makeResources(cpu float64, memory float64) *api.NodeResources {
return &api.NodeResources{ return &api.NodeResources{
Capacity: api.ResourceList{ Capacity: api.ResourceList{
resources.CPU: util.NewIntOrStringFromInt(int(cpu * 1000)), api.ResourceCPU: *resource.NewMilliQuantity(int64(cpu*1000), resource.DecimalSI),
resources.Memory: util.NewIntOrStringFromInt(int(memory * 1024 * 1024 * 1024)), api.ResourceMemory: *resource.NewQuantity(int64(memory*1024*1024*1024), resource.BinarySI),
}, },
} }
} }
@@ -359,6 +360,7 @@ func (gce *GCECloud) GetNodeResources(name string) (*api.NodeResources, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
// TODO: actually read machine size instead of this awful hack.
switch canonicalizeMachineType(res.MachineType) { switch canonicalizeMachineType(res.MachineType) {
case "f1-micro": case "f1-micro":
return makeResources(1, 0.6), nil return makeResources(1, 0.6), nil

View File

@@ -398,7 +398,7 @@ func makePortsAndBindings(container *api.Container) (map[docker.Port]struct{}, m
return exposedPorts, portBindings return exposedPorts, portBindings
} }
func milliCPUToShares(milliCPU int) int { func milliCPUToShares(milliCPU int64) int64 {
if milliCPU == 0 { if milliCPU == 0 {
// zero milliCPU means unset. Use kernel default. // zero milliCPU means unset. Use kernel default.
return 0 return 0
@@ -537,8 +537,8 @@ func (kl *Kubelet) runContainer(pod *api.BoundPod, container *api.Container, pod
ExposedPorts: exposedPorts, ExposedPorts: exposedPorts,
Hostname: pod.Name, Hostname: pod.Name,
Image: container.Image, Image: container.Image,
Memory: int64(container.Memory), Memory: container.Memory.Value(),
CPUShares: int64(milliCPUToShares(container.CPU)), CPUShares: milliCPUToShares(container.CPU.MilliValue()),
WorkingDir: container.WorkingDir, WorkingDir: container.WorkingDir,
}, },
} }

View File

@@ -22,7 +22,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
"github.com/golang/glog" "github.com/golang/glog"
) )
@@ -89,15 +88,15 @@ type ResourceFit struct {
} }
type resourceRequest struct { type resourceRequest struct {
milliCPU int milliCPU int64
memory int memory int64
} }
func getResourceRequest(pod *api.Pod) resourceRequest { func getResourceRequest(pod *api.Pod) resourceRequest {
result := resourceRequest{} result := resourceRequest{}
for ix := range pod.Spec.Containers { for ix := range pod.Spec.Containers {
result.memory += pod.Spec.Containers[ix].Memory result.memory += pod.Spec.Containers[ix].Memory.Value()
result.milliCPU += pod.Spec.Containers[ix].CPU result.milliCPU += pod.Spec.Containers[ix].CPU.MilliValue()
} }
return result return result
} }
@@ -113,17 +112,16 @@ func (r *ResourceFit) PodFitsResources(pod api.Pod, existingPods []api.Pod, node
if err != nil { if err != nil {
return false, err return false, err
} }
milliCPURequested := 0 milliCPURequested := int64(0)
memoryRequested := 0 memoryRequested := int64(0)
for ix := range existingPods { for ix := range existingPods {
existingRequest := getResourceRequest(&existingPods[ix]) existingRequest := getResourceRequest(&existingPods[ix])
milliCPURequested += existingRequest.milliCPU milliCPURequested += existingRequest.milliCPU
memoryRequested += existingRequest.memory memoryRequested += existingRequest.memory
} }
// TODO: convert to general purpose resource matching, when pods ask for resources totalMilliCPU := info.Spec.Capacity.Get(api.ResourceCPU).MilliValue()
totalMilliCPU := int(resources.GetFloatResource(info.Spec.Capacity, resources.CPU, 0) * 1000) totalMemory := info.Spec.Capacity.Get(api.ResourceMemory).Value()
totalMemory := resources.GetIntegerResource(info.Spec.Capacity, resources.Memory, 0)
fitsCPU := totalMilliCPU == 0 || (totalMilliCPU-milliCPURequested) >= podRequest.milliCPU fitsCPU := totalMilliCPU == 0 || (totalMilliCPU-milliCPURequested) >= podRequest.milliCPU
fitsMemory := totalMemory == 0 || (totalMemory-memoryRequested) >= podRequest.memory fitsMemory := totalMemory == 0 || (totalMemory-memoryRequested) >= podRequest.memory

View File

@@ -21,8 +21,7 @@ import (
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
) )
type FakeNodeInfo api.Node type FakeNodeInfo api.Node
@@ -32,17 +31,11 @@ func (n FakeNodeInfo) GetNodeInfo(nodeName string) (*api.Node, error) {
return &node, nil return &node, nil
} }
func makeResources(milliCPU int, memory int) api.NodeResources { func makeResources(milliCPU int64, memory int64) api.NodeResources {
return api.NodeResources{ return api.NodeResources{
Capacity: api.ResourceList{ Capacity: api.ResourceList{
resources.CPU: util.IntOrString{ api.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI),
IntVal: milliCPU, api.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI),
Kind: util.IntstrInt,
},
resources.Memory: util.IntOrString{
IntVal: memory,
Kind: util.IntstrInt,
},
}, },
} }
} }
@@ -51,8 +44,8 @@ func newResourcePod(usage ...resourceRequest) api.Pod {
containers := []api.Container{} containers := []api.Container{}
for _, req := range usage { for _, req := range usage {
containers = append(containers, api.Container{ containers = append(containers, api.Container{
Memory: req.memory, Memory: *resource.NewQuantity(req.memory, resource.BinarySI),
CPU: req.milliCPU, CPU: *resource.NewMilliQuantity(req.milliCPU, resource.DecimalSI),
}) })
} }
return api.Pod{ return api.Pod{

View File

@@ -18,13 +18,12 @@ package scheduler
import ( import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
"github.com/golang/glog" "github.com/golang/glog"
) )
// the unused capacity is calculated on a scale of 0-10 // the unused capacity is calculated on a scale of 0-10
// 0 being the lowest priority and 10 being the highest // 0 being the lowest priority and 10 being the highest
func calculateScore(requested, capacity int, node string) int { func calculateScore(requested, capacity int64, node string) int {
if capacity == 0 { if capacity == 0 {
return 0 return 0
} }
@@ -32,30 +31,39 @@ func calculateScore(requested, capacity int, node string) int {
glog.Errorf("Combined requested resources from existing pods exceeds capacity on minion: %s", node) glog.Errorf("Combined requested resources from existing pods exceeds capacity on minion: %s", node)
return 0 return 0
} }
return ((capacity - requested) * 10) / capacity return int(((capacity - requested) * 10) / capacity)
} }
// Calculate the occupancy on a node. 'node' has information about the resources on the node. // Calculate the occupancy on a node. 'node' has information about the resources on the node.
// 'pods' is a list of pods currently scheduled on the node. // 'pods' is a list of pods currently scheduled on the node.
func calculateOccupancy(pod api.Pod, node api.Node, pods []api.Pod) HostPriority { func calculateOccupancy(pod api.Pod, node api.Node, pods []api.Pod) HostPriority {
totalCPU := 0 totalMilliCPU := int64(0)
totalMemory := 0 totalMemory := int64(0)
for _, existingPod := range pods { for _, existingPod := range pods {
for _, container := range existingPod.Spec.Containers { for _, container := range existingPod.Spec.Containers {
totalCPU += container.CPU totalMilliCPU += container.CPU.MilliValue()
totalMemory += container.Memory totalMemory += container.Memory.Value()
} }
} }
// Add the resources requested by the current pod being scheduled. // Add the resources requested by the current pod being scheduled.
// This also helps differentiate between differently sized, but empty, minions. // This also helps differentiate between differently sized, but empty, minions.
for _, container := range pod.Spec.Containers { for _, container := range pod.Spec.Containers {
totalCPU += container.CPU totalMilliCPU += container.CPU.MilliValue()
totalMemory += container.Memory totalMemory += container.Memory.Value()
} }
cpuScore := calculateScore(totalCPU, resources.GetIntegerResource(node.Spec.Capacity, resources.CPU, 0), node.Name) capacityMilliCPU := node.Spec.Capacity.Get(api.ResourceCPU).MilliValue()
memoryScore := calculateScore(totalMemory, resources.GetIntegerResource(node.Spec.Capacity, resources.Memory, 0), node.Name) capacityMemory := node.Spec.Capacity.Get(api.ResourceMemory).Value()
glog.V(4).Infof("Least Requested Priority, AbsoluteRequested: (%d, %d) Score:(%d, %d)", totalCPU, totalMemory, cpuScore, memoryScore)
cpuScore := calculateScore(totalMilliCPU, capacityMilliCPU, node.Name)
memoryScore := calculateScore(totalMemory, capacityMemory, node.Name)
glog.V(4).Infof(
"%v -> %v: Least Requested Priority, AbsoluteRequested: (%d, %d) / (%d, %d) Score: (%d, %d)",
pod.Name, node.Name,
totalMilliCPU, totalMemory,
capacityMilliCPU, capacityMemory,
cpuScore, memoryScore,
)
return HostPriority{ return HostPriority{
host: node.Name, host: node.Name,

View File

@@ -21,17 +21,16 @@ import (
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
) )
func makeMinion(node string, cpu, memory int) api.Node { func makeMinion(node string, milliCPU, memory int64) api.Node {
return api.Node{ return api.Node{
ObjectMeta: api.ObjectMeta{Name: node}, ObjectMeta: api.ObjectMeta{Name: node},
Spec: api.NodeSpec{ Spec: api.NodeSpec{
Capacity: api.ResourceList{ Capacity: api.ResourceList{
resources.CPU: util.NewIntOrStringFromInt(cpu), api.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI),
resources.Memory: util.NewIntOrStringFromInt(memory), api.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI),
}, },
}, },
} }
@@ -57,14 +56,14 @@ func TestLeastRequested(t *testing.T) {
} }
cpuOnly := api.PodSpec{ cpuOnly := api.PodSpec{
Containers: []api.Container{ Containers: []api.Container{
{CPU: 1000}, {CPU: *resource.Q("1000m")},
{CPU: 2000}, {CPU: *resource.Q("2000m")},
}, },
} }
cpuAndMemory := api.PodSpec{ cpuAndMemory := api.PodSpec{
Containers: []api.Container{ Containers: []api.Container{
{CPU: 1000, Memory: 2000}, {CPU: *resource.Q("1000m"), Memory: *resource.Q("2000")},
{CPU: 2000, Memory: 3000}, {CPU: *resource.Q("2000m"), Memory: *resource.Q("3000")},
}, },
} }
tests := []struct { tests := []struct {