Accept fractional component limits on the ordering and limit-change paths - #94
Open
thomasbergernz wants to merge 1 commit into
Open
thomasbergernz wants to merge 1 commit into
thomasbergernz wants to merge 1 commit into
Conversation
…aths Every limit field is DictField(child=IntegerField()), so a fractional limit can only ever reach a resource through the provider set_limits action, whose serializer uses a plain JSONField. Ordering one, changing one from the UI, renewing with one or reallocating one all return "A valid integer is required". That matters for storage components measured in TiB, where a sub-TiB allocation is legitimate — a free-tier quota of 0.1 TiB cannot be expressed as an integer, so it can be provisioned by an operator but never requested by a customer. LimitValueField widens the six limit fields while keeping the stored shape: whole numbers come back as int, so a limit of 5 still serialises as 5 rather than 5.0 and existing payloads are byte-identical. It is a FloatField rather than DecimalField deliberately — Order.limits and Resource.limits are JSONFields written with the stdlib encoder, and a Decimal raises at save time. QuotasUpdateSerializer.quotas is left alone; quotas are counts, not measures. The client half is waldur/waldur-homeport#105 — without it the forms still parse every limit input with parseInt, so the widened API is unreachable from the UI.
This was referenced Sep 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Every component limit field is
DictField(child=IntegerField()), so a fractional limit can only ever reach a resource through the providerset_limitsaction, whose serializer uses a plainJSONField. Ordering one, changing one from the UI, renewing with one, or reallocating one all return"A valid integer is required".That matters for storage components measured in TiB, where a sub-TiB allocation is legitimate: a free-tier quota of 0.1 TiB has no integer representation. Today it can be provisioned by an operator but never requested by a customer — and the asymmetry is also why the two billing bugs in this area went unnoticed for so long, since
set_limitswas the only door a fraction could come through.Change
LimitValueFieldwidens the six limit fields:BaseOrderSerializerlimitsResourceRenewSerializerlimitsRenewalEstimateRequestSerializerlimitsResourceUpdateLimitsSerializerlimitsResourceReallocateTargetSerializerallocated_limitsResourceReallocateLimitsSerializerlimitsIt keeps the stored shape: whole numbers come back as
int, so a limit of 5 still serialises as 5 rather than 5.0 and existing payloads are byte-identical.FloatFieldrather thanDecimalFieldis deliberate —Order.limitsandResource.limitsare JSONFields written with the stdlib encoder, and aDecimalraises at save time. The billing path coerces toDecimalat the point of arithmetic instead, which is what 595327d does.QuotasUpdateSerializer.quotasis left alone; quotas are counts, not measures. Read-only report serializers are untouched.Verified
Against DRF:
0.1and"0.1"become0.1(float);2and2.0become2(int);"abc"is rejected;min_value=0still rejects-0.5.Built on 8.1.2 and run in a test deployment: an order carrying
storage_project: 0.1reachesdoneand the resource stores{"cpu": 2000, "storage_project": 0.1, "storage_scratch": 2}— typesint,float,int.Related
parseInt, so this widened API is unreachable from the UI. The two are only useful together.TypeErrorfrom set_limits raises TypeError (HTTP 500) for a fractional limit when the resource already has invoice items #91. Both should land before fractional limits are reachable by customers, or the wider API will produce wrong invoices rather than errors.Licensing: I agree to license this contribution under the MIT license.