feat: support compose resource limits (legacy keys and deploy.resources)#34
Merged
Conversation
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.
Summary
Convert compose CPU/memory resource limits to podman
runflags, both forms: the legacy top-level service keys and the moderndeploy.resourcesblock. When both forms set the same flag, conversion refuses loudly rather than guessing a precedence the compose spec leaves undefined.Design:
planning/changes/2026-07-11.02-resource-limits.md. This closes the last flat-mappable Bucket B item from the coverage audit.Legacy keys (registry entries)
All flags verified against
podman-run.1. A new_number_scalarfactory (accepts int/float/string, rejectsbool) backs 12 keys;oom_kill_disableuses_bool:mem_limit→--memory,memswap_limit→--memory-swap,mem_reservation→--memory-reservation,mem_swappiness→--memory-swappiness,cpus→--cpus,cpu_shares→--cpu-shares,cpu_quota→--cpu-quota,cpu_period→--cpu-period,cpuset→--cpuset-cpus,pids_limit→--pids-limit,shm_size→--shm-size,oom_score_adj→--oom-score-adj,oom_kill_disable→--oom-kill-disable.Values pass through unchanged (a bare int
mem_limitis bytes;"512m"carries a unit; a${VAR}stays live at run time, via the same_Expand/to_shellpath every scalar uses). Because these areSERVICE_KEYSregistry entries, the existingparsing/emitloops wire them into validation and emission with no bespoke code.deploy.resources (new
resources.py)deploybecomes a structural key; onlydeploy.resourcesis honored (otherdeploysubkeys —replicas/placement/… — are refused, per the audit's swarm-key rejection).limits.cpus/memory/pids→--cpus/--memory/--pids-limit;reservations.memory→--memory-reservation.reservations.cpusandreservations.deviceshave no clean podman flag and are refused.Refuse on conflict
The four flags reachable from both forms —
mem_limit/limits.memory,cpus/limits.cpus,pids_limit/limits.pids,mem_reservation/reservations.memory— refuse loudly when both are set on a service. A single_LIMITStable drives both conflict detection and emission, so no flag can be emitted without being conflict-checked.Non-goals
blkio_configand the Windows-onlycpu_count/cpu_percentremain rejected.Testing
just test-ciat 100% coverage (328 tests),just lint-ciclean,just check-planningOK.tests/test_resources.pycovers eachdeploy.resourcesfield, every refusal, all four conflict pairs, and empty-block no-ops; legacy-key emission and value-type validation are intest_emit.py/test_parsing.py; the supported-keys snapshot is updated.architecture/supported-subset.mdgains a## Resource limitssection (and its stale_Expand-fields enumeration was corrected for the new keys).An adversarial whole-branch review confirmed value passthrough introduces no new shell-injection surface (
mem_limit: "$(touch x)"is escaped byto_shell, identical to every other scalar). Two review Minors were fixed in this branch: emptylimits:/reservations:YAML blocks are now no-ops (matchingdeploy:null/resources:nulland theulimits/pull_policyprecedent), and the numeric-check predicate is shared betweenkeys.pyandresources.py.