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 (
|
||||
"flag"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||
minionControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/controller"
|
||||
replicationControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/controller"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/service"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"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.")
|
||||
machineList util.StringList
|
||||
// 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")
|
||||
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() {
|
||||
@ -90,18 +90,6 @@ func main() {
|
||||
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)
|
||||
|
||||
endpoints := service.NewEndpointController(kubeClient)
|
||||
@ -113,8 +101,8 @@ func main() {
|
||||
cloud := cloudprovider.InitCloudProvider(*cloudProvider, *cloudConfigFile)
|
||||
nodeResources := &api.NodeResources{
|
||||
Capacity: api.ResourceList{
|
||||
resources.CPU: util.NewIntOrStringFromInt(int(*nodeMilliCPU)),
|
||||
resources.Memory: util.NewIntOrStringFromInt(int(*nodeMemory)),
|
||||
api.ResourceCPU: *resource.NewMilliQuantity(*nodeMilliCPU, resource.DecimalSI),
|
||||
api.ResourceMemory: *nodeMemory,
|
||||
},
|
||||
}
|
||||
minionController := minionControllerPkg.NewMinionController(cloud, *minionRegexp, machineList, nodeResources, kubeClient)
|
||||
|
@ -18,6 +18,28 @@ package api
|
||||
|
||||
import (
|
||||
"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
|
||||
|
@ -18,7 +18,6 @@ package latest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
@ -167,7 +166,7 @@ func TestInternalRoundTrip(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(obj, actual) {
|
||||
if !internal.Semantic.DeepEqual(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)
|
||||
)
|
||||
|
||||
// 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.
|
||||
func ParseOrDie(str string) *Quantity {
|
||||
func MustParse(str string) Quantity {
|
||||
q, err := ParseQuantity(str)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot parse '%v': %v", str, err))
|
||||
}
|
||||
return q
|
||||
return *q
|
||||
}
|
||||
|
||||
const (
|
||||
@ -148,7 +148,7 @@ var (
|
||||
// The maximum value we can represent milli-units for.
|
||||
// Compare with the return value of Quantity.Value() to
|
||||
// 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.
|
||||
@ -403,10 +403,7 @@ func (qf qFlag) String() string {
|
||||
// QuantityFlag is a helper that makes a quantity flag (using standard flag package).
|
||||
// Will panic if defaultValue is not a valid quantity.
|
||||
func QuantityFlag(flagName, defaultValue, description string) *Quantity {
|
||||
q, err := ParseQuantity(defaultValue)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("can't use %v as a quantity: %v", defaultValue, err))
|
||||
}
|
||||
flag.Var(qFlag{q}, flagName, description)
|
||||
return q
|
||||
q := MustParse(defaultValue)
|
||||
flag.Var(qFlag{&q}, flagName, description)
|
||||
return &q
|
||||
}
|
||||
|
@ -38,17 +38,17 @@ func ExampleFormat() {
|
||||
// cores = 5300m
|
||||
}
|
||||
|
||||
func ExampleParseOrDie() {
|
||||
memorySize := resource.ParseOrDie("5Gi")
|
||||
func ExampleMustParse() {
|
||||
memorySize := resource.MustParse("5Gi")
|
||||
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)
|
||||
|
||||
cores := resource.ParseOrDie("5300m")
|
||||
cores := resource.MustParse("5300m")
|
||||
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)
|
||||
|
||||
// Output:
|
||||
|
@ -27,12 +27,15 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"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/v1beta2"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
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.")
|
||||
@ -136,6 +139,16 @@ var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
|
||||
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) {
|
||||
@ -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)
|
||||
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)
|
||||
return
|
||||
}
|
||||
@ -170,7 +183,7 @@ func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) {
|
||||
t.Errorf("2: %v: %v", name, err)
|
||||
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)
|
||||
return
|
||||
}
|
||||
@ -244,7 +257,7 @@ func TestEncode_Ptr(t *testing.T) {
|
||||
if _, ok := obj2.(*api.Pod); !ok {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
@ -309,12 +310,12 @@ type Container struct {
|
||||
Ports []Port `json:"ports,omitempty"`
|
||||
Env []EnvVar `json:"env,omitempty"`
|
||||
// Optional: Defaults to unlimited.
|
||||
Memory int `json:"memory,omitempty"`
|
||||
Memory resource.Quantity `json:"memory,omitempty"`
|
||||
// Optional: Defaults to unlimited.
|
||||
CPU int `json:"cpu,omitempty"`
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||
LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty"`
|
||||
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
||||
CPU resource.Quantity `json:"cpu,omitempty"`
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||
LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty"`
|
||||
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
||||
// Optional: Defaults to /dev/termination-log
|
||||
TerminationMessagePath string `json:"terminationMessagePath,omitempty"`
|
||||
// Optional: Default to false.
|
||||
@ -747,9 +748,29 @@ type NodeResources struct {
|
||||
Capacity ResourceList `json:"capacity,omitempty"`
|
||||
}
|
||||
|
||||
// ResourceName is the name identifying various resources in a ResourceList.
|
||||
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
|
||||
// The name of the node according to etcd is in ObjectMeta.Name.
|
||||
|
@ -18,10 +18,13 @@ package v1beta1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
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/util"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -38,7 +41,7 @@ func init() {
|
||||
// newer.Scheme.AddStructFieldConversion(string(""), "Status", string(""), "Condition")
|
||||
// newer.Scheme.AddStructFieldConversion(string(""), "Condition", string(""), "Status")
|
||||
|
||||
newer.Scheme.AddConversionFuncs(
|
||||
err := newer.Scheme.AddConversionFuncs(
|
||||
// TypeMeta must be split into two objects
|
||||
func(in *newer.TypeMeta, out *TypeMeta, s conversion.Scope) error {
|
||||
out.Kind = in.Kind
|
||||
@ -582,5 +585,61 @@ func init() {
|
||||
out.Timestamp = in.Timestamp
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -234,7 +234,7 @@ func TestMinionListConversionToOld(t *testing.T) {
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ type Container struct {
|
||||
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"`
|
||||
// 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.
|
||||
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"`
|
||||
@ -583,6 +583,13 @@ type NodeResources struct {
|
||||
|
||||
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
|
||||
|
||||
// Minion is a worker node in Kubernetenes.
|
||||
|
@ -18,10 +18,13 @@ package v1beta2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
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/util"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -38,7 +41,7 @@ func init() {
|
||||
// newer.Scheme.AddStructFieldConversion(string(""), "Status", string(""), "Condition")
|
||||
// newer.Scheme.AddStructFieldConversion(string(""), "Condition", string(""), "Status")
|
||||
|
||||
newer.Scheme.AddConversionFuncs(
|
||||
err := newer.Scheme.AddConversionFuncs(
|
||||
// TypeMeta must be split into two objects
|
||||
func(in *newer.TypeMeta, out *TypeMeta, s conversion.Scope) error {
|
||||
out.Kind = in.Kind
|
||||
@ -498,5 +501,61 @@ func init() {
|
||||
out.Timestamp = in.Timestamp
|
||||
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"`
|
||||
Env []EnvVar `json:"env,omitempty" description:"list of environment variables to set in the container"`
|
||||
// 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.
|
||||
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"`
|
||||
@ -546,6 +546,13 @@ type NodeResources struct {
|
||||
|
||||
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
|
||||
|
||||
// Minion is a worker node in Kubernetenes.
|
||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package v1beta3
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
@ -326,13 +327,13 @@ type Container struct {
|
||||
WorkingDir string `json:"workingDir,omitempty"`
|
||||
Ports []Port `json:"ports,omitempty"`
|
||||
Env []EnvVar `json:"env,omitempty"`
|
||||
// Optional: Defaults to unlimited.
|
||||
Memory int `json:"memory,omitempty"`
|
||||
// Optional: Defaults to unlimited.
|
||||
CPU int `json:"cpu,omitempty"`
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||
LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty"`
|
||||
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
||||
// Optional: Defaults to unlimited. Units: bytes.
|
||||
Memory resource.Quantity `json:"memory,omitempty"`
|
||||
// Optional: Defaults to unlimited. Units: Cores. (500m == 1/2 core)
|
||||
CPU resource.Quantity `json:"cpu,omitempty"`
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||
LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty"`
|
||||
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
||||
// Optional: Defaults to /dev/termination-log
|
||||
TerminationMessagePath string `json:"terminationMessagePath,omitempty"`
|
||||
// Optional: Default to false.
|
||||
@ -776,9 +777,18 @@ type NodeCondition struct {
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// ResourceName is the name identifying various resources in a ResourceList.
|
||||
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.
|
||||
// The name of the node according to etcd is in ID.
|
||||
|
@ -18,7 +18,6 @@ package validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
@ -429,7 +428,7 @@ func ValidatePodUpdate(newPod, oldPod *api.Pod) errs.ValidationErrorList {
|
||||
newContainers = append(newContainers, container)
|
||||
}
|
||||
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.
|
||||
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 {
|
||||
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"))
|
||||
}
|
||||
|
||||
@ -596,7 +595,7 @@ func ValidateMinionUpdate(oldMinion *api.Node, minion *api.Node) errs.Validation
|
||||
// Clear 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)
|
||||
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/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/capabilities"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
@ -372,8 +373,8 @@ func TestValidateManifest(t *testing.T) {
|
||||
Image: "image",
|
||||
Command: []string{"foo", "bar"},
|
||||
WorkingDir: "/tmp",
|
||||
Memory: 1,
|
||||
CPU: 1,
|
||||
Memory: resource.MustParse("1"),
|
||||
CPU: resource.MustParse("1"),
|
||||
Ports: []api.Port{
|
||||
{Name: "p1", ContainerPort: 80, HostPort: 8080},
|
||||
{Name: "p2", ContainerPort: 81},
|
||||
@ -623,7 +624,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "foo:V1",
|
||||
CPU: 100,
|
||||
CPU: resource.MustParse("100m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -634,7 +635,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Image: "foo:V2",
|
||||
CPU: 1000,
|
||||
CPU: resource.MustParse("1000m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1300,8 +1301,8 @@ func TestValidateMinionUpdate(t *testing.T) {
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
Capacity: api.ResourceList{
|
||||
"cpu": util.NewIntOrStringFromInt(10000),
|
||||
"memory": util.NewIntOrStringFromInt(100),
|
||||
api.ResourceCPU: resource.MustParse("10000"),
|
||||
api.ResourceMemory: resource.MustParse("100"),
|
||||
},
|
||||
},
|
||||
}, api.Node{
|
||||
@ -1310,8 +1311,8 @@ func TestValidateMinionUpdate(t *testing.T) {
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
Capacity: api.ResourceList{
|
||||
"cpu": util.NewIntOrStringFromInt(100),
|
||||
"memory": util.NewIntOrStringFromInt(10000),
|
||||
api.ResourceCPU: resource.MustParse("100"),
|
||||
api.ResourceMemory: resource.MustParse("10000"),
|
||||
},
|
||||
},
|
||||
}, true},
|
||||
@ -1322,8 +1323,8 @@ func TestValidateMinionUpdate(t *testing.T) {
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
Capacity: api.ResourceList{
|
||||
"cpu": util.NewIntOrStringFromInt(10000),
|
||||
"memory": util.NewIntOrStringFromInt(100),
|
||||
api.ResourceCPU: resource.MustParse("10000"),
|
||||
api.ResourceMemory: resource.MustParse("100"),
|
||||
},
|
||||
},
|
||||
}, api.Node{
|
||||
@ -1333,8 +1334,8 @@ func TestValidateMinionUpdate(t *testing.T) {
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
Capacity: api.ResourceList{
|
||||
"cpu": util.NewIntOrStringFromInt(100),
|
||||
"memory": util.NewIntOrStringFromInt(10000),
|
||||
api.ResourceCPU: resource.MustParse("100"),
|
||||
api.ResourceMemory: resource.MustParse("10000"),
|
||||
},
|
||||
},
|
||||
}, true},
|
||||
|
@ -28,9 +28,9 @@ import (
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"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/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"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) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -734,8 +734,8 @@ func TestCreateMinion(t *testing.T) {
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
Capacity: api.ResourceList{
|
||||
resources.CPU: util.NewIntOrStringFromInt(1000),
|
||||
resources.Memory: util.NewIntOrStringFromInt(1024 * 1024),
|
||||
api.ResourceCPU: resource.MustParse("1000m"),
|
||||
api.ResourceMemory: resource.MustParse("1Mi"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -28,13 +28,13 @@ import (
|
||||
"strings"
|
||||
"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"
|
||||
compute "code.google.com/p/google-api-go-client/compute/v1"
|
||||
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"
|
||||
)
|
||||
|
||||
@ -338,11 +338,12 @@ func (gce *GCECloud) List(filter string) ([]string, error) {
|
||||
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{
|
||||
Capacity: api.ResourceList{
|
||||
resources.CPU: util.NewIntOrStringFromInt(int(cpu * 1000)),
|
||||
resources.Memory: util.NewIntOrStringFromInt(int(memory * 1024 * 1024 * 1024)),
|
||||
api.ResourceCPU: *resource.NewMilliQuantity(int64(cpu*1000), resource.DecimalSI),
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
// TODO: actually read machine size instead of this awful hack.
|
||||
switch canonicalizeMachineType(res.MachineType) {
|
||||
case "f1-micro":
|
||||
return makeResources(1, 0.6), nil
|
||||
|
@ -36,8 +36,8 @@ import (
|
||||
"github.com/rackspace/gophercloud/pagination"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
@ -169,11 +169,11 @@ func (os *OpenStack) Instances() (cloudprovider.Instances, bool) {
|
||||
for _, flavor := range flavorList {
|
||||
rsrc := api.NodeResources{
|
||||
Capacity: api.ResourceList{
|
||||
"cpu": util.NewIntOrStringFromInt(flavor.VCPUs),
|
||||
"memory": util.NewIntOrStringFromString(fmt.Sprintf("%dMiB", flavor.RAM)),
|
||||
"openstack.org/disk": util.NewIntOrStringFromString(fmt.Sprintf("%dGB", flavor.Disk)),
|
||||
"openstack.org/rxTxFactor": util.NewIntOrStringFromInt(int(flavor.RxTxFactor * 1000)),
|
||||
"openstack.org/swap": util.NewIntOrStringFromString(fmt.Sprintf("%dMiB", flavor.Swap)),
|
||||
api.ResourceCPU: *resource.NewMilliQuantity(int64(flavor.VCPUs*1000), resource.DecimalSI),
|
||||
api.ResourceMemory: resource.MustParse(fmt.Sprintf("%dMi", flavor.RAM)),
|
||||
"openstack.org/disk": resource.MustParse(fmt.Sprintf("%dG", flavor.Disk)),
|
||||
"openstack.org/rxTxFactor": *resource.NewQuantity(int64(flavor.RxTxFactor*1000), resource.DecimalSI),
|
||||
"openstack.org/swap": resource.MustParse(fmt.Sprintf("%dMi", flavor.Swap)),
|
||||
},
|
||||
}
|
||||
flavor_to_resource[flavor.ID] = &rsrc
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@ -233,7 +232,7 @@ func TestCreateReplica(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %#v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(&expectedPod, actualPod) {
|
||||
if !api.Semantic.DeepEqual(&expectedPod, actualPod) {
|
||||
t.Logf("Body: %s", fakeHandler.RequestBody)
|
||||
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
|
||||
received := make(chan struct{})
|
||||
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)
|
||||
}
|
||||
close(received)
|
||||
|
@ -22,15 +22,28 @@ import (
|
||||
|
||||
func TestEqualities(t *testing.T) {
|
||||
e := Equalities{}
|
||||
type Bar struct {
|
||||
X int
|
||||
}
|
||||
type Baz struct {
|
||||
Y Bar
|
||||
}
|
||||
err := e.AddFuncs(
|
||||
func(a, b int) bool {
|
||||
return a+1 == b
|
||||
},
|
||||
func(a, b Bar) bool {
|
||||
return a.X*10 == b.X
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected: %v", err)
|
||||
}
|
||||
|
||||
type Foo struct {
|
||||
X int
|
||||
}
|
||||
|
||||
table := []struct {
|
||||
a, b interface{}
|
||||
equal bool
|
||||
@ -38,6 +51,10 @@ func TestEqualities(t *testing.T) {
|
||||
{1, 2, true},
|
||||
{2, 1, false},
|
||||
{"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{}, map[string]int(nil), true},
|
||||
{[]int{}, []int(nil), true},
|
||||
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||
package config
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"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 {
|
||||
// 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))
|
||||
if len(pods) == 0 {
|
||||
return kubelet.PodUpdate{newPods, op, source}
|
||||
}
|
||||
for i := range pods {
|
||||
newPods[i] = pods[i]
|
||||
}
|
||||
@ -89,7 +82,7 @@ func expectPodUpdate(t *testing.T, ch <-chan kubelet.PodUpdate, expected ...kube
|
||||
for i := range expected {
|
||||
update := <-ch
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
@ -130,7 +129,7 @@ func TestReadFromFile(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -171,7 +170,7 @@ func TestExtractFromValidDataFile(t *testing.T) {
|
||||
}
|
||||
update := (<-ch).(kubelet.PodUpdate)
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -192,7 +191,7 @@ func TestExtractFromEmptyDir(t *testing.T) {
|
||||
|
||||
update := (<-ch).(kubelet.PodUpdate)
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -242,7 +241,7 @@ func TestExtractFromDir(t *testing.T) {
|
||||
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, pods...)
|
||||
sort.Sort(sortedPods(update.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)
|
||||
}
|
||||
for i := range update.Pods {
|
||||
|
@ -19,7 +19,6 @@ package config
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -193,7 +192,7 @@ func TestExtractFromHTTP(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
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)
|
||||
}
|
||||
for i := range update.Pods {
|
||||
|
@ -398,7 +398,7 @@ func makePortsAndBindings(container *api.Container) (map[docker.Port]struct{}, m
|
||||
return exposedPorts, portBindings
|
||||
}
|
||||
|
||||
func milliCPUToShares(milliCPU int) int {
|
||||
func milliCPUToShares(milliCPU int64) int64 {
|
||||
if milliCPU == 0 {
|
||||
// zero milliCPU means unset. Use kernel default.
|
||||
return 0
|
||||
@ -537,8 +537,8 @@ func (kl *Kubelet) runContainer(pod *api.BoundPod, container *api.Container, pod
|
||||
ExposedPorts: exposedPorts,
|
||||
Hostname: pod.Name,
|
||||
Image: container.Image,
|
||||
Memory: int64(container.Memory),
|
||||
CPUShares: int64(milliCPUToShares(container.CPU)),
|
||||
Memory: container.Memory.Value(),
|
||||
CPUShares: milliCPUToShares(container.CPU.MilliValue()),
|
||||
WorkingDir: container.WorkingDir,
|
||||
},
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@ -136,7 +135,7 @@ func TestControllerDecode(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -208,7 +207,7 @@ func TestControllerParsing(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -375,7 +374,7 @@ func TestFillCurrentState(t *testing.T) {
|
||||
if controller.Status.Replicas != 2 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -448,7 +448,7 @@ func TestEtcdUpdatePodNotScheduled(t *testing.T) {
|
||||
}
|
||||
var podOut api.Pod
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -529,7 +529,7 @@ func TestEtcdUpdatePodScheduled(t *testing.T) {
|
||||
}
|
||||
var podOut api.Pod
|
||||
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)
|
||||
}
|
||||
|
||||
@ -542,7 +542,7 @@ func TestEtcdUpdatePodScheduled(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
@ -89,15 +88,15 @@ type ResourceFit struct {
|
||||
}
|
||||
|
||||
type resourceRequest struct {
|
||||
milliCPU int
|
||||
memory int
|
||||
milliCPU int64
|
||||
memory int64
|
||||
}
|
||||
|
||||
func getResourceRequest(pod *api.Pod) resourceRequest {
|
||||
result := resourceRequest{}
|
||||
for ix := range pod.Spec.Containers {
|
||||
result.memory += pod.Spec.Containers[ix].Memory
|
||||
result.milliCPU += pod.Spec.Containers[ix].CPU
|
||||
result.memory += pod.Spec.Containers[ix].Memory.Value()
|
||||
result.milliCPU += pod.Spec.Containers[ix].CPU.MilliValue()
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -113,17 +112,16 @@ func (r *ResourceFit) PodFitsResources(pod api.Pod, existingPods []api.Pod, node
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
milliCPURequested := 0
|
||||
memoryRequested := 0
|
||||
milliCPURequested := int64(0)
|
||||
memoryRequested := int64(0)
|
||||
for ix := range existingPods {
|
||||
existingRequest := getResourceRequest(&existingPods[ix])
|
||||
milliCPURequested += existingRequest.milliCPU
|
||||
memoryRequested += existingRequest.memory
|
||||
}
|
||||
|
||||
// TODO: convert to general purpose resource matching, when pods ask for resources
|
||||
totalMilliCPU := int(resources.GetFloatResource(info.Spec.Capacity, resources.CPU, 0) * 1000)
|
||||
totalMemory := resources.GetIntegerResource(info.Spec.Capacity, resources.Memory, 0)
|
||||
totalMilliCPU := info.Spec.Capacity.Get(api.ResourceCPU).MilliValue()
|
||||
totalMemory := info.Spec.Capacity.Get(api.ResourceMemory).Value()
|
||||
|
||||
fitsCPU := totalMilliCPU == 0 || (totalMilliCPU-milliCPURequested) >= podRequest.milliCPU
|
||||
fitsMemory := totalMemory == 0 || (totalMemory-memoryRequested) >= podRequest.memory
|
||||
|
@ -21,8 +21,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
)
|
||||
|
||||
type FakeNodeInfo api.Node
|
||||
@ -32,17 +31,11 @@ func (n FakeNodeInfo) GetNodeInfo(nodeName string) (*api.Node, error) {
|
||||
return &node, nil
|
||||
}
|
||||
|
||||
func makeResources(milliCPU int, memory int) api.NodeResources {
|
||||
func makeResources(milliCPU int64, memory int64) api.NodeResources {
|
||||
return api.NodeResources{
|
||||
Capacity: api.ResourceList{
|
||||
resources.CPU: util.IntOrString{
|
||||
IntVal: milliCPU,
|
||||
Kind: util.IntstrInt,
|
||||
},
|
||||
resources.Memory: util.IntOrString{
|
||||
IntVal: memory,
|
||||
Kind: util.IntstrInt,
|
||||
},
|
||||
api.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI),
|
||||
api.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -51,8 +44,8 @@ func newResourcePod(usage ...resourceRequest) api.Pod {
|
||||
containers := []api.Container{}
|
||||
for _, req := range usage {
|
||||
containers = append(containers, api.Container{
|
||||
Memory: req.memory,
|
||||
CPU: req.milliCPU,
|
||||
Memory: *resource.NewQuantity(req.memory, resource.BinarySI),
|
||||
CPU: *resource.NewMilliQuantity(req.milliCPU, resource.DecimalSI),
|
||||
})
|
||||
}
|
||||
return api.Pod{
|
||||
|
@ -18,13 +18,12 @@ package scheduler
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// the unused capacity is calculated on a scale of 0-10
|
||||
// 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 {
|
||||
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)
|
||||
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.
|
||||
// 'pods' is a list of pods currently scheduled on the node.
|
||||
func calculateOccupancy(pod api.Pod, node api.Node, pods []api.Pod) HostPriority {
|
||||
totalCPU := 0
|
||||
totalMemory := 0
|
||||
totalMilliCPU := int64(0)
|
||||
totalMemory := int64(0)
|
||||
for _, existingPod := range pods {
|
||||
for _, container := range existingPod.Spec.Containers {
|
||||
totalCPU += container.CPU
|
||||
totalMemory += container.Memory
|
||||
totalMilliCPU += container.CPU.MilliValue()
|
||||
totalMemory += container.Memory.Value()
|
||||
}
|
||||
}
|
||||
// Add the resources requested by the current pod being scheduled.
|
||||
// This also helps differentiate between differently sized, but empty, minions.
|
||||
for _, container := range pod.Spec.Containers {
|
||||
totalCPU += container.CPU
|
||||
totalMemory += container.Memory
|
||||
totalMilliCPU += container.CPU.MilliValue()
|
||||
totalMemory += container.Memory.Value()
|
||||
}
|
||||
|
||||
cpuScore := calculateScore(totalCPU, resources.GetIntegerResource(node.Spec.Capacity, resources.CPU, 0), node.Name)
|
||||
memoryScore := calculateScore(totalMemory, resources.GetIntegerResource(node.Spec.Capacity, resources.Memory, 0), node.Name)
|
||||
glog.V(4).Infof("Least Requested Priority, AbsoluteRequested: (%d, %d) Score:(%d, %d)", totalCPU, totalMemory, cpuScore, memoryScore)
|
||||
capacityMilliCPU := node.Spec.Capacity.Get(api.ResourceCPU).MilliValue()
|
||||
capacityMemory := node.Spec.Capacity.Get(api.ResourceMemory).Value()
|
||||
|
||||
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{
|
||||
host: node.Name,
|
||||
|
@ -21,17 +21,16 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
)
|
||||
|
||||
func makeMinion(node string, cpu, memory int) api.Node {
|
||||
func makeMinion(node string, milliCPU, memory int64) api.Node {
|
||||
return api.Node{
|
||||
ObjectMeta: api.ObjectMeta{Name: node},
|
||||
Spec: api.NodeSpec{
|
||||
Capacity: api.ResourceList{
|
||||
resources.CPU: util.NewIntOrStringFromInt(cpu),
|
||||
resources.Memory: util.NewIntOrStringFromInt(memory),
|
||||
api.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI),
|
||||
api.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -57,14 +56,14 @@ func TestLeastRequested(t *testing.T) {
|
||||
}
|
||||
cpuOnly := api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{CPU: 1000},
|
||||
{CPU: 2000},
|
||||
{CPU: resource.MustParse("1000m")},
|
||||
{CPU: resource.MustParse("2000m")},
|
||||
},
|
||||
}
|
||||
cpuAndMemory := api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{CPU: 1000, Memory: 2000},
|
||||
{CPU: 2000, Memory: 3000},
|
||||
{CPU: resource.MustParse("1000m"), Memory: resource.MustParse("2000")},
|
||||
{CPU: resource.MustParse("2000m"), Memory: resource.MustParse("3000")},
|
||||
},
|
||||
}
|
||||
tests := []struct {
|
||||
|
@ -18,12 +18,12 @@ package standalone
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/clientauth"
|
||||
@ -33,7 +33,6 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/config"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/resources"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/service"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
@ -125,22 +124,10 @@ func RunScheduler(cl *client.Client) {
|
||||
|
||||
// RunControllerManager starts a controller
|
||||
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{
|
||||
Capacity: api.ResourceList{
|
||||
resources.CPU: util.NewIntOrStringFromInt(int(nodeMilliCPU)),
|
||||
resources.Memory: util.NewIntOrStringFromInt(int(nodeMemory)),
|
||||
api.ResourceCPU: *resource.NewMilliQuantity(nodeMilliCPU, resource.DecimalSI),
|
||||
api.ResourceMemory: *resource.NewQuantity(nodeMemory, resource.BinarySI),
|
||||
},
|
||||
}
|
||||
minionController := minionControllerPkg.NewMinionController(nil, "", machineList, nodeResources, cl)
|
||||
|
@ -113,6 +113,14 @@ func (intstr *IntOrString) UnmarshalJSON(value []byte) error {
|
||||
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.
|
||||
func (intstr IntOrString) MarshalJSON() ([]byte, error) {
|
||||
switch intstr.Kind {
|
||||
|
Loading…
Reference in New Issue
Block a user