mirror of https://github.com/k3s-io/k3s
Wire resource.Quantity into api
parent
3b5c3ec786
commit
894a3e6d3f
|
@ -27,16 +27,28 @@ 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/conversion"
|
||||
"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.")
|
||||
|
||||
// apiObjectComparer can do semantic deep equality checks for api objects.
|
||||
var apiObjectComparer = conversion.EqualitiesOrDie(
|
||||
func(a, b resource.Quantity) bool {
|
||||
// Ignore formatting, only care that numeric value stayed the same.
|
||||
return a.Amount.Cmp(b.Amount) == 0
|
||||
},
|
||||
)
|
||||
|
||||
// apiObjectFuzzer can randomly populate api objects.
|
||||
var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
|
||||
func(j *runtime.PluginBase, c fuzz.Continue) {
|
||||
|
@ -136,6 +148,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 +181,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 !apiObjectComparer.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 +192,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 !apiObjectComparer.DeepEqual(source, obj3) {
|
||||
t.Errorf("3: %v: diff: %v\nCodec: %v", name, util.ObjectDiff(source, obj3), codec)
|
||||
return
|
||||
}
|
||||
|
@ -244,7 +266,7 @@ func TestEncode_Ptr(t *testing.T) {
|
|||
if _, ok := obj2.(*api.Pod); !ok {
|
||||
t.Fatalf("Got wrong type")
|
||||
}
|
||||
if !reflect.DeepEqual(obj2, pod) {
|
||||
if !apiObjectComparer.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,9 +310,9 @@ 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"`
|
||||
CPU resource.Quantity `json:"cpu,omitempty"`
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||
LivenessProbe *LivenessProbe `json:"livenessProbe,omitempty"`
|
||||
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,10 +327,10 @@ 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"`
|
||||
// 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"`
|
||||
|
@ -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.
|
||||
|
|
|
@ -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