mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-01 07:47:56 +00:00
Merge pull request #3195 from lavalamp/numericWire
Add numeric type into api
This commit is contained in:
commit
5f2dae4dd8
@ -22,20 +22,19 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"math"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||||
minionControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/controller"
|
minionControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/controller"
|
||||||
replicationControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/controller"
|
replicationControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/controller"
|
||||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/service"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/service"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/version/verflag"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/version/verflag"
|
||||||
@ -51,8 +50,9 @@ var (
|
|||||||
minionRegexp = flag.String("minion_regexp", "", "If non empty, and -cloud_provider is specified, a regular expression for matching minion VMs.")
|
minionRegexp = flag.String("minion_regexp", "", "If non empty, and -cloud_provider is specified, a regular expression for matching minion VMs.")
|
||||||
machineList util.StringList
|
machineList util.StringList
|
||||||
// TODO: Discover these by pinging the host machines, and rip out these flags.
|
// TODO: Discover these by pinging the host machines, and rip out these flags.
|
||||||
|
// TODO: in the meantime, use resource.QuantityFlag() instead of these
|
||||||
nodeMilliCPU = flag.Int64("node_milli_cpu", 1000, "The amount of MilliCPU provisioned on each node")
|
nodeMilliCPU = flag.Int64("node_milli_cpu", 1000, "The amount of MilliCPU provisioned on each node")
|
||||||
nodeMemory = flag.Int64("node_memory", 3*1024*1024*1024, "The amount of memory (in bytes) provisioned on each node")
|
nodeMemory = resource.QuantityFlag("node_memory", "3Gi", "The amount of memory (in bytes) provisioned on each node")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -90,18 +90,6 @@ func main() {
|
|||||||
glog.Fatalf("Invalid API configuration: %v", err)
|
glog.Fatalf("Invalid API configuration: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if int64(int(*nodeMilliCPU)) != *nodeMilliCPU {
|
|
||||||
glog.Warningf("node_milli_cpu is too big for platform. Clamping: %d -> %d",
|
|
||||||
*nodeMilliCPU, math.MaxInt32)
|
|
||||||
*nodeMilliCPU = math.MaxInt32
|
|
||||||
}
|
|
||||||
|
|
||||||
if int64(int(*nodeMemory)) != *nodeMemory {
|
|
||||||
glog.Warningf("node_memory is too big for platform. Clamping: %d -> %d",
|
|
||||||
*nodeMemory, math.MaxInt32)
|
|
||||||
*nodeMemory = math.MaxInt32
|
|
||||||
}
|
|
||||||
|
|
||||||
go http.ListenAndServe(net.JoinHostPort(address.String(), strconv.Itoa(*port)), nil)
|
go http.ListenAndServe(net.JoinHostPort(address.String(), strconv.Itoa(*port)), nil)
|
||||||
|
|
||||||
endpoints := service.NewEndpointController(kubeClient)
|
endpoints := service.NewEndpointController(kubeClient)
|
||||||
@ -113,8 +101,8 @@ func main() {
|
|||||||
cloud := cloudprovider.InitCloudProvider(*cloudProvider, *cloudConfigFile)
|
cloud := cloudprovider.InitCloudProvider(*cloudProvider, *cloudConfigFile)
|
||||||
nodeResources := &api.NodeResources{
|
nodeResources := &api.NodeResources{
|
||||||
Capacity: api.ResourceList{
|
Capacity: api.ResourceList{
|
||||||
resources.CPU: util.NewIntOrStringFromInt(int(*nodeMilliCPU)),
|
api.ResourceCPU: *resource.NewMilliQuantity(*nodeMilliCPU, resource.DecimalSI),
|
||||||
resources.Memory: util.NewIntOrStringFromInt(int(*nodeMemory)),
|
api.ResourceMemory: *nodeMemory,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
minionController := minionControllerPkg.NewMinionController(cloud, *minionRegexp, machineList, nodeResources, kubeClient)
|
minionController := minionControllerPkg.NewMinionController(cloud, *minionRegexp, machineList, nodeResources, kubeClient)
|
||||||
|
@ -18,6 +18,28 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Semantic can do semantic deep equality checks for api objects.
|
||||||
|
// Example: api.Semantic.DeepEqual(aPod, aPodWithNonNilButEmptyMaps) == true
|
||||||
|
var Semantic = conversion.EqualitiesOrDie(
|
||||||
|
func(a, b resource.Quantity) bool {
|
||||||
|
// Ignore formatting, only care that numeric value stayed the same.
|
||||||
|
// TODO: if we decide it's important, after we drop v1beta1/2, we
|
||||||
|
// could start comparing format.
|
||||||
|
//
|
||||||
|
// Uninitialized quantities are equivilent to 0 quantities.
|
||||||
|
if a.Amount == nil && b.MilliValue() == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if b.Amount == nil && a.MilliValue() == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return a.Amount.Cmp(b.Amount) == 0
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Address these per #1502
|
// TODO: Address these per #1502
|
||||||
|
@ -18,7 +18,6 @@ package latest
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"reflect"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -167,7 +166,7 @@ func TestInternalRoundTrip(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(obj, actual) {
|
if !internal.Semantic.DeepEqual(obj, actual) {
|
||||||
t.Errorf("%s: diff %s", k, util.ObjectDiff(obj, actual))
|
t.Errorf("%s: diff %s", k, util.ObjectDiff(obj, actual))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,14 +102,14 @@ const (
|
|||||||
DecimalSI = Format("DecimalSI") // e.g., 12M (12 * 10^6)
|
DecimalSI = Format("DecimalSI") // e.g., 12M (12 * 10^6)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParseOrDie turns the given string into a quantity or panics; for tests
|
// MustParse turns the given string into a quantity or panics; for tests
|
||||||
// or others cases where you know the string is valid.
|
// or others cases where you know the string is valid.
|
||||||
func ParseOrDie(str string) *Quantity {
|
func MustParse(str string) Quantity {
|
||||||
q, err := ParseQuantity(str)
|
q, err := ParseQuantity(str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("cannot parse '%v': %v", str, err))
|
panic(fmt.Errorf("cannot parse '%v': %v", str, err))
|
||||||
}
|
}
|
||||||
return q
|
return *q
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -148,7 +148,7 @@ var (
|
|||||||
// The maximum value we can represent milli-units for.
|
// The maximum value we can represent milli-units for.
|
||||||
// Compare with the return value of Quantity.Value() to
|
// Compare with the return value of Quantity.Value() to
|
||||||
// see if it's safe to use Quantity.MilliValue().
|
// see if it's safe to use Quantity.MilliValue().
|
||||||
MaxMilliValue = ((1 << 63) - 1) / 1000
|
MaxMilliValue = int64(((1 << 63) - 1) / 1000)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParseQuantity turns str into a Quantity, or returns an error.
|
// ParseQuantity turns str into a Quantity, or returns an error.
|
||||||
@ -403,10 +403,7 @@ func (qf qFlag) String() string {
|
|||||||
// QuantityFlag is a helper that makes a quantity flag (using standard flag package).
|
// QuantityFlag is a helper that makes a quantity flag (using standard flag package).
|
||||||
// Will panic if defaultValue is not a valid quantity.
|
// Will panic if defaultValue is not a valid quantity.
|
||||||
func QuantityFlag(flagName, defaultValue, description string) *Quantity {
|
func QuantityFlag(flagName, defaultValue, description string) *Quantity {
|
||||||
q, err := ParseQuantity(defaultValue)
|
q := MustParse(defaultValue)
|
||||||
if err != nil {
|
flag.Var(qFlag{&q}, flagName, description)
|
||||||
panic(fmt.Errorf("can't use %v as a quantity: %v", defaultValue, err))
|
return &q
|
||||||
}
|
|
||||||
flag.Var(qFlag{q}, flagName, description)
|
|
||||||
return q
|
|
||||||
}
|
}
|
||||||
|
@ -38,17 +38,17 @@ func ExampleFormat() {
|
|||||||
// cores = 5300m
|
// cores = 5300m
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleParseOrDie() {
|
func ExampleMustParse() {
|
||||||
memorySize := resource.ParseOrDie("5Gi")
|
memorySize := resource.MustParse("5Gi")
|
||||||
fmt.Printf("memorySize = %v (%v)\n", memorySize.Value(), memorySize.Format)
|
fmt.Printf("memorySize = %v (%v)\n", memorySize.Value(), memorySize.Format)
|
||||||
|
|
||||||
diskSize := resource.ParseOrDie("5G")
|
diskSize := resource.MustParse("5G")
|
||||||
fmt.Printf("diskSize = %v (%v)\n", diskSize.Value(), diskSize.Format)
|
fmt.Printf("diskSize = %v (%v)\n", diskSize.Value(), diskSize.Format)
|
||||||
|
|
||||||
cores := resource.ParseOrDie("5300m")
|
cores := resource.MustParse("5300m")
|
||||||
fmt.Printf("milliCores = %v (%v)\n", cores.MilliValue(), cores.Format)
|
fmt.Printf("milliCores = %v (%v)\n", cores.MilliValue(), cores.Format)
|
||||||
|
|
||||||
cores2 := resource.ParseOrDie("5.4")
|
cores2 := resource.MustParse("5.4")
|
||||||
fmt.Printf("milliCores = %v (%v)\n", cores2.MilliValue(), cores2.Format)
|
fmt.Printf("milliCores = %v (%v)\n", cores2.MilliValue(), cores2.Format)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
|
@ -27,12 +27,15 @@ 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/meta"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
|
||||||
docker "github.com/fsouza/go-dockerclient"
|
docker "github.com/fsouza/go-dockerclient"
|
||||||
fuzz "github.com/google/gofuzz"
|
fuzz "github.com/google/gofuzz"
|
||||||
|
"speter.net/go/exp/math/dec/inf"
|
||||||
)
|
)
|
||||||
|
|
||||||
var fuzzIters = flag.Int("fuzz_iters", 40, "How many fuzzing iterations to do.")
|
var fuzzIters = flag.Int("fuzz_iters", 40, "How many fuzzing iterations to do.")
|
||||||
@ -136,6 +139,16 @@ var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
|
|||||||
c.RandString(): c.RandString(),
|
c.RandString(): c.RandString(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
func(q *resource.Quantity, c fuzz.Continue) {
|
||||||
|
// Real Quantity fuzz testing is done elsewhere;
|
||||||
|
// this limited subset of functionality survives
|
||||||
|
// round-tripping to v1beta1/2.
|
||||||
|
q.Amount = &inf.Dec{}
|
||||||
|
q.Format = resource.DecimalExponent
|
||||||
|
//q.Amount.SetScale(inf.Scale(-c.Intn(12)))
|
||||||
|
q.Amount.SetUnscaled(c.Int63n(1000))
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) {
|
func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) {
|
||||||
@ -159,7 +172,7 @@ func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) {
|
|||||||
t.Errorf("0: %v: %v\nCodec: %v\nData: %s\nSource: %#v", name, err, codec, string(data), source)
|
t.Errorf("0: %v: %v\nCodec: %v\nData: %s\nSource: %#v", name, err, codec, string(data), source)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(source, obj2) {
|
if !api.Semantic.DeepEqual(source, obj2) {
|
||||||
t.Errorf("1: %v: diff: %v\nCodec: %v\nData: %s\nSource: %#v", name, util.ObjectGoPrintDiff(source, obj2), codec, string(data), source)
|
t.Errorf("1: %v: diff: %v\nCodec: %v\nData: %s\nSource: %#v", name, util.ObjectGoPrintDiff(source, obj2), codec, string(data), source)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -170,7 +183,7 @@ func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) {
|
|||||||
t.Errorf("2: %v: %v", name, err)
|
t.Errorf("2: %v: %v", name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(source, obj3) {
|
if !api.Semantic.DeepEqual(source, obj3) {
|
||||||
t.Errorf("3: %v: diff: %v\nCodec: %v", name, util.ObjectDiff(source, obj3), codec)
|
t.Errorf("3: %v: diff: %v\nCodec: %v", name, util.ObjectDiff(source, obj3), codec)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -244,7 +257,7 @@ func TestEncode_Ptr(t *testing.T) {
|
|||||||
if _, ok := obj2.(*api.Pod); !ok {
|
if _, ok := obj2.(*api.Pod); !ok {
|
||||||
t.Fatalf("Got wrong type")
|
t.Fatalf("Got wrong type")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(obj2, pod) {
|
if !api.Semantic.DeepEqual(obj2, pod) {
|
||||||
t.Errorf("Expected:\n %#v,\n Got:\n %#v", &pod, obj2)
|
t.Errorf("Expected:\n %#v,\n Got:\n %#v", &pod, obj2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
@ -309,12 +310,12 @@ type Container struct {
|
|||||||
Ports []Port `json:"ports,omitempty"`
|
Ports []Port `json:"ports,omitempty"`
|
||||||
Env []EnvVar `json:"env,omitempty"`
|
Env []EnvVar `json:"env,omitempty"`
|
||||||
// Optional: Defaults to unlimited.
|
// Optional: Defaults to unlimited.
|
||||||
Memory int `json:"memory,omitempty"`
|
Memory resource.Quantity `json:"memory,omitempty"`
|
||||||
// Optional: Defaults to unlimited.
|
// Optional: Defaults to unlimited.
|
||||||
CPU int `json:"cpu,omitempty"`
|
CPU resource.Quantity `json:"cpu,omitempty"`
|
||||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||||
LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty"`
|
LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty"`
|
||||||
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
||||||
// Optional: Defaults to /dev/termination-log
|
// Optional: Defaults to /dev/termination-log
|
||||||
TerminationMessagePath string `json:"terminationMessagePath,omitempty"`
|
TerminationMessagePath string `json:"terminationMessagePath,omitempty"`
|
||||||
// Optional: Default to false.
|
// Optional: Default to false.
|
||||||
@ -747,9 +748,29 @@ type NodeResources struct {
|
|||||||
Capacity ResourceList `json:"capacity,omitempty"`
|
Capacity ResourceList `json:"capacity,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResourceName is the name identifying various resources in a ResourceList.
|
||||||
type ResourceName string
|
type ResourceName string
|
||||||
|
|
||||||
type ResourceList map[ResourceName]util.IntOrString
|
const (
|
||||||
|
// CPU, in cores. (500m = .5 cores)
|
||||||
|
ResourceCPU ResourceName = "cpu"
|
||||||
|
// Memory, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
|
||||||
|
ResourceMemory ResourceName = "memory"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResourceList is a set of (resource name, quantity) pairs.
|
||||||
|
type ResourceList map[ResourceName]resource.Quantity
|
||||||
|
|
||||||
|
// Get is a convenience function, which returns a 0 quantity if the
|
||||||
|
// resource list is nil, empty, or lacks a value for the requested resource.
|
||||||
|
// Treat as read only!
|
||||||
|
func (rl ResourceList) Get(name ResourceName) *resource.Quantity {
|
||||||
|
if rl == nil {
|
||||||
|
return &resource.Quantity{}
|
||||||
|
}
|
||||||
|
q := rl[name]
|
||||||
|
return &q
|
||||||
|
}
|
||||||
|
|
||||||
// Node is a worker node in Kubernetenes
|
// Node is a worker node in Kubernetenes
|
||||||
// The name of the node according to etcd is in ObjectMeta.Name.
|
// The name of the node according to etcd is in ObjectMeta.Name.
|
||||||
|
@ -18,10 +18,13 @@ package v1beta1
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -38,7 +41,7 @@ func init() {
|
|||||||
// newer.Scheme.AddStructFieldConversion(string(""), "Status", string(""), "Condition")
|
// newer.Scheme.AddStructFieldConversion(string(""), "Status", string(""), "Condition")
|
||||||
// newer.Scheme.AddStructFieldConversion(string(""), "Condition", string(""), "Status")
|
// newer.Scheme.AddStructFieldConversion(string(""), "Condition", string(""), "Status")
|
||||||
|
|
||||||
newer.Scheme.AddConversionFuncs(
|
err := newer.Scheme.AddConversionFuncs(
|
||||||
// TypeMeta must be split into two objects
|
// TypeMeta must be split into two objects
|
||||||
func(in *newer.TypeMeta, out *TypeMeta, s conversion.Scope) error {
|
func(in *newer.TypeMeta, out *TypeMeta, s conversion.Scope) error {
|
||||||
out.Kind = in.Kind
|
out.Kind = in.Kind
|
||||||
@ -582,5 +585,61 @@ func init() {
|
|||||||
out.Timestamp = in.Timestamp
|
out.Timestamp = in.Timestamp
|
||||||
return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0)
|
return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// This is triggered for the Memory field of Container.
|
||||||
|
func(in *int64, out *resource.Quantity, s conversion.Scope) error {
|
||||||
|
out.Set(*in)
|
||||||
|
out.Format = resource.BinarySI
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
func(in *resource.Quantity, out *int64, s conversion.Scope) error {
|
||||||
|
*out = in.Value()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
|
||||||
|
// This is triggered by the CPU field of Container.
|
||||||
|
// Note that if we add other int/Quantity conversions my
|
||||||
|
// simple hack (int64=Value(), int=MilliValue()) here won't work.
|
||||||
|
func(in *int, out *resource.Quantity, s conversion.Scope) error {
|
||||||
|
out.SetMilli(int64(*in))
|
||||||
|
out.Format = resource.DecimalSI
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
func(in *resource.Quantity, out *int, s conversion.Scope) error {
|
||||||
|
*out = int(in.MilliValue())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
|
||||||
|
// Convert resource lists.
|
||||||
|
func(in *ResourceList, out *newer.ResourceList, s conversion.Scope) error {
|
||||||
|
*out = newer.ResourceList{}
|
||||||
|
for k, v := range *in {
|
||||||
|
fv, err := strconv.ParseFloat(v.String(), 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("value '%v' of '%v': %v", v, k, err)
|
||||||
|
}
|
||||||
|
if k == ResourceCPU {
|
||||||
|
(*out)[newer.ResourceCPU] = *resource.NewMilliQuantity(int64(fv*1000), resource.DecimalSI)
|
||||||
|
} else {
|
||||||
|
(*out)[newer.ResourceName(k)] = *resource.NewQuantity(int64(fv), resource.BinarySI)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
func(in *newer.ResourceList, out *ResourceList, s conversion.Scope) error {
|
||||||
|
*out = ResourceList{}
|
||||||
|
for k, v := range *in {
|
||||||
|
if k == newer.ResourceCPU {
|
||||||
|
(*out)[ResourceCPU] = util.NewIntOrStringFromString(fmt.Sprintf("%v", float64(v.MilliValue())/1000))
|
||||||
|
} else {
|
||||||
|
(*out)[ResourceName(k)] = util.NewIntOrStringFromInt(int(v.Value()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
// If one of the conversion functions is malformed, detect it immediately.
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,7 +201,7 @@ func TestMinionListConversionToNew(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if e, a := item.newML, got; !reflect.DeepEqual(e, a) {
|
if e, a := item.newML, got; !newer.Semantic.DeepEqual(e, a) {
|
||||||
t.Errorf("Expected: %#v, got %#v", e, a)
|
t.Errorf("Expected: %#v, got %#v", e, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,7 +234,7 @@ func TestMinionListConversionToOld(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if e, a := oldML, got; !reflect.DeepEqual(e, a) {
|
if e, a := oldML, got; !newer.Semantic.DeepEqual(e, a) {
|
||||||
t.Errorf("Expected: %#v, got %#v", e, a)
|
t.Errorf("Expected: %#v, got %#v", e, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,7 +254,7 @@ type Container struct {
|
|||||||
Ports []Port `json:"ports,omitempty" description:"list of ports to expose from the container"`
|
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"`
|
Env []EnvVar `json:"env,omitempty" description:"list of environment variables to set in the container"`
|
||||||
// Optional: Defaults to unlimited.
|
// Optional: Defaults to unlimited.
|
||||||
Memory int `json:"memory,omitempty" description:"memory limit in bytes; defaults to unlimited"`
|
Memory int64 `json:"memory,omitempty" description:"memory limit in bytes; defaults to unlimited"`
|
||||||
// Optional: Defaults to unlimited.
|
// Optional: Defaults to unlimited.
|
||||||
CPU int `json:"cpu,omitempty" description:"CPU share in thousandths of a core"`
|
CPU int `json:"cpu,omitempty" description:"CPU share in thousandths of a core"`
|
||||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" description:"pod volumes to mount into the container's filesystem"`
|
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" description:"pod volumes to mount into the container's filesystem"`
|
||||||
@ -583,6 +583,13 @@ type NodeResources struct {
|
|||||||
|
|
||||||
type ResourceName string
|
type ResourceName string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// CPU, in cores. (floating point w/ 3 decimal places)
|
||||||
|
ResourceCPU ResourceName = "cpu"
|
||||||
|
// Memory, in bytes.
|
||||||
|
ResourceMemory ResourceName = "memory"
|
||||||
|
)
|
||||||
|
|
||||||
type ResourceList map[ResourceName]util.IntOrString
|
type ResourceList map[ResourceName]util.IntOrString
|
||||||
|
|
||||||
// Minion is a worker node in Kubernetenes.
|
// Minion is a worker node in Kubernetenes.
|
||||||
|
@ -18,10 +18,13 @@ package v1beta2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -38,7 +41,7 @@ func init() {
|
|||||||
// newer.Scheme.AddStructFieldConversion(string(""), "Status", string(""), "Condition")
|
// newer.Scheme.AddStructFieldConversion(string(""), "Status", string(""), "Condition")
|
||||||
// newer.Scheme.AddStructFieldConversion(string(""), "Condition", string(""), "Status")
|
// newer.Scheme.AddStructFieldConversion(string(""), "Condition", string(""), "Status")
|
||||||
|
|
||||||
newer.Scheme.AddConversionFuncs(
|
err := newer.Scheme.AddConversionFuncs(
|
||||||
// TypeMeta must be split into two objects
|
// TypeMeta must be split into two objects
|
||||||
func(in *newer.TypeMeta, out *TypeMeta, s conversion.Scope) error {
|
func(in *newer.TypeMeta, out *TypeMeta, s conversion.Scope) error {
|
||||||
out.Kind = in.Kind
|
out.Kind = in.Kind
|
||||||
@ -498,5 +501,61 @@ func init() {
|
|||||||
out.Timestamp = in.Timestamp
|
out.Timestamp = in.Timestamp
|
||||||
return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0)
|
return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// This is triggered for the Memory field of Container.
|
||||||
|
func(in *int64, out *resource.Quantity, s conversion.Scope) error {
|
||||||
|
out.Set(*in)
|
||||||
|
out.Format = resource.BinarySI
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
func(in *resource.Quantity, out *int64, s conversion.Scope) error {
|
||||||
|
*out = in.Value()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
|
||||||
|
// This is triggered by the CPU field of Container.
|
||||||
|
// Note that if we add other int/Quantity conversions my
|
||||||
|
// simple hack (int64=Value(), int=MilliValue()) here won't work.
|
||||||
|
func(in *int, out *resource.Quantity, s conversion.Scope) error {
|
||||||
|
out.SetMilli(int64(*in))
|
||||||
|
out.Format = resource.DecimalSI
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
func(in *resource.Quantity, out *int, s conversion.Scope) error {
|
||||||
|
*out = int(in.MilliValue())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
|
||||||
|
// Convert resource lists.
|
||||||
|
func(in *ResourceList, out *newer.ResourceList, s conversion.Scope) error {
|
||||||
|
*out = newer.ResourceList{}
|
||||||
|
for k, v := range *in {
|
||||||
|
fv, err := strconv.ParseFloat(v.String(), 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("value '%v' of '%v': %v", v, k, err)
|
||||||
|
}
|
||||||
|
if k == ResourceCPU {
|
||||||
|
(*out)[newer.ResourceCPU] = *resource.NewMilliQuantity(int64(fv*1000), resource.DecimalSI)
|
||||||
|
} else {
|
||||||
|
(*out)[newer.ResourceName(k)] = *resource.NewQuantity(int64(fv), resource.BinarySI)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
func(in *newer.ResourceList, out *ResourceList, s conversion.Scope) error {
|
||||||
|
*out = ResourceList{}
|
||||||
|
for k, v := range *in {
|
||||||
|
if k == newer.ResourceCPU {
|
||||||
|
(*out)[ResourceCPU] = util.NewIntOrStringFromString(fmt.Sprintf("%v", float64(v.MilliValue())/1000))
|
||||||
|
} else {
|
||||||
|
(*out)[ResourceName(k)] = util.NewIntOrStringFromInt(int(v.Value()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
// If one of the conversion functions is malformed, detect it immediately.
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,7 +218,7 @@ type Container struct {
|
|||||||
Ports []Port `json:"ports,omitempty" description:"list of ports to expose from the container"`
|
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"`
|
Env []EnvVar `json:"env,omitempty" description:"list of environment variables to set in the container"`
|
||||||
// Optional: Defaults to unlimited.
|
// Optional: Defaults to unlimited.
|
||||||
Memory int `json:"memory,omitempty" description:"memory limit in bytes; defaults to unlimited"`
|
Memory int64 `json:"memory,omitempty" description:"memory limit in bytes; defaults to unlimited"`
|
||||||
// Optional: Defaults to unlimited.
|
// Optional: Defaults to unlimited.
|
||||||
CPU int `json:"cpu,omitempty" description:"CPU share in thousandths of a core"`
|
CPU int `json:"cpu,omitempty" description:"CPU share in thousandths of a core"`
|
||||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" description:"pod volumes to mount into the container's filesystem"`
|
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" description:"pod volumes to mount into the container's filesystem"`
|
||||||
@ -546,6 +546,13 @@ type NodeResources struct {
|
|||||||
|
|
||||||
type ResourceName string
|
type ResourceName string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// CPU, in cores. (500m = .5 cores)
|
||||||
|
ResourceCPU ResourceName = "cpu"
|
||||||
|
// Memory, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
|
||||||
|
ResourceMemory ResourceName = "memory"
|
||||||
|
)
|
||||||
|
|
||||||
type ResourceList map[ResourceName]util.IntOrString
|
type ResourceList map[ResourceName]util.IntOrString
|
||||||
|
|
||||||
// Minion is a worker node in Kubernetenes.
|
// Minion is a worker node in Kubernetenes.
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package v1beta3
|
package v1beta3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
@ -326,13 +327,13 @@ type Container struct {
|
|||||||
WorkingDir string `json:"workingDir,omitempty"`
|
WorkingDir string `json:"workingDir,omitempty"`
|
||||||
Ports []Port `json:"ports,omitempty"`
|
Ports []Port `json:"ports,omitempty"`
|
||||||
Env []EnvVar `json:"env,omitempty"`
|
Env []EnvVar `json:"env,omitempty"`
|
||||||
// Optional: Defaults to unlimited.
|
// Optional: Defaults to unlimited. Units: bytes.
|
||||||
Memory int `json:"memory,omitempty"`
|
Memory resource.Quantity `json:"memory,omitempty"`
|
||||||
// Optional: Defaults to unlimited.
|
// Optional: Defaults to unlimited. Units: Cores. (500m == 1/2 core)
|
||||||
CPU int `json:"cpu,omitempty"`
|
CPU resource.Quantity `json:"cpu,omitempty"`
|
||||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||||
LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty"`
|
LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty"`
|
||||||
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
||||||
// Optional: Defaults to /dev/termination-log
|
// Optional: Defaults to /dev/termination-log
|
||||||
TerminationMessagePath string `json:"terminationMessagePath,omitempty"`
|
TerminationMessagePath string `json:"terminationMessagePath,omitempty"`
|
||||||
// Optional: Default to false.
|
// Optional: Default to false.
|
||||||
@ -776,9 +777,18 @@ type NodeCondition struct {
|
|||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResourceName is the name identifying various resources in a ResourceList.
|
||||||
type ResourceName string
|
type ResourceName string
|
||||||
|
|
||||||
type ResourceList map[ResourceName]util.IntOrString
|
const (
|
||||||
|
// CPU, in cores. (500m = .5 cores)
|
||||||
|
ResourceCPU ResourceName = "cpu"
|
||||||
|
// Memory, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
|
||||||
|
ResourceMemory ResourceName = "memory"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResourceList is a set of (resource name, quantity) pairs.
|
||||||
|
type ResourceList map[ResourceName]resource.Quantity
|
||||||
|
|
||||||
// Node is a worker node in Kubernetes.
|
// Node is a worker node in Kubernetes.
|
||||||
// The name of the node according to etcd is in ID.
|
// The name of the node according to etcd is in ID.
|
||||||
|
@ -18,7 +18,6 @@ package validation
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
@ -429,7 +428,7 @@ func ValidatePodUpdate(newPod, oldPod *api.Pod) errs.ValidationErrorList {
|
|||||||
newContainers = append(newContainers, container)
|
newContainers = append(newContainers, container)
|
||||||
}
|
}
|
||||||
pod.Spec.Containers = newContainers
|
pod.Spec.Containers = newContainers
|
||||||
if !reflect.DeepEqual(pod.Spec, oldPod.Spec) {
|
if !api.Semantic.DeepEqual(pod.Spec, oldPod.Spec) {
|
||||||
// TODO: a better error would include all immutable fields explicitly.
|
// TODO: a better error would include all immutable fields explicitly.
|
||||||
allErrs = append(allErrs, errs.NewFieldInvalid("spec.containers", newPod.Spec.Containers, "some fields are immutable"))
|
allErrs = append(allErrs, errs.NewFieldInvalid("spec.containers", newPod.Spec.Containers, "some fields are immutable"))
|
||||||
}
|
}
|
||||||
@ -586,7 +585,7 @@ func ValidateMinion(minion *api.Node) errs.ValidationErrorList {
|
|||||||
func ValidateMinionUpdate(oldMinion *api.Node, minion *api.Node) errs.ValidationErrorList {
|
func ValidateMinionUpdate(oldMinion *api.Node, minion *api.Node) errs.ValidationErrorList {
|
||||||
allErrs := errs.ValidationErrorList{}
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
|
||||||
if !reflect.DeepEqual(minion.Status, api.NodeStatus{}) {
|
if !api.Semantic.DeepEqual(minion.Status, api.NodeStatus{}) {
|
||||||
allErrs = append(allErrs, errs.NewFieldInvalid("status", minion.Status, "status must be empty"))
|
allErrs = append(allErrs, errs.NewFieldInvalid("status", minion.Status, "status must be empty"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,7 +595,7 @@ func ValidateMinionUpdate(oldMinion *api.Node, minion *api.Node) errs.Validation
|
|||||||
// Clear status
|
// Clear status
|
||||||
oldMinion.Status = minion.Status
|
oldMinion.Status = minion.Status
|
||||||
|
|
||||||
if !reflect.DeepEqual(oldMinion, minion) {
|
if !api.Semantic.DeepEqual(oldMinion, minion) {
|
||||||
glog.V(4).Infof("Update failed validation %#v vs %#v", oldMinion, minion)
|
glog.V(4).Infof("Update failed validation %#v vs %#v", oldMinion, minion)
|
||||||
allErrs = append(allErrs, fmt.Errorf("update contains more than labels or capacity changes"))
|
allErrs = append(allErrs, fmt.Errorf("update contains more than labels or capacity changes"))
|
||||||
}
|
}
|
||||||
|
@ -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.MustParse("1"),
|
||||||
CPU: 1,
|
CPU: resource.MustParse("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.MustParse("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.MustParse("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.MustParse("10000"),
|
||||||
"memory": util.NewIntOrStringFromInt(100),
|
api.ResourceMemory: resource.MustParse("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.MustParse("100"),
|
||||||
"memory": util.NewIntOrStringFromInt(10000),
|
api.ResourceMemory: resource.MustParse("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.MustParse("10000"),
|
||||||
"memory": util.NewIntOrStringFromInt(100),
|
api.ResourceMemory: resource.MustParse("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.MustParse("100"),
|
||||||
"memory": util.NewIntOrStringFromInt(10000),
|
api.ResourceMemory: resource.MustParse("10000"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, true},
|
}, true},
|
||||||
|
@ -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.MustParse("1000m"),
|
||||||
resources.Memory: util.NewIntOrStringFromInt(1024 * 1024),
|
api.ResourceMemory: resource.MustParse("1Mi"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -36,8 +36,8 @@ import (
|
|||||||
"github.com/rackspace/gophercloud/pagination"
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -169,11 +169,11 @@ func (os *OpenStack) Instances() (cloudprovider.Instances, bool) {
|
|||||||
for _, flavor := range flavorList {
|
for _, flavor := range flavorList {
|
||||||
rsrc := api.NodeResources{
|
rsrc := api.NodeResources{
|
||||||
Capacity: api.ResourceList{
|
Capacity: api.ResourceList{
|
||||||
"cpu": util.NewIntOrStringFromInt(flavor.VCPUs),
|
api.ResourceCPU: *resource.NewMilliQuantity(int64(flavor.VCPUs*1000), resource.DecimalSI),
|
||||||
"memory": util.NewIntOrStringFromString(fmt.Sprintf("%dMiB", flavor.RAM)),
|
api.ResourceMemory: resource.MustParse(fmt.Sprintf("%dMi", flavor.RAM)),
|
||||||
"openstack.org/disk": util.NewIntOrStringFromString(fmt.Sprintf("%dGB", flavor.Disk)),
|
"openstack.org/disk": resource.MustParse(fmt.Sprintf("%dG", flavor.Disk)),
|
||||||
"openstack.org/rxTxFactor": util.NewIntOrStringFromInt(int(flavor.RxTxFactor * 1000)),
|
"openstack.org/rxTxFactor": *resource.NewQuantity(int64(flavor.RxTxFactor*1000), resource.DecimalSI),
|
||||||
"openstack.org/swap": util.NewIntOrStringFromString(fmt.Sprintf("%dMiB", flavor.Swap)),
|
"openstack.org/swap": resource.MustParse(fmt.Sprintf("%dMi", flavor.Swap)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
flavor_to_resource[flavor.ID] = &rsrc
|
flavor_to_resource[flavor.ID] = &rsrc
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -233,7 +232,7 @@ func TestCreateReplica(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %#v", err)
|
t.Errorf("Unexpected error: %#v", err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(&expectedPod, actualPod) {
|
if !api.Semantic.DeepEqual(&expectedPod, actualPod) {
|
||||||
t.Logf("Body: %s", fakeHandler.RequestBody)
|
t.Logf("Body: %s", fakeHandler.RequestBody)
|
||||||
t.Errorf("Unexpected mismatch. Expected\n %#v,\n Got:\n %#v", &expectedPod, actualPod)
|
t.Errorf("Unexpected mismatch. Expected\n %#v,\n Got:\n %#v", &expectedPod, actualPod)
|
||||||
}
|
}
|
||||||
@ -345,7 +344,7 @@ func TestWatchControllers(t *testing.T) {
|
|||||||
var testControllerSpec api.ReplicationController
|
var testControllerSpec api.ReplicationController
|
||||||
received := make(chan struct{})
|
received := make(chan struct{})
|
||||||
manager.syncHandler = func(controllerSpec api.ReplicationController) error {
|
manager.syncHandler = func(controllerSpec api.ReplicationController) error {
|
||||||
if !reflect.DeepEqual(controllerSpec, testControllerSpec) {
|
if !api.Semantic.DeepEqual(controllerSpec, testControllerSpec) {
|
||||||
t.Errorf("Expected %#v, but got %#v", testControllerSpec, controllerSpec)
|
t.Errorf("Expected %#v, but got %#v", testControllerSpec, controllerSpec)
|
||||||
}
|
}
|
||||||
close(received)
|
close(received)
|
||||||
|
@ -22,15 +22,28 @@ import (
|
|||||||
|
|
||||||
func TestEqualities(t *testing.T) {
|
func TestEqualities(t *testing.T) {
|
||||||
e := Equalities{}
|
e := Equalities{}
|
||||||
|
type Bar struct {
|
||||||
|
X int
|
||||||
|
}
|
||||||
|
type Baz struct {
|
||||||
|
Y Bar
|
||||||
|
}
|
||||||
err := e.AddFuncs(
|
err := e.AddFuncs(
|
||||||
func(a, b int) bool {
|
func(a, b int) bool {
|
||||||
return a+1 == b
|
return a+1 == b
|
||||||
},
|
},
|
||||||
|
func(a, b Bar) bool {
|
||||||
|
return a.X*10 == b.X
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected: %v", err)
|
t.Fatalf("Unexpected: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Foo struct {
|
||||||
|
X int
|
||||||
|
}
|
||||||
|
|
||||||
table := []struct {
|
table := []struct {
|
||||||
a, b interface{}
|
a, b interface{}
|
||||||
equal bool
|
equal bool
|
||||||
@ -38,6 +51,10 @@ func TestEqualities(t *testing.T) {
|
|||||||
{1, 2, true},
|
{1, 2, true},
|
||||||
{2, 1, false},
|
{2, 1, false},
|
||||||
{"foo", "foo", true},
|
{"foo", "foo", true},
|
||||||
|
{Foo{1}, Foo{2}, true},
|
||||||
|
{Bar{1}, Bar{10}, true},
|
||||||
|
{&Bar{1}, &Bar{10}, true},
|
||||||
|
{Baz{Bar{1}}, Baz{Bar{10}}, true},
|
||||||
{map[string]int{"foo": 1}, map[string]int{"foo": 2}, true},
|
{map[string]int{"foo": 1}, map[string]int{"foo": 2}, true},
|
||||||
{map[string]int{}, map[string]int(nil), true},
|
{map[string]int{}, map[string]int(nil), true},
|
||||||
{[]int{}, []int(nil), true},
|
{[]int{}, []int(nil), true},
|
||||||
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -65,13 +64,7 @@ func CreateValidPod(name, namespace, source string) api.BoundPod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreatePodUpdate(op kubelet.PodOperation, source string, pods ...api.BoundPod) kubelet.PodUpdate {
|
func CreatePodUpdate(op kubelet.PodOperation, source string, pods ...api.BoundPod) kubelet.PodUpdate {
|
||||||
// We deliberately return an empty slice instead of a nil pointer here
|
|
||||||
// because reflect.DeepEqual differentiates between the two and we need to
|
|
||||||
// pick one for consistency.
|
|
||||||
newPods := make([]api.BoundPod, len(pods))
|
newPods := make([]api.BoundPod, len(pods))
|
||||||
if len(pods) == 0 {
|
|
||||||
return kubelet.PodUpdate{newPods, op, source}
|
|
||||||
}
|
|
||||||
for i := range pods {
|
for i := range pods {
|
||||||
newPods[i] = pods[i]
|
newPods[i] = pods[i]
|
||||||
}
|
}
|
||||||
@ -89,7 +82,7 @@ func expectPodUpdate(t *testing.T, ch <-chan kubelet.PodUpdate, expected ...kube
|
|||||||
for i := range expected {
|
for i := range expected {
|
||||||
update := <-ch
|
update := <-ch
|
||||||
sort.Sort(sortedPods(update.Pods))
|
sort.Sort(sortedPods(update.Pods))
|
||||||
if !reflect.DeepEqual(expected[i], update) {
|
if !api.Semantic.DeepEqual(expected[i], update) {
|
||||||
t.Fatalf("Expected %#v, Got %#v", expected[i], update)
|
t.Fatalf("Expected %#v, Got %#v", expected[i], update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -130,7 +129,7 @@ func TestReadFromFile(t *testing.T) {
|
|||||||
Containers: []api.Container{{Image: "test/image", TerminationMessagePath: "/dev/termination-log"}},
|
Containers: []api.Container{{Image: "test/image", TerminationMessagePath: "/dev/termination-log"}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if !reflect.DeepEqual(expected, update) {
|
if !api.Semantic.DeepEqual(expected, update) {
|
||||||
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +170,7 @@ func TestExtractFromValidDataFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
update := (<-ch).(kubelet.PodUpdate)
|
update := (<-ch).(kubelet.PodUpdate)
|
||||||
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, expectedPod)
|
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, expectedPod)
|
||||||
if !reflect.DeepEqual(expected, update) {
|
if !api.Semantic.DeepEqual(expected, update) {
|
||||||
t.Errorf("Expected %#v, Got %#v", expected, update)
|
t.Errorf("Expected %#v, Got %#v", expected, update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,7 +191,7 @@ func TestExtractFromEmptyDir(t *testing.T) {
|
|||||||
|
|
||||||
update := (<-ch).(kubelet.PodUpdate)
|
update := (<-ch).(kubelet.PodUpdate)
|
||||||
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource)
|
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource)
|
||||||
if !reflect.DeepEqual(expected, update) {
|
if !api.Semantic.DeepEqual(expected, update) {
|
||||||
t.Errorf("Expected %#v, Got %#v", expected, update)
|
t.Errorf("Expected %#v, Got %#v", expected, update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -242,7 +241,7 @@ func TestExtractFromDir(t *testing.T) {
|
|||||||
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, pods...)
|
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, pods...)
|
||||||
sort.Sort(sortedPods(update.Pods))
|
sort.Sort(sortedPods(update.Pods))
|
||||||
sort.Sort(sortedPods(expected.Pods))
|
sort.Sort(sortedPods(expected.Pods))
|
||||||
if !reflect.DeepEqual(expected, update) {
|
if !api.Semantic.DeepEqual(expected, update) {
|
||||||
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
||||||
}
|
}
|
||||||
for i := range update.Pods {
|
for i := range update.Pods {
|
||||||
|
@ -19,7 +19,6 @@ package config
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -193,7 +192,7 @@ func TestExtractFromHTTP(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
update := (<-ch).(kubelet.PodUpdate)
|
update := (<-ch).(kubelet.PodUpdate)
|
||||||
if !reflect.DeepEqual(testCase.expected, update) {
|
if !api.Semantic.DeepEqual(testCase.expected, update) {
|
||||||
t.Errorf("%s: Expected: %#v, Got: %#v", testCase.desc, testCase.expected, update)
|
t.Errorf("%s: Expected: %#v, Got: %#v", testCase.desc, testCase.expected, update)
|
||||||
}
|
}
|
||||||
for i := range update.Pods {
|
for i := range update.Pods {
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -136,7 +135,7 @@ func TestControllerDecode(t *testing.T) {
|
|||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(controller, controllerOut) {
|
if !api.Semantic.DeepEqual(controller, controllerOut) {
|
||||||
t.Errorf("Expected %#v, found %#v", controller, controllerOut)
|
t.Errorf("Expected %#v, found %#v", controller, controllerOut)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,7 +207,7 @@ func TestControllerParsing(t *testing.T) {
|
|||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(controller, expectedController) {
|
if !api.Semantic.DeepEqual(controller, expectedController) {
|
||||||
t.Errorf("Parsing failed: %s %#v %#v", string(data), controller, expectedController)
|
t.Errorf("Parsing failed: %s %#v %#v", string(data), controller, expectedController)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,7 +374,7 @@ func TestFillCurrentState(t *testing.T) {
|
|||||||
if controller.Status.Replicas != 2 {
|
if controller.Status.Replicas != 2 {
|
||||||
t.Errorf("expected 2, got: %d", controller.Status.Replicas)
|
t.Errorf("expected 2, got: %d", controller.Status.Replicas)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(fakeLister.s, labels.Set(controller.Spec.Selector).AsSelector()) {
|
if !api.Semantic.DeepEqual(fakeLister.s, labels.Set(controller.Spec.Selector).AsSelector()) {
|
||||||
t.Errorf("unexpected output: %#v %#v", labels.Set(controller.Spec.Selector).AsSelector(), fakeLister.s)
|
t.Errorf("unexpected output: %#v %#v", labels.Set(controller.Spec.Selector).AsSelector(), fakeLister.s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,7 +448,7 @@ func TestEtcdUpdatePodNotScheduled(t *testing.T) {
|
|||||||
}
|
}
|
||||||
var podOut api.Pod
|
var podOut api.Pod
|
||||||
latest.Codec.DecodeInto([]byte(response.Node.Value), &podOut)
|
latest.Codec.DecodeInto([]byte(response.Node.Value), &podOut)
|
||||||
if !reflect.DeepEqual(podOut, podIn) {
|
if !api.Semantic.DeepEqual(podOut, podIn) {
|
||||||
t.Errorf("expected: %v, got: %v", podOut, podIn)
|
t.Errorf("expected: %v, got: %v", podOut, podIn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -529,7 +529,7 @@ func TestEtcdUpdatePodScheduled(t *testing.T) {
|
|||||||
}
|
}
|
||||||
var podOut api.Pod
|
var podOut api.Pod
|
||||||
latest.Codec.DecodeInto([]byte(response.Node.Value), &podOut)
|
latest.Codec.DecodeInto([]byte(response.Node.Value), &podOut)
|
||||||
if !reflect.DeepEqual(podOut, podIn) {
|
if !api.Semantic.DeepEqual(podOut, podIn) {
|
||||||
t.Errorf("expected: %#v, got: %#v", podOut, podIn)
|
t.Errorf("expected: %#v, got: %#v", podOut, podIn)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,7 +542,7 @@ func TestEtcdUpdatePodScheduled(t *testing.T) {
|
|||||||
t.Fatalf("unexpected error decoding response: %v", err)
|
t.Fatalf("unexpected error decoding response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(list.Items) != 2 || !reflect.DeepEqual(list.Items[0].Spec, podIn.Spec) {
|
if len(list.Items) != 2 || !api.Semantic.DeepEqual(list.Items[0].Spec, podIn.Spec) {
|
||||||
t.Errorf("unexpected container list: %d\n items[0] - %#v\n podin.spec - %#v\n", len(list.Items), list.Items[0].Spec, podIn.Spec)
|
t.Errorf("unexpected container list: %d\n items[0] - %#v\n podin.spec - %#v\n", len(list.Items), list.Items[0].Spec, podIn.Spec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
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 resources has constants and utilities for dealing with resources
|
|
||||||
package resources
|
|
@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
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 resources
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
CPU api.ResourceName = "cpu"
|
|
||||||
Memory api.ResourceName = "memory"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO: None of these currently handle SI units
|
|
||||||
|
|
||||||
func GetFloatResource(resources api.ResourceList, name api.ResourceName, def float64) float64 {
|
|
||||||
value, found := resources[name]
|
|
||||||
if !found {
|
|
||||||
return def
|
|
||||||
}
|
|
||||||
if value.Kind == util.IntstrInt {
|
|
||||||
return float64(value.IntVal)
|
|
||||||
}
|
|
||||||
result, err := strconv.ParseFloat(value.StrVal, 64)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("parsing failed for %s: %s", name, value.StrVal)
|
|
||||||
return def
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetIntegerResource(resources api.ResourceList, name api.ResourceName, def int) int {
|
|
||||||
value, found := resources[name]
|
|
||||||
if !found {
|
|
||||||
return def
|
|
||||||
}
|
|
||||||
if value.Kind == util.IntstrInt {
|
|
||||||
return value.IntVal
|
|
||||||
}
|
|
||||||
result, err := strconv.Atoi(value.StrVal)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("parsing failed for %s: %s", name, value.StrVal)
|
|
||||||
return def
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetStringResource(resources api.ResourceList, name api.ResourceName, def string) string {
|
|
||||||
value, found := resources[name]
|
|
||||||
if !found {
|
|
||||||
return def
|
|
||||||
}
|
|
||||||
if value.Kind == util.IntstrInt {
|
|
||||||
return strconv.Itoa(value.IntVal)
|
|
||||||
}
|
|
||||||
return value.StrVal
|
|
||||||
}
|
|
@ -1,169 +0,0 @@
|
|||||||
/*
|
|
||||||
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 resources
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetInteger(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
res api.ResourceList
|
|
||||||
name api.ResourceName
|
|
||||||
expected int
|
|
||||||
def int
|
|
||||||
test string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
res: api.ResourceList{},
|
|
||||||
name: CPU,
|
|
||||||
expected: 1,
|
|
||||||
def: 1,
|
|
||||||
test: "nothing present",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
res: api.ResourceList{
|
|
||||||
CPU: util.NewIntOrStringFromInt(2),
|
|
||||||
},
|
|
||||||
name: CPU,
|
|
||||||
expected: 2,
|
|
||||||
def: 1,
|
|
||||||
test: "present",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
res: api.ResourceList{
|
|
||||||
Memory: util.NewIntOrStringFromInt(2),
|
|
||||||
},
|
|
||||||
name: CPU,
|
|
||||||
expected: 1,
|
|
||||||
def: 1,
|
|
||||||
test: "not-present",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
res: api.ResourceList{
|
|
||||||
CPU: util.NewIntOrStringFromString("2"),
|
|
||||||
},
|
|
||||||
name: CPU,
|
|
||||||
expected: 2,
|
|
||||||
def: 1,
|
|
||||||
test: "present-string",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
res: api.ResourceList{
|
|
||||||
CPU: util.NewIntOrStringFromString("foo"),
|
|
||||||
},
|
|
||||||
name: CPU,
|
|
||||||
expected: 1,
|
|
||||||
def: 1,
|
|
||||||
test: "present-invalid",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
val := GetIntegerResource(test.res, test.name, test.def)
|
|
||||||
if val != test.expected {
|
|
||||||
t.Errorf("expected: %d found %d", test.expected, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func TestGetFloat(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
res api.ResourceList
|
|
||||||
name api.ResourceName
|
|
||||||
expected float64
|
|
||||||
def float64
|
|
||||||
test string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
res: api.ResourceList{},
|
|
||||||
name: CPU,
|
|
||||||
expected: 1.5,
|
|
||||||
def: 1.5,
|
|
||||||
test: "nothing present",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
res: api.ResourceList{
|
|
||||||
CPU: util.NewIntOrStringFromInt(2),
|
|
||||||
},
|
|
||||||
name: CPU,
|
|
||||||
expected: 2.0,
|
|
||||||
def: 1.5,
|
|
||||||
test: "present",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
res: api.ResourceList{
|
|
||||||
CPU: util.NewIntOrStringFromString("2.5"),
|
|
||||||
},
|
|
||||||
name: CPU,
|
|
||||||
expected: 2.5,
|
|
||||||
def: 1,
|
|
||||||
test: "present-string",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
res: api.ResourceList{
|
|
||||||
CPU: util.NewIntOrStringFromString("foo"),
|
|
||||||
},
|
|
||||||
name: CPU,
|
|
||||||
expected: 1,
|
|
||||||
def: 1,
|
|
||||||
test: "present-invalid",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
val := GetFloatResource(test.res, test.name, test.def)
|
|
||||||
if val != test.expected {
|
|
||||||
t.Errorf("expected: %f found %f", test.expected, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func TestGetString(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
res api.ResourceList
|
|
||||||
name api.ResourceName
|
|
||||||
expected string
|
|
||||||
def string
|
|
||||||
test string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
res: api.ResourceList{},
|
|
||||||
name: CPU,
|
|
||||||
expected: "foo",
|
|
||||||
def: "foo",
|
|
||||||
test: "nothing present",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
res: api.ResourceList{
|
|
||||||
CPU: util.NewIntOrStringFromString("bar"),
|
|
||||||
},
|
|
||||||
name: CPU,
|
|
||||||
expected: "bar",
|
|
||||||
def: "foo",
|
|
||||||
test: "present",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
val := GetStringResource(test.res, test.name, test.def)
|
|
||||||
if val != test.expected {
|
|
||||||
t.Errorf("expected: %s found %s", test.expected, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
||||||
|
@ -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{
|
||||||
|
@ -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,
|
||||||
|
@ -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.MustParse("1000m")},
|
||||||
{CPU: 2000},
|
{CPU: resource.MustParse("2000m")},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cpuAndMemory := api.PodSpec{
|
cpuAndMemory := api.PodSpec{
|
||||||
Containers: []api.Container{
|
Containers: []api.Container{
|
||||||
{CPU: 1000, Memory: 2000},
|
{CPU: resource.MustParse("1000m"), Memory: resource.MustParse("2000")},
|
||||||
{CPU: 2000, Memory: 3000},
|
{CPU: resource.MustParse("2000m"), Memory: resource.MustParse("3000")},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
@ -18,12 +18,12 @@ package standalone
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/clientauth"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/clientauth"
|
||||||
@ -33,7 +33,6 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/config"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/config"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/service"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/service"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
@ -125,22 +124,10 @@ func RunScheduler(cl *client.Client) {
|
|||||||
|
|
||||||
// RunControllerManager starts a controller
|
// RunControllerManager starts a controller
|
||||||
func RunControllerManager(machineList []string, cl *client.Client, nodeMilliCPU, nodeMemory int64) {
|
func RunControllerManager(machineList []string, cl *client.Client, nodeMilliCPU, nodeMemory int64) {
|
||||||
if int64(int(nodeMilliCPU)) != nodeMilliCPU {
|
|
||||||
glog.Warningf("node_milli_cpu is too big for platform. Clamping: %d -> %d",
|
|
||||||
nodeMilliCPU, math.MaxInt32)
|
|
||||||
nodeMilliCPU = math.MaxInt32
|
|
||||||
}
|
|
||||||
|
|
||||||
if int64(int(nodeMemory)) != nodeMemory {
|
|
||||||
glog.Warningf("node_memory is too big for platform. Clamping: %d -> %d",
|
|
||||||
nodeMemory, math.MaxInt32)
|
|
||||||
nodeMemory = math.MaxInt32
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeResources := &api.NodeResources{
|
nodeResources := &api.NodeResources{
|
||||||
Capacity: api.ResourceList{
|
Capacity: api.ResourceList{
|
||||||
resources.CPU: util.NewIntOrStringFromInt(int(nodeMilliCPU)),
|
api.ResourceCPU: *resource.NewMilliQuantity(nodeMilliCPU, resource.DecimalSI),
|
||||||
resources.Memory: util.NewIntOrStringFromInt(int(nodeMemory)),
|
api.ResourceMemory: *resource.NewQuantity(nodeMemory, resource.BinarySI),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
minionController := minionControllerPkg.NewMinionController(nil, "", machineList, nodeResources, cl)
|
minionController := minionControllerPkg.NewMinionController(nil, "", machineList, nodeResources, cl)
|
||||||
|
@ -113,6 +113,14 @@ func (intstr *IntOrString) UnmarshalJSON(value []byte) error {
|
|||||||
return json.Unmarshal(value, &intstr.IntVal)
|
return json.Unmarshal(value, &intstr.IntVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String returns the string value, or Itoa's the int value.
|
||||||
|
func (intstr *IntOrString) String() string {
|
||||||
|
if intstr.Kind == IntstrString {
|
||||||
|
return intstr.StrVal
|
||||||
|
}
|
||||||
|
return strconv.Itoa(intstr.IntVal)
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaller interface.
|
// MarshalJSON implements the json.Marshaller interface.
|
||||||
func (intstr IntOrString) MarshalJSON() ([]byte, error) {
|
func (intstr IntOrString) MarshalJSON() ([]byte, error) {
|
||||||
switch intstr.Kind {
|
switch intstr.Kind {
|
||||||
|
Loading…
Reference in New Issue
Block a user