Skip to content

fix(resources-management): stop aborting the rendering on a valid quantity - #218

Merged
Suselz merged 2 commits into
mainfrom
fix-quantity-parsing-regression
Sep 21, 2026
Merged

Suselz merged 2 commits into
mainfrom
fix-quantity-parsing-regression

Conversation

@Suselz

@Suselz Suselz commented Sep 21, 2026

Copy link
Copy Markdown
Member

What is broken

#217, released as 1.72.23, gave helm_lib_resources_management_cpu_units_to_millicores a fail
branch it never had and narrowed both helpers to two regexes. The Kubernetes quantity grammar is
wider than those regexes, so a valid quantity now aborts the rendering of the whole chart:

cpu "+1"     FAIL   was 1000          <- rendered correctly before
cpu "-1"     FAIL   was -1000
cpu "1."     FAIL   was 0
cpu "100u"   FAIL   was 0
cpu "100n"   FAIL   was 0
cpu "1k"     FAIL   was 0
mem "+1Gi"   FAIL   was 1073741824
mem "abcGi"  FAIL   was 0

A CRD that validates a quantity with the standard pattern accepts every one of them — a leading
sign, a trailing dot, and the n, u, k, M, G suffixes are all part of it — and there is no
Quantity canonicalization on the way to the template, so the value arrives verbatim.

+1 is the sharp case. It produced the right number before and takes the release down now, which
is the same class of failure #217 set out to remove, reached through a different input and from a
shared helper rather than one module.

Found in review of deckhouse/deckhouse#23170 by @AlwxSin, who measured the CPU cases. The two
memory cases are the same defect in the other helper.

What this pull request changes

Both helpers now parse the grammar they are given: an optional sign, a decimal mantissa with either
side of the point optional, a decimal exponent, and the n, u, m, k, M, G, T, P, E
and Ki...Ei suffixes. Exact integer arithmetic still covers an integer mantissa, so no value
changes the result it has today.

Nothing that used to produce a number aborts any more:

cpu "+1"     -> 1000        cpu "0.5"    -> 500
cpu "-1"     -> -1000       cpu "500m"   -> 500
cpu "1."     -> 1000        cpu "2"      -> 2000
cpu "100u"   -> 1           cpu "abc"    -> 0
cpu "100n"   -> 1           mem "+1Gi"   -> 1073741824
cpu "1k"     -> 1000000     mem "abcGi"  -> 0

An unparsable CPU value yields 0 as it did before 1.72.23. A memory value carrying a known
suffix and an unparsable mantissa does the same. The fail of the memory helper is reached only by
a value that carries neither a known suffix nor a number.

The helpers convert, they do not validate. A negative quantity comes back as a negative number, as
it always did, and a result that does not fit an int64 comes back as 0. Rejecting either belongs
to the caller — the doc comments say so.

The memory helper also gained the n, u and m branches it was missing, so 100m, 100n and
100u convert instead of aborting, and both helpers check the int64 range before converting, so
1E, 1Ei and 10P on the CPU path come back as 0 rather than saturated or wrapped.

Verification

helm unittest ./tests — 420 tests pass. The two helper suites gained a case per quantity form,
including the sign, the trailing dot, the exponent and every suffix.

helm_lib_resources_management_original_pod_resources gained the assertion that was missing when
the zero was introduced, and which would have caught it:

- equal: {path: result_fractional_limits_cpu, value: "750m"}   # 0.5 cores * 1.5
- equal: {path: result_fractional_requests_cpu, value: "0.5"}

Until now that suite only asserted the rendered block was non-empty, which a limits.cpu: 0m
against requests.cpu: 0.5 satisfies.

Release

The chart version is bumped to 1.72.24. The platform picks it up through
make update-lib-helm version=1.72.24. deckhouse/deckhouse#23170 carries the 1.72.23 bump today
and has to move to 1.72.24 before it merges, so that a patch release does not ship the abort.

…ntity

1.72.23 gave the CPU helper a `fail` branch it never had and narrowed both
helpers to two regexes. Anything outside them now aborts the rendering of the
whole chart, and the Kubernetes quantity grammar is wider than those regexes:

    cpu "+1"    FAIL, was 1000   -- rendered correctly before
    cpu "-1"    FAIL, was -1000
    cpu "1."    FAIL, was 0
    cpu "100u"  FAIL, was 0
    cpu "100n"  FAIL, was 0
    cpu "1k"    FAIL, was 0
    mem "+1Gi"  FAIL, was 1073741824
    mem "abcGi" FAIL, was 0

A CRD that validates a quantity with the standard pattern accepts every one of
them, and there is no canonicalization on the way to the template, so the value
arrives verbatim. `+1` is the sharp case: it produced the right number before
and takes the release down now.

Both helpers now parse the grammar they are given: an optional sign, a decimal
mantissa with either side of the point optional, a decimal exponent, and the
n, u, m, k, M, G, T, P, E and Ki...Ei suffixes. Exact integer arithmetic still
covers an integer mantissa, so no value changes its result.

Nothing that used to produce a number aborts any more. An unparsable CPU value
yields 0 as it did before 1.72.23, and a memory value with a known suffix and an
unparsable mantissa does the same. The `fail` of the memory helper survives only
where it already was, on a value carrying no suffix and no digits.

The tests gained a case per quantity form, and
`helm_lib_resources_management_original_pod_resources` gained the assertion that
was missing when the zero was introduced: a fractional `vpa.cpu.min` with a
`limitRatio` has to size the limits, not collapse them below the requests.

Signed-off-by: suselz <suselz@mail.ru>
Comment thread charts/helm_lib/templates/_resources_management.tpl
Comment thread charts/helm_lib/templates/_resources_management.tpl Outdated
Comment thread tests/tests/helm_lib_resources_management_cpu_units_to_millicores_test.yaml Outdated
Comment thread tests/tests/helm_lib_resources_management_cpu_units_to_millicores_test.yaml Outdated
…int64 conversion

Review of the previous commit found two cases it missed and one claim it got
wrong.

The memory helper never gained the n, u and m branches its CPU sibling did, so
`100m`, `100n` and `100u` fell through to the `fail`. All three are valid
Kubernetes quantities, and the commit message claimed the `fail` was reachable
only by "a value carrying no suffix and no digits", which `100m` plainly
contradicts. The branches are there now and the claim holds.

Putting the k...E and Ki...Ei suffixes on the CPU path made a result of 10^18
cores expressible, and in millicores it no longer fits an int64. `1E`, `1Ei`
and `10P` came back saturated at the int64 maximum, or wrapped negative on
another toolchain; either way the caller got a limit the API server rejects
where the value used to be 0. Both helpers now check the range before the
conversion and return 0 outside it, which is what these inputs did before the
suffixes were added.

The doc comments state what the helpers promise: they convert, they do not
validate. A negative quantity comes back negative, an out-of-range one comes
back as 0, and rejecting either belongs to the caller. The test that asserts
the sign says so too, rather than reading as an endorsement of a negative
limit.

The assertions that were reflowed into flow style are back in the block style
of the file, so the diff carries additions only.

Signed-off-by: suselz <suselz@mail.ru>
@Suselz Suselz self-assigned this Sep 21, 2026
@Suselz
Suselz marked this pull request as ready for review September 21, 2026 14:52
@Suselz
Suselz merged commit 59c26d0 into main Sep 21, 2026
4 checks passed
Suselz added a commit to deckhouse/deckhouse that referenced this pull request Sep 21, 2026
deckhouse/lib-helm#218 restores the quantity helpers that `1.72.23` narrowed.
That release aborted the rendering on a quantity the standard Kubernetes pattern
accepts — `+1`, `1.`, `100u`, `1k` for CPU, `100m` and `+1Gi` for memory — where
the code before it returned a number. It also put the `E` and `Ei` suffixes on
the CPU path, where the result no longer fits an int64 and came back saturated.

Both helpers now parse the full grammar, keep exact integer arithmetic for an
integer mantissa, and return 0 rather than aborting or overflowing. Nothing this
repository renders today changes: the template tests of `istio` and `cni-cilium`,
the two modules that reach these helpers through `resourcesManagement`, pass
unchanged.

The `user-authn` module does not call the helpers any more, so the bump carries
nothing for it beyond keeping the vendored chart current.

Signed-off-by: suselz <suselz@mail.ru>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants