Skip to content

Commit ea48395

Browse files
Fix precision of cpu to millicore and memory to bytes
1 parent b33f606 commit ea48395

File tree

2 files changed

+66
-16
lines changed

2 files changed

+66
-16
lines changed

pkg/quota/admission/clusterresourceoverride/admission.go

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ const (
2626
)
2727

2828
var (
29-
zeroDec = inf.NewDec(0, 0)
29+
zeroDec = inf.NewDec(0, 0)
30+
miDec = inf.NewDec(1024*1024, 0)
31+
cpuFloor = resource.MustParse("1m")
32+
memFloor = resource.MustParse("1Mi")
3033
)
3134

3235
func init() {
@@ -153,24 +156,37 @@ func (a *clusterResourceOverridePlugin) Admit(attr admission.Attributes) error {
153156
resources := container.Resources
154157
memLimit, memFound := resources.Limits[kapi.ResourceMemory]
155158
if memFound && a.config.memoryRequestToLimitRatio.Cmp(zeroDec) != 0 {
156-
resources.Requests[kapi.ResourceMemory] = resource.Quantity{
157-
Amount: multiply(memLimit.Amount, a.config.memoryRequestToLimitRatio),
158-
Format: resource.BinarySI,
159+
// memory is measured in whole bytes.
160+
// the plugin rounds up to the nearest MiB rather than bytes to improve ease of use for end-users.
161+
amount := multiply(memLimit.Amount, a.config.memoryRequestToLimitRatio)
162+
roundDownToNearestMi := multiply(divide(amount, miDec, 0, inf.RoundDown), miDec)
163+
value := resource.Quantity{Amount: roundDownToNearestMi, Format: resource.BinarySI}
164+
if memFloor.Cmp(value) > 0 {
165+
value = *(memFloor.Copy())
159166
}
167+
resources.Requests[kapi.ResourceMemory] = value
160168
}
161169
if memFound && a.config.limitCPUToMemoryRatio.Cmp(zeroDec) != 0 {
162-
resources.Limits[kapi.ResourceCPU] = resource.Quantity{
163-
// float math is necessary here as there is no way to create an inf.Dec to represent cpuBaseScaleFactor < 0.001
164-
Amount: multiply(inf.NewDec(int64(float64(memLimit.Value())*cpuBaseScaleFactor), 3), a.config.limitCPUToMemoryRatio),
165-
Format: resource.DecimalSI,
170+
// float math is necessary here as there is no way to create an inf.Dec to represent cpuBaseScaleFactor < 0.001
171+
// cpu is measured in millicores, so we need to scale and round down the value to nearest millicore scale
172+
amount := multiply(inf.NewDec(int64(float64(memLimit.Value())*cpuBaseScaleFactor), 3), a.config.limitCPUToMemoryRatio)
173+
amount.Round(amount, 3, inf.RoundDown)
174+
value := resource.Quantity{Amount: amount, Format: resource.DecimalSI}
175+
if cpuFloor.Cmp(value) > 0 {
176+
value = *(cpuFloor.Copy())
166177
}
178+
resources.Limits[kapi.ResourceCPU] = value
167179
}
168180
cpuLimit, cpuFound := resources.Limits[kapi.ResourceCPU]
169181
if cpuFound && a.config.cpuRequestToLimitRatio.Cmp(zeroDec) != 0 {
170-
resources.Requests[kapi.ResourceCPU] = resource.Quantity{
171-
Amount: multiply(cpuLimit.Amount, a.config.cpuRequestToLimitRatio),
172-
Format: resource.DecimalSI,
182+
// cpu is measured in millicores, so we need to scale and round down the value to nearest millicore scale
183+
amount := multiply(cpuLimit.Amount, a.config.cpuRequestToLimitRatio)
184+
amount.Round(amount, 3, inf.RoundDown)
185+
value := resource.Quantity{Amount: amount, Format: resource.DecimalSI}
186+
if cpuFloor.Cmp(value) > 0 {
187+
value = *(cpuFloor.Copy())
173188
}
189+
resources.Requests[kapi.ResourceCPU] = value
174190
}
175191
}
176192
glog.V(5).Infof("%s: pod limits after overrides are: %#v", api.PluginName, pod.Spec.Containers[0].Resources)
@@ -180,3 +196,7 @@ func (a *clusterResourceOverridePlugin) Admit(attr admission.Attributes) error {
180196
func multiply(x *inf.Dec, y *inf.Dec) *inf.Dec {
181197
return inf.NewDec(0, 0).Mul(x, y)
182198
}
199+
200+
func divide(x *inf.Dec, y *inf.Dec, s inf.Scale, r inf.Rounder) *inf.Dec {
201+
return inf.NewDec(0, 0).QuoRound(x, y, s, r)
202+
}

pkg/quota/admission/clusterresourceoverride/admission_test.go

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,23 @@ func TestLimitRequestAdmission(t *testing.T) {
130130
namespace *kapi.Namespace
131131
}{
132132
{
133-
name: "this thing even runs",
133+
name: "ignore pods that have no memory limit specified",
134134
config: testConfig(100, 50, 50),
135-
object: testPod("0", "0", "0", "0"),
135+
object: testBestEffortPod(),
136136
expectedMemRequest: resource.MustParse("0"),
137137
expectedCpuLimit: resource.MustParse("0"),
138138
expectedCpuRequest: resource.MustParse("0"),
139139
namespace: fakeNamespace(true),
140140
},
141+
{
142+
name: "test floor for memory and cpu",
143+
config: testConfig(100, 50, 50),
144+
object: testPod("1Mi", "0", "0", "0"),
145+
expectedMemRequest: resource.MustParse("1Mi"),
146+
expectedCpuLimit: resource.MustParse("1m"),
147+
expectedCpuRequest: resource.MustParse("1m"),
148+
namespace: fakeNamespace(true),
149+
},
141150
{
142151
name: "nil config",
143152
config: nil,
@@ -184,12 +193,21 @@ func TestLimitRequestAdmission(t *testing.T) {
184193
namespace: fakeNamespace(true),
185194
},
186195
{
187-
name: "little values don't get lost",
196+
name: "little values mess things up",
188197
config: testConfig(500, 10, 10),
189198
object: testPod("1.024Mi", "0", "0", "0"),
190-
expectedMemRequest: resource.MustParse(".0001Gi"),
199+
expectedMemRequest: resource.MustParse("1Mi"),
191200
expectedCpuLimit: resource.MustParse("5m"),
192-
expectedCpuRequest: resource.MustParse(".5m"),
201+
expectedCpuRequest: resource.MustParse("1m"),
202+
namespace: fakeNamespace(true),
203+
},
204+
{
205+
name: "test fractional memory requests round up",
206+
config: testConfig(500, 10, 60),
207+
object: testPod("512Mi", "0", "0", "0"),
208+
expectedMemRequest: resource.MustParse("307Mi"),
209+
expectedCpuLimit: resource.MustParse("2.5"),
210+
expectedCpuRequest: resource.MustParse("250m"),
193211
namespace: fakeNamespace(true),
194212
},
195213
}
@@ -231,6 +249,18 @@ func TestLimitRequestAdmission(t *testing.T) {
231249
}
232250
}
233251

252+
func testBestEffortPod() *kapi.Pod {
253+
return &kapi.Pod{
254+
Spec: kapi.PodSpec{
255+
Containers: []kapi.Container{
256+
{
257+
Resources: kapi.ResourceRequirements{},
258+
},
259+
},
260+
},
261+
}
262+
}
263+
234264
func testPod(memLimit string, memRequest string, cpuLimit string, cpuRequest string) *kapi.Pod {
235265
return &kapi.Pod{
236266
Spec: kapi.PodSpec{

0 commit comments

Comments
 (0)