diff --git a/internal/api/handlers_user.go b/internal/api/handlers_user.go index 4295f47..ff34171 100644 --- a/internal/api/handlers_user.go +++ b/internal/api/handlers_user.go @@ -1145,15 +1145,10 @@ func quantityToMilli(q resource.Quantity) int { return int(q.MilliValue()) } -// quantityToMB converts a K8s resource.Quantity to whole megabytes, rounding up -// (e.g. "4Gi"→4096, "1G"→1000). A zero/unset quantity returns 0. +// quantityToMB converts a K8s resource.Quantity to whole MiB, the MB of the quota +// columns, rounding up so a size between two counts as the larger: "4Gi"→4096, +// "1G"→954. A zero/unset quantity returns 0. func quantityToMB(q resource.Quantity) int { - if q.IsZero() { - return 0 - } - mb := q.Value() / (1024 * 1024) - if mb < 1 { - return 1 - } - return int(mb) + const mib = 1 << 20 + return int((q.Value() + mib - 1) / mib) } diff --git a/internal/api/quantity_test.go b/internal/api/quantity_test.go new file mode 100644 index 0000000..98d64a5 --- /dev/null +++ b/internal/api/quantity_test.go @@ -0,0 +1,31 @@ +package api + +import ( + "testing" + + "k8s.io/apimachinery/pkg/api/resource" +) + +// Sizes reach the quota sums in whole MiB, rounded up: a part-MiB used to be +// dropped, so a server sized in decimal units counted for less than it holds. +func TestQuantityToMB(t *testing.T) { + for _, c := range []struct { + in string + want int + }{ + {"4Gi", 4096}, + {"1Mi", 1}, + {"1G", 954}, // 953.67 MiB + {"1500M", 1431}, // 1430.51 MiB + {"1048577", 2}, // one byte past 1 MiB + {"1", 1}, + {"0", 0}, + } { + if got := quantityToMB(resource.MustParse(c.in)); got != c.want { + t.Errorf("quantityToMB(%s) = %d, want %d", c.in, got, c.want) + } + } + if got := quantityToMB(resource.Quantity{}); got != 0 { + t.Errorf("quantityToMB(unset) = %d, want 0", got) + } +}