Skip to content

promote: drop-in fixes (default network, restart any→always, quadlet CPU/tmpfs, NOTICE)#425

Merged
Jaro-c merged 5 commits into
mainfrom
develop
Jun 17, 2026
Merged

promote: drop-in fixes (default network, restart any→always, quadlet CPU/tmpfs, NOTICE)#425
Jaro-c merged 5 commits into
mainfrom
develop

Conversation

@Jaro-c

@Jaro-c Jaro-c commented Jun 17, 2026

Copy link
Copy Markdown
Member

Promote verified develop fixes to main (merge, no tag — not a release; tag is cut later when releasing).

Brings to main:

All merged to develop individually with CI green + unit/integration tests. No public API change (bug fixes); no version bump, no release.

Jaro-c added 5 commits June 17, 2026 05:24
## What

The Apache-2.0 `NOTICE` file named `podman-compose` instead of `podup`:

```
-podman-compose
+podup
 Copyright 2026 Glyndor
```

## Why

Leftover from the relicense template (introduced in the Apache-2.0
relicense commit). The NOTICE file must attribute *this* project, not an
unrelated tool. It is a public-facing attribution file required by
Apache-2.0 §4(d).

## Scope

One line. No code change. Targets `develop`.

Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com>
…rks: block (#421)

Fixes the P1 in #417 (empirically confirmed on Podman 5.4.2).

## Problem

docker-compose attaches every service that declares neither `networks:`
nor `network_mode` to an implicit `<project>_default` network, so
services resolve each other by name out of the box. podup created such
services with **no network namespace at all** — they got no IP and could
not reach each other — and `up` exited 0 with no warning. The common
no-`networks:`-block compose file silently produced mutually-unreachable
containers.

## Fix

`normalize_default_network` runs on the parsed file at the
`-f`/`COMPOSE_FILE` entry point (`parse_files_with_env_files`, the path
that feeds the engine, `config`, and `quadlet`): any service with
neither `networks:` nor `network_mode` is attached to a `default`
network, created as `{project}_default` (DNS-enabled) unless the file
defines a top-level `networks.default` (whose config is then respected).
Idempotent; `parse_str` deliberately stays un-normalized for unit tests.

The `run` one-off path now also calls `create_networks` so it can attach
to the synthesized default (matching `docker compose run`).

## Verification (real Podman 5.4.2, rootless, netavark)

Before: two-service file, no `networks:` block →
`NetworkSettings.Networks = null`, no IP, `getent hosts <service>`
fails.
After: services land on `{project}_default`, `getent hosts <service>`
resolves, sibling reachable by service name.

- New integration test
`sibling_resolves_service_by_name_without_networks_block` (goes through
the real normalized entry point).
- 4 unit tests: bare service attached; explicit `networks:` untouched;
`network_mode` skipped; user-defined `default` config respected.
- Full `cargo test --all-features` green; `cargo fmt --check` and `cargo
clippy --all-features --all-targets` clean.

## Note

`config` output now canonically includes `networks: default:` for such
files, matching `docker compose config`.

Refs #417 (close on merge to develop).

Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com>
…422)

Addresses item 1 of #418.

## Problem
`deploy.restart_policy.condition: any` (and the unset default) means
"restart under any circumstance" per the compose spec — docker-compose
maps it to `always`. podup mapped it to `unless-stopped`, which silently
skips restarts after an explicit stop. Behavioral divergence.

## Fix
Map `any` (and the unset default) → `always`. Unknown conditions still
fall back to `unless-stopped`. One-line change in `build_restart_policy`
+ 2 unit tests (`condition: any` and unset default both → `always`).

`cargo test --lib restart_policy` green (13 tests); fmt + clippy clean.

## Scope
#418 bundles three divergences; this PR handles **only the restart
mapping** (clean, safe, unit-testable). The other two are deliberately
deferred:
- healthcheck `wait_healthy` ignoring `start_period`/`interval` —
couples with #420 (server-side `wait?condition=healthy`); better done
together against `health.rs`.
- single-replica `-1` naming suffix — a convention change with broad
impact; needs a deliberate decision (change vs document).

Refs #418 (keep open for the remaining two items).

Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com>
Closes #408.

## Problem
`generate quadlet` silently dropped **all** CPU limits (`cpus`,
`cpuset`, `cpu_shares`, `cpu_quota`, `cpu_period`) — neither emitted nor
warned — while `mem_limit`/`pids_limit` were honored. Inconsistent and
surprising: an operator's `cpus: "2"` had no effect in the generated
unit.

## Fix
CPU has no native `[Container]` Quadlet key in Podman 5.x (unlike
`Memory=`/`PidsLimit=`), so route it through `PodmanArgs=`, mirroring
the existing `--memory` handling. `cpus` falls back to
`deploy.resources.limits.cpus`.

## Verification
Real `podup generate quadlet` on a service with
`cpus`/`cpuset`/`cpu_shares` now emits:
```
PodmanArgs=--cpus=1.5
PodmanArgs=--cpuset-cpus=0,1
PodmanArgs=--cpu-shares=512
```
Unit tests cover the five service-level keys and the deploy fallback.
`cargo fmt`/`clippy` clean.

## Note
`internal/quadlet/unit.rs` is now at 490/500 lines. The broader quadlet
sweep (#419) will need to split this file to stay under the line-limit
gate.

Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com>
First fix from #419.

## Problem
A long-form volume with `type: tmpfs` went through the generic `Volume=`
path, which Quadlet treats as a persistent named/anonymous volume —
silently inverting an in-memory tmpfs into durable storage. (Top-level
`tmpfs:` shorthand was already correct.)

## Fix
`render_tmpfs_mount` (in `render.rs`, which has line-budget headroom)
detects a long-form `type: tmpfs` mount and the container builder routes
it to `Tmpfs=<target>[:size=,mode=]`, mirroring the runtime mount
options (mode rendered octal, matching `volume_mounts`).

Unit test asserts `Tmpfs=/cache:size=…,mode=755` is emitted and
`Volume=/cache` is not.

## Note — #419 stays open
The remaining #419 items (ipv4/ipv6_address → `IP=`/`IP6=`,
`network_mode: none` → `Network=none`, security `label=filetype/nested`,
network/volume `ipam`/`driver_opts`/custom-`name`, the `PodmanArgs=`
fallback class + `warnings.rs` coverage) require adding to
`network_unit`/`volume_unit`/`container_unit`.
**`internal/quadlet/unit.rs` is at 496/500**, so that work must first
split the file (e.g. extract `network_unit`/`volume_unit` into their own
module). Deferred to a follow-up PR.

Refs #419.

Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.com>
@Jaro-c Jaro-c merged commit 4416590 into main Jun 17, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant