Skip to content

feat: support compose resource limits (legacy keys and deploy.resources)#34

Merged
lesnik512 merged 5 commits into
mainfrom
feat/resource-limits
Jul 11, 2026
Merged

feat: support compose resource limits (legacy keys and deploy.resources)#34
lesnik512 merged 5 commits into
mainfrom
feat/resource-limits

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Summary

Convert compose CPU/memory resource limits to podman run flags, both forms: the legacy top-level service keys and the modern deploy.resources block. 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_scalar factory (accepts int/float/string, rejects bool) backs 12 keys; oom_kill_disable uses _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_limit is bytes; "512m" carries a unit; a ${VAR} stays live at run time, via the same _Expand/to_shell path every scalar uses). Because these are SERVICE_KEYS registry entries, the existing parsing/emit loops wire them into validation and emission with no bespoke code.

deploy.resources (new resources.py)

deploy becomes a structural key; only deploy.resources is honored (other deploy subkeys — replicas/placement/… — are refused, per the audit's swarm-key rejection). limits.cpus/memory/pids--cpus/--memory/--pids-limit; reservations.memory--memory-reservation. reservations.cpus and reservations.devices have 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 _LIMITS table drives both conflict detection and emission, so no flag can be emitted without being conflict-checked.

Non-goals

blkio_config and the Windows-only cpu_count/cpu_percent remain rejected.

Testing

just test-ci at 100% coverage (328 tests), just lint-ci clean, just check-planning OK. tests/test_resources.py covers each deploy.resources field, every refusal, all four conflict pairs, and empty-block no-ops; legacy-key emission and value-type validation are in test_emit.py/test_parsing.py; the supported-keys snapshot is updated. architecture/supported-subset.md gains a ## Resource limits section (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 by to_shell, identical to every other scalar). Two review Minors were fixed in this branch: empty limits:/reservations: YAML blocks are now no-ops (matching deploy:null/resources:null and the ulimits/pull_policy precedent), and the numeric-check predicate is shared between keys.py and resources.py.

@lesnik512 lesnik512 merged commit 9ce3624 into main Jul 11, 2026
6 checks passed
@lesnik512 lesnik512 deleted the feat/resource-limits branch July 11, 2026 11:27
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.

1 participant