From 989457d673ebfa32b97f8b9a466c471bd67a9c19 Mon Sep 17 00:00:00 2001 From: joseph Date: Tue, 1 Sep 2026 14:09:26 +0000 Subject: [PATCH 1/3] =?UTF-8?q?Plan=2000091:=20create=20plan=20=E2=80=94?= =?UTF-8?q?=20demote=20rootful=20Docker=20from=20core=20to=20optional=20(p?= =?UTF-8?q?odman-first);=20Refs=20#41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- .../JOURNAL/00091-Journal-26-09-01.md | 64 ++++++++++++++++++ .../PLAN.md | 65 +++++++++++++++++++ CLAUDE/Plan/README.md | 2 + .../{ => optional/common}/play-docker.yml | 0 4 files changed, 131 insertions(+) create mode 100644 CLAUDE/Plan/00091-podman-first-docker-optional/JOURNAL/00091-Journal-26-09-01.md create mode 100644 CLAUDE/Plan/00091-podman-first-docker-optional/PLAN.md rename playbooks/imports/{ => optional/common}/play-docker.yml (100%) diff --git a/CLAUDE/Plan/00091-podman-first-docker-optional/JOURNAL/00091-Journal-26-09-01.md b/CLAUDE/Plan/00091-podman-first-docker-optional/JOURNAL/00091-Journal-26-09-01.md new file mode 100644 index 00000000..7f4ad63f --- /dev/null +++ b/CLAUDE/Plan/00091-podman-first-docker-optional/JOURNAL/00091-Journal-26-09-01.md @@ -0,0 +1,64 @@ +# Plan 00091 — Journal 26-09-01 + +> **Append-only activity log** for plan 00091. One file per day +> (`00091-Journal-YY-MM-DD.md`). `PLAN.md` tracks the plan (what/why, +> current state, tasks); this journal tracks what actually *happened* — +> findings, decisions, dead-ends, hand-off state — the linear lifecycle a plan +> document structurally cannot carry. +> +> **Entry grammar** — append new entries at the BOTTOM; NEVER edit earlier +> entries (corrections are new entries): +> +> ``` +> ## HH:MM · category · REF — optional short title +> ``` +> +> - `HH:MM` local 24h (the date is in the filename); times increase down the file. +> - `category` ∈ `action` | `finding` | `decision` | `thought` | `blocker` | `handoff` +> - `REF` = optional task/phase ref (`T1.2`, `P1`) or `—`. +> - Bodies may embed fenced logs/diffs/snippets — no size limit — with a +> one-line takeaway above the fence. +> - End a working session with a `handoff` entry so the next agent's entry +> point is the last entry of the newest day-file. + +## 14:02 · action · — — plan scaffolded + +Plan 00091 created via `mkplan.bash`; `JOURNAL/` initialised. Next: +fill in `PLAN.md`, then log progress here as it happens. + +## 14:03 · action · — — issue filed + +Tracking issue created: https://github.com/LongTermSupport/fedora-desktop/issues/41 +(rootful Docker core import vs podman-first hosts; docker-ce-cli conflicts with +podman-docker; remaining coexistence concerns tracked there). + +## 14:06 · action · T1.1 T1.2 — demotion implemented + +- `git mv playbooks/imports/play-docker.yml playbooks/imports/optional/common/play-docker.yml`; + import removed from `playbook-main.yml`. +- `play-lxc-install-config.yml`: replaced the hard "Docker must be installed first" assert + with a `/usr/bin/dockerd` presence probe (`docker_daemon_check`). Chose `dockerd`, not + `/usr/bin/docker`, because `podman-docker` also ships `/usr/bin/docker` — the probe must + detect the rootful engine, not the CLI shim. All five Docker-coexistence tasks + (DOCKER-USER assert, reconcile script deploy, immediate apply, systemd unit deploy, + unit enable) now condition on it. Fail-fast preserved: with dockerd on disk but no + DOCKER-USER chain the assert still aborts (half-configured Docker), pointing at the + optional play. +- Fixed a `partial-become` ansible-lint fatal on the lxc-bash block (`become_user` + without same-level `become`) — behaviourally a no-op (play is `become: true`). + +## 14:07 · decision · — — server-recommended.bundle: no docker, no change + +The bundle lists neither `play-docker.yml` nor `play-ddev.yml`, so podman-first is already +coherent there: DDEV users opt in explicitly to both. No bundle change. + +## 14:08 · finding · T2.1 — menu discovery is automatic + +Both the interactive optional menu and headless `RUN_BASH_OPTIONAL_PLAYBOOKS` discover plays +via `find playbooks/imports/optional…`, so the moved `play-docker.yml` appears with no +run.bash change. Docs/refs updated: play-ddev fix messages, playbooks.md (section moved to +optional catalog), architecture.md, README.md, installation.md, configuration.md, ddev.md, +containerization.md, ContainerEngines.md. `CLAUDE/PlanWorkflow.md`'s mention is an +illustrative example in a daemon-deployed doc — left untouched. QA: qa-ansible-syntax, +qa-ansible, qa-patterns, qa-discovery all pass; qa-docs fails only on pre-existing +`.claude/rules/*` links to a missing daemon doc (unrelated to this plan). diff --git a/CLAUDE/Plan/00091-podman-first-docker-optional/PLAN.md b/CLAUDE/Plan/00091-podman-first-docker-optional/PLAN.md new file mode 100644 index 00000000..85d4d5a7 --- /dev/null +++ b/CLAUDE/Plan/00091-podman-first-docker-optional/PLAN.md @@ -0,0 +1,65 @@ +# Plan 00091: podman first docker optional + +**Status**: In Progress +**Created**: 2026-09-01 +**Owner**: joseph +**Priority**: Medium + +## Overview + +The repo's own container-engine policy (CLAUDE/ContainerEngines.md) is "Podman first, Docker +only for compatibility (e.g. DDEV)", yet `playbooks/playbook-main.yml` imports +`playbooks/imports/play-docker.yml` as a core, non-optional play. On a podman-first host that +carries `podman-docker` (the `docker` CLI shim — e.g. a headless podman-only CI host), the +`docker-ce-cli` package conflict makes the main playbook unable to converge at all. + +This plan demotes rootful Docker from core to optional per the owner's direction: move +`play-docker.yml` to `playbooks/imports/optional/common/`, drop its import from +`playbook-main.yml`, and make `play-lxc-install-config.yml`'s Docker-coexistence handling +conditional on Docker actually being present (fail-fast is preserved for hosts with Docker +half-configured). The env-var opt-out of PR #40 (`RUN_BASH_SKIP_DOCKER`) is superseded and +that PR is closed. Remaining coexistence concerns are tracked in issue #41 (Refs #41). + +## Goals + +- `playbook-main.yml` converges on a podman-only host (no Docker CE install attempted). +- `play-docker.yml` remains fully functional as an optional play, discovered by both the + interactive menu and headless `RUN_BASH_OPTIONAL_PLAYBOOKS`. +- `play-lxc-install-config.yml` works on hosts with and without Docker, with no error hiding. +- Docs and CLAUDE topic files describe Docker as optional; no functional reference to the old + core path remains. + +## Non-Goals + +- Removing Docker support or the DDEV workflow (DDEV still requires rootful Docker). +- Adding `play-docker.yml` (or `play-ddev.yml`) to `server-recommended.bundle` — the bundle + stays podman-first; DDEV users opt in explicitly. +- Solving the wider coexistence problems (podman-docker assertion, docker-group containment) + — tracked in issue #41. + +## Tasks + +### Phase 1: Demotion + +- [x] ✅ **Task 1.1**: `git mv playbooks/imports/play-docker.yml playbooks/imports/optional/common/play-docker.yml`; remove the import from `playbook-main.yml`. +- [x] ✅ **Task 1.2**: Make `play-lxc-install-config.yml` Docker-conditional: probe Docker presence; when present, keep the fail-fast DOCKER-USER assertion and reconcile tasks; when absent, skip the Docker-coexistence block (lxc-net's own FORWARD/MASQUERADE rules suffice without Docker). + +### Phase 2: References + +- [x] ✅ **Task 2.1**: Update all functional references to the old path (play-ddev.yml fix messages, docs/installation.md, docs/ddev.md, docs/playbooks.md, docs/architecture.md, docs/containerization.md, docs/configuration.md, docs/README.md, CLAUDE/ContainerEngines.md). + +### Phase 3: QA and PR + +- [x] ✅ **Task 3.1**: Run the repo QA (`scripts/qa-all.bash` relevant gates) and fix findings. +- [ ] 🔄 **Task 3.2**: Push branch, open PR (Refs #41), close PR #40 as superseded. + +## Success Criteria + +- [ ] `ansible-playbook --syntax-check` passes for `playbook-main.yml` and the moved play. +- [ ] No functional reference to `playbooks/imports/play-docker.yml` remains outside + historical plan folders. +- [ ] PR open with rationale, migration notes, and bundle decision; PR #40 closed. + +## Delivery & Milestones + +- Issue: https://github.com/LongTermSupport/fedora-desktop/issues/41 diff --git a/CLAUDE/Plan/README.md b/CLAUDE/Plan/README.md index d619b4e5..677c4a10 100644 --- a/CLAUDE/Plan/README.md +++ b/CLAUDE/Plan/README.md @@ -34,6 +34,8 @@ Use these Unicode icons in plan documents: ## Active Plans +- [00091-podman-first-docker-optional](00091-podman-first-docker-optional/) - Demote rootful Docker from core to optional (podman-first); Refs #41 + - [004-comprehensive-feature-documentation](004-comprehensive-feature-documentation/) - Documentation for all major features (CCY, CCB, Nord, Speech-to-Text, etc.) - [007-speech-to-text-resource-leak-fixes](007-speech-to-text-resource-leak-fixes/) - Fix microphone resource leak, transcription truncation, and browser paste failures diff --git a/playbooks/imports/play-docker.yml b/playbooks/imports/optional/common/play-docker.yml similarity index 100% rename from playbooks/imports/play-docker.yml rename to playbooks/imports/optional/common/play-docker.yml From 67ee5a566b98cd0430979560cb986e351a831ebc Mon Sep 17 00:00:00 2001 From: joseph Date: Tue, 1 Sep 2026 14:09:34 +0000 Subject: [PATCH 2/3] =?UTF-8?q?Plan=2000091:=20podman-first=20=E2=80=94=20?= =?UTF-8?q?Docker=20optional;=20LXC=20play=20adapts=20to=20Docker=20presen?= =?UTF-8?q?ce;=20Refs=20#41?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the play-docker.yml import from playbook-main.yml (the play itself moved to imports/optional/common/ in the previous commit). play-lxc-install-config.yml now probes /usr/bin/dockerd (not /usr/bin/docker, which podman-docker also ships) and conditions the whole DOCKER-USER coexistence block on it: Docker hosts keep the fail-fast chain assertion, podman-only hosts skip it. Update all functional references and docs to the optional path; server-recommended.bundle unchanged (it lists neither docker nor ddev — already podman-first coherent). Co-Authored-By: Claude Fable 5 --- CLAUDE/ContainerEngines.md | 23 ++++-- docs/README.md | 5 +- docs/architecture.md | 38 +++++----- docs/configuration.md | 7 +- docs/containerization.md | 5 +- docs/ddev.md | 5 +- docs/installation.md | 8 +- docs/playbooks.md | 36 ++++----- .../imports/optional/common/play-ddev.yml | 6 +- playbooks/imports/play-lxc-install-config.yml | 75 ++++++++++--------- playbooks/playbook-main.yml | 8 +- 11 files changed, 117 insertions(+), 99 deletions(-) diff --git a/CLAUDE/ContainerEngines.md b/CLAUDE/ContainerEngines.md index e3f83def..f363b4b2 100644 --- a/CLAUDE/ContainerEngines.md +++ b/CLAUDE/ContainerEngines.md @@ -8,13 +8,20 @@ This repo sets up three container technologies. They are not interchangeable — ## The role split -| Engine | Mode | Role | Installed by | -| ---------- | ------------ | ---------------------------------------------------------------- | ----------------------------------------------- | -| **Podman** | **rootless** | Default container engine for everything. Daily use. | `playbooks/imports/play-podman.yml` | -| **Docker** | **rootful** | Compatibility mode for tools that require full Docker semantics. | `playbooks/imports/play-docker.yml` | -| **LXC** | rootful | Full-system, VM-like containers with systemd inside. | `playbooks/imports/play-lxc-install-config.yml` | - -All three are installed by `playbook-main.yml`. They coexist cleanly — different sockets, different storage, different networking stacks. See "Coexistence" below. +| Engine | Mode | Role | Installed by | +| ---------- | ------------ | ---------------------------------------------------------------- | -------------------------------------------------------------- | +| **Podman** | **rootless** | Default container engine for everything. Daily use. | `playbooks/imports/play-podman.yml` | +| **Docker** | **rootful** | Compatibility mode for tools that require full Docker semantics. | `playbooks/imports/optional/common/play-docker.yml` (optional) | +| **LXC** | rootful | Full-system, VM-like containers with systemd inside. | `playbooks/imports/play-lxc-install-config.yml` | + +Podman and LXC are installed by `playbook-main.yml`. Docker is **optional** — consistent with +this document's own policy, a compatibility-only engine is not a core component: install it +explicitly (interactive optional menu, or `RUN_BASH_OPTIONAL_PLAYBOOKS` headless) only on hosts +that need it, e.g. for DDEV. A further reason it cannot be core: `docker-ce-cli` package-conflicts +with `podman-docker` (the `docker` CLI shim), so a core Docker import makes `playbook-main.yml` +unable to converge on a podman-only host that carries the shim. When installed, the engines +coexist cleanly — different sockets, different storage, different networking stacks. See +"Coexistence" below. ## Podman — the default, use this first @@ -143,5 +150,5 @@ Yes — once, to pick up the new `docker` group membership. Log out and back in, - `CLAUDE/Plan/Completed/033-ddev-installation/container-engine-strategy.md` — the decision-gate analysis that led to this split - `vars/container-defaults.yml` — the `container_engine` default - `playbooks/imports/play-podman.yml` — Podman setup -- `playbooks/imports/play-docker.yml` — Docker setup +- `playbooks/imports/optional/common/play-docker.yml` — Docker setup (optional) - `playbooks/imports/play-lxc-install-config.yml` — LXC setup diff --git a/docs/README.md b/docs/README.md index 425a1daa..5abb8f75 100644 --- a/docs/README.md +++ b/docs/README.md @@ -178,9 +178,8 @@ ansible desktop -m setup | grep ansible_distribution ```bash cd ~/Projects/fedora-desktop -# Docker is installed automatically by the main playbook (rootful, core) -# To re-run it manually: -ansible-playbook playbooks/imports/play-docker.yml +# Install rootful Docker (optional — needed for DDEV; Podman is the default engine) +ansible-playbook playbooks/imports/optional/common/play-docker.yml # Install Distrobox ansible-playbook playbooks/imports/optional/common/play-distrobox.yml diff --git a/docs/architecture.md b/docs/architecture.md index 7a5ee7f7..17018232 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -106,28 +106,30 @@ The bootstrap script: 14. **play-rpm-fusion.yml**: Third-party repository setup 15. **play-browsers.yml**: Additional browser setup 16. **play-toolbox-install.yml**: JetBrains Toolbox -17. **play-docker.yml**: Rootful Docker (compatibility engine for DDEV) -18. **play-lxc-install-config.yml**: LXC container support - - **Ordering constraint**: LXC runs _after_ Docker so the `DOCKER-USER` - iptables chain exists when LXC reconciles outbound connectivity. - See the "Reconcile iptables" block in `play-lxc-install-config.yml`. -19. **play-podman.yml**: Rootless Podman (default container engine) -20. **play-python.yml**: Python/pyenv setup -21. **play-claude-yolo.yml**: CCY (Claude container wrapper) installation +17. **play-lxc-install-config.yml**: LXC container support + - Rootful Docker is optional (`imports/optional/common/play-docker.yml`, + podman-first policy). On Docker hosts, run Docker _before_ this play so + the `DOCKER-USER` iptables chain exists when LXC reconciles outbound + connectivity; on podman-only hosts the Docker-coexistence block is + skipped. See the "Reconcile iptables" block in + `play-lxc-install-config.yml`. +18. **play-podman.yml**: Rootless Podman (default container engine) +19. **play-python.yml**: Python/pyenv setup +20. **play-claude-yolo.yml**: CCY (Claude container wrapper) installation - **Ordering constraint**: CCY must run _before_ `play-claude-code.yml` because the `cc` wrapper sources CCY lib files at runtime, and `play-claude-code.yml` asserts the lib is present before deploying it. See `CLAUDE/Plan/00048-cc-token-source-parity`. -22. **play-claude-code.yml**: Claude Code CLI and `cc` wrapper -23. **play-comms.yml**: Communication applications -24. **play-gnome-shell.yml**: GNOME Shell configuration -25. **play-gnome-shell-extensions.yml**: GNOME Shell extensions -26. **play-markless.yml**: Markless tool setup -27. **play-terminal-emulators.yml**: Terminal emulator configuration -28. **play-vscode.yml**: Visual Studio Code -29. **play-vpn.yml**: VPN configuration -30. **play-gsettings.yml**: GNOME settings -31. **play-ZZ-repo-cleanup.yml**: Post-run repository cleanup +21. **play-claude-code.yml**: Claude Code CLI and `cc` wrapper +22. **play-comms.yml**: Communication applications +23. **play-gnome-shell.yml**: GNOME Shell configuration +24. **play-gnome-shell-extensions.yml**: GNOME Shell extensions +25. **play-markless.yml**: Markless tool setup +26. **play-terminal-emulators.yml**: Terminal emulator configuration +27. **play-vscode.yml**: Visual Studio Code +28. **play-vpn.yml**: VPN configuration +29. **play-gsettings.yml**: GNOME settings +30. **play-ZZ-repo-cleanup.yml**: Post-run repository cleanup ### Desktop or server — the `provisioning_profile` / `scope` pair diff --git a/docs/configuration.md b/docs/configuration.md index a711756a..83e636e4 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -124,10 +124,11 @@ Bash Git Prompt with Solarized theme in: These plays are imported by `playbook-main.yml` and run automatically on every provisioning run — there is nothing to enable. -### Docker +### Docker (optional — not imported by the main playbook) -`play-docker.yml` installs Docker as a **rootful** compatibility engine (Podman remains -the rootless default — see [Container Engines](../CLAUDE/ContainerEngines.md)): +`playbooks/imports/optional/common/play-docker.yml` installs Docker as a **rootful** +compatibility engine when a tool needs it (e.g. DDEV). Podman remains the rootless +default — see [Container Engines](../CLAUDE/ContainerEngines.md): - User added to the `docker` group - Systemd service enabled diff --git a/docs/containerization.md b/docs/containerization.md index faa4cf9e..9fa23a34 100644 --- a/docs/containerization.md +++ b/docs/containerization.md @@ -159,10 +159,11 @@ Docker is an application containerization platform designed for packaging, distr ### Installation -Installed automatically by the main playbook (`playbooks/imports/play-docker.yml` is a core import of `playbook-main.yml`). To run it standalone: +**Optional** — not imported by `playbook-main.yml` (podman-first policy; Docker is a +compatibility engine, e.g. for DDEV). Install it via the optional play: ```bash -ansible-playbook playbooks/imports/play-docker.yml +ansible-playbook playbooks/imports/optional/common/play-docker.yml ``` Configuration details: diff --git a/docs/ddev.md b/docs/ddev.md index bdaaa289..1ad69854 100644 --- a/docs/ddev.md +++ b/docs/ddev.md @@ -13,10 +13,11 @@ This installs: - **mkcert** — local HTTPS certificate authority (bundled with the DDEV RPM; Fedora's standalone `mkcert` package is removed first because it conflicts file-for-file) - **DDEV** — via the official yum repository at `pkg.ddev.com` -**Prerequisite:** Rootful Docker must be installed first: +**Prerequisite:** Rootful Docker must be installed first (it is an optional play — +podman-first policy): ```bash -ansible-playbook playbooks/imports/play-docker.yml +ansible-playbook playbooks/imports/optional/common/play-docker.yml ``` This installs Docker CE as a system-wide daemon and adds your user to the `docker` group. After the first run you must **log out and back in** (or run `newgrp docker` in your shell) before `docker` commands work without `sudo`. diff --git a/docs/installation.md b/docs/installation.md index 8c17f5a9..0dd8a932 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -220,8 +220,9 @@ The main playbook installs and configures: Must be run manually after main playbook. See [Playbooks Reference](playbooks.md#optional-playbooks) for the complete catalog. -**Note:** Docker (rootful) is installed automatically by the main playbook via -`playbooks/imports/play-docker.yml` — it is a core component, not optional. See +**Note:** Docker (rootful) is **optional** — the main playbook does not install it. +Podman is the default container engine; install Docker only when a tool needs it for +compatibility (e.g. DDEV) via `playbooks/imports/optional/common/play-docker.yml`. See `CLAUDE/ContainerEngines.md` for the Podman-first / Docker-for-compatibility policy. Popular optional components: @@ -229,6 +230,9 @@ Popular optional components: ```bash cd ~/Projects/fedora-desktop +# Docker (rootful compatibility engine — required for DDEV) +ansible-playbook playbooks/imports/optional/common/play-docker.yml + # Distrobox ansible-playbook playbooks/imports/optional/common/play-distrobox.yml diff --git a/docs/playbooks.md b/docs/playbooks.md index bcddc7a3..ce434729 100644 --- a/docs/playbooks.md +++ b/docs/playbooks.md @@ -55,7 +55,7 @@ so running one on its own auto-detects and cleanly no-ops on a server: ansible-playbook playbooks/imports/play-firefox.yml # runs fully on a desktop; ends immediately (guard) on a server -ansible-playbook playbooks/imports/play-docker.yml +ansible-playbook playbooks/imports/play-podman.yml # general play — runs on both desktop and server ``` @@ -283,20 +283,6 @@ gh-personal issue list - Downloads and installs JetBrains Toolbox - Configures desktop integration -### play-docker.yml - -**Purpose**: Docker container platform (rootful — compatibility engine for DDEV)\ -**Actions**: - -- Removes any previous rootless Docker setup (legacy cleanup) -- Adds Docker CE repository -- Installs Docker CE and tools -- Configures rootful system daemon (`docker.service` / `docker.socket`) -- Adds user to `docker` group (root-equivalent; deliberate for DDEV compatibility) -- See [Containerization Guide](containerization.md) for rootful vs rootless rationale - -> **Note**: Docker runs as a rootful system daemon. `docker` group membership is root-equivalent by design. See `CLAUDE/ContainerEngines.md` for the full security trade-off analysis. - ### play-lxc-install-config.yml **Purpose**: LXC full-system containers\ @@ -307,7 +293,7 @@ gh-personal issue list - Configures container networking - Sets up SSH configuration for containers - Configures firewall rules -- Runs **after** `play-docker.yml` so the DOCKER-USER iptables chain exists before LXC reconciles outbound connectivity +- Detects rootful Docker: on Docker hosts it reconciles the DOCKER-USER iptables chain for LXC outbound connectivity (run the optional `play-docker.yml` first); on podman-only hosts the Docker-coexistence block is skipped ### play-podman.yml @@ -678,9 +664,25 @@ Build and install darktable RPM with AI features (USE_AI=ON): DDEV local development environment: - Installs DDEV for PHP/WordPress/Drupal local dev -- Requires rootful Docker (`play-docker.yml` — core) +- Requires rootful Docker (run the optional `play-docker.yml` first) - See [docs/ddev.md](ddev.md) for full setup guide +#### play-docker.yml + +Docker container platform (rootful — compatibility engine for DDEV). Optional under the +podman-first policy (`CLAUDE/ContainerEngines.md`): Podman is the default engine, and +`docker-ce-cli` package-conflicts with `podman-docker`, so hosts choose one `docker` CLI +provider. + +- Removes any previous rootless Docker setup (legacy cleanup) +- Adds Docker CE repository; installs Docker CE and tools +- Configures rootful system daemon (`docker.service` / `docker.socket`) +- Adds user to `docker` group (root-equivalent by design; deliberate for DDEV compatibility — + see `CLAUDE/ContainerEngines.md` for the security trade-off analysis) +- On LXC hosts, run it before `play-lxc-install-config.yml` so the DOCKER-USER chain is + reconciled for LXC outbound connectivity +- See [Containerization Guide](containerization.md) for rootful vs rootless rationale + #### play-disk-reclaim.yml Disk reclaim — disk-usage analysers plus the `reclaim` cleanup TUI: diff --git a/playbooks/imports/optional/common/play-ddev.yml b/playbooks/imports/optional/common/play-ddev.yml index c6025f82..59695b0e 100755 --- a/playbooks/imports/optional/common/play-ddev.yml +++ b/playbooks/imports/optional/common/play-ddev.yml @@ -24,7 +24,7 @@ Likely causes: 1. play-docker.yml has not been run yet. - Fix: ansible-playbook playbooks/imports/play-docker.yml + Fix: ansible-playbook playbooks/imports/optional/common/play-docker.yml 2. docker.service is not running. Fix: sudo systemctl status docker --no-pager -l when: docker_info.rc != 0 @@ -52,7 +52,7 @@ Check: docker context ls Fix: docker context use default 3. play-docker.yml has not been re-run since the rootful pivot. - Fix: ansible-playbook playbooks/imports/play-docker.yml + Fix: ansible-playbook playbooks/imports/optional/common/play-docker.yml when: "'name=rootless' in docker_security.stdout" - name: Query {{ user_login }}'s group membership @@ -68,7 +68,7 @@ {{ user_login }} is not a member of the docker group. Current groups: {{ ddev_user_groups.stdout }} - Fix: re-run ansible-playbook playbooks/imports/play-docker.yml + Fix: re-run ansible-playbook playbooks/imports/optional/common/play-docker.yml then log out and back in (or run `newgrp docker`). # DDEV's RPM ships /usr/bin/mkcert itself. Fedora's standalone mkcert diff --git a/playbooks/imports/play-lxc-install-config.yml b/playbooks/imports/play-lxc-install-config.yml index 05d0b6c7..bdc47122 100755 --- a/playbooks/imports/play-lxc-install-config.yml +++ b/playbooks/imports/play-lxc-install-config.yml @@ -2,12 +2,16 @@ --- # LXC install + config. # -# IaC ORDERING: this play MUST run AFTER play-docker.yml. See playbook-main.yml -# for the canonical order. The "Reconcile iptables" block near the end of this -# file inserts rules into Docker's DOCKER-USER chain to keep LXC outbound -# connectivity working on Docker hosts; that chain only exists once Docker is -# installed and its daemon has run. The first two tasks below fail-fast with a -# clear error if Docker is missing. +# DOCKER COEXISTENCE: rootful Docker is OPTIONAL (podman-first policy, +# CLAUDE/ContainerEngines.md — imports/optional/common/play-docker.yml). The +# "Reconcile iptables" block near the end of this file inserts rules into +# Docker's DOCKER-USER chain to keep LXC outbound connectivity working on +# Docker hosts. The probe below detects whether Docker is installed: on Docker +# hosts the whole coexistence block runs and still FAILS FAST if the +# DOCKER-USER chain is missing (Docker half-configured); on podman-only hosts +# it is skipped — without Docker there is no DOCKER-USER short-circuit and +# lxc-net's own FORWARD/MASQUERADE rules suffice. On hosts that DO run Docker, +# run play-docker.yml BEFORE this play. # # Rootless Podman (play-podman.yml) does NOT need to come before LXC — it # uses slirp4netns/pasta for networking and does not touch host iptables. @@ -18,32 +22,16 @@ root_dir: "{{ lookup('ansible.builtin.config', 'CONFIG_FILE') | dirname }}" scope: general # general | gnome | server — see CLAUDE/AnsibleStyle.md tasks: - # ── IaC Ordering Guard ───────────────────────────────────────────────────── - - name: Check whether Docker is installed + # ── Docker presence probe (Docker is optional — podman-first) ────────────── + # /usr/bin/docker exists on Docker hosts AND on podman-docker (shim) hosts, + # so the probe keys on dockerd, which only rootful Docker CE installs. + # Every Docker-coexistence task below conditions on this probe; the + # DOCKER-USER assertion keeps fail-fast semantics for hosts where Docker IS + # installed but half-configured (daemon never started, chain absent). + - name: Check whether rootful Docker is installed (dockerd present) ansible.builtin.stat: - path: /usr/bin/docker - register: docker_binary_check - - - name: Assert Docker is installed before LXC (IaC ordering) - ansible.builtin.assert: - that: - - docker_binary_check.stat.exists - fail_msg: | - Docker is not installed but this play expects Docker to have been - installed first. - - ORDERING REQUIREMENT: play-docker.yml must run before - play-lxc-install-config.yml in playbook-main.yml. The LXC play - reconciles iptables rules in Docker's DOCKER-USER chain (see the - "Reconcile iptables" block later in this file); that chain only - exists once Docker is installed. - - To run standalone, install Docker first: - ansible-playbook playbooks/imports/play-docker.yml - ansible-playbook playbooks/imports/play-lxc-install-config.yml - - Rootless Podman does NOT need to precede LXC — it uses - slirp4netns/pasta and does not touch host iptables. + path: /usr/bin/dockerd + register: docker_daemon_check # Named for what it is: ganto/lxc4 is an LXC 4.x repo and the only packages # taken from it are `lxc` / `lxc-templates`. It was called "LXD Copr" until @@ -297,6 +285,7 @@ # lxc-bash provides shell aliases + completion only; it is not an LXC host # prerequisite. - name: Clone lxc-bash and wire its shell completion (public repo, HTTPS) + become: true become_user: "{{ user_login }}" block: - name: Clone lxc-bash (public, HTTPS — no GitHub auth) @@ -351,20 +340,28 @@ # start lxc-net). Net result: containers boot, get IPs, accept SSH, but # have zero outbound TCP connectivity (curl exit 28). # - # IaC ordering: playbook-main.yml runs this play AFTER play-docker.yml, - # so DOCKER-USER is guaranteed to exist. We assert it (fail-fast) rather - # than probing for a runtime fallback — Docker IS installed because the - # IaC says so. The LXC subnet is derived from the live lxcbr0 interface - # so a customised LXC_NETWORK still works. + # Docker is OPTIONAL (imports/optional/common/play-docker.yml), so this + # whole block conditions on the dockerd presence probe at the top of the + # play. Without Docker there is no DOCKER-USER short-circuit and no + # FORWARD DROP policy, so lxc-net's own rules suffice and nothing here is + # needed. With Docker installed we still ASSERT the chain exists + # (fail-fast) rather than probing for a runtime fallback — a host with + # dockerd on disk but no DOCKER-USER chain is half-configured and must be + # fixed (run the optional play-docker.yml), not silently skipped. The LXC + # subnet is derived from the live lxcbr0 interface so a customised + # LXC_NETWORK still works. # # Persistence: the ACCEPT/MASQUERADE rules are runtime-only kernel state that # vanishes on host reboot and on a Docker daemon restart (which flushes # DOCKER-USER). A shared reconcile script + a systemd unit bound to # docker.service (PartOf=) re-apply them on every boot and every docker # restart — see the "Deploy DOCKER-USER iptables reconciliation" tasks below. - - name: Assert DOCKER-USER iptables chain exists (Docker must run before LXC) + - name: Assert DOCKER-USER iptables chain exists (Docker installed but half-configured?) ansible.builtin.command: iptables -n -L DOCKER-USER changed_when: false + register: _docker_user_chain + failed_when: _docker_user_chain.rc != 0 + when: docker_daemon_check.stat.exists tags: [lxc_iptables] # The DOCKER-USER ACCEPT rules + the LXC-subnet MASQUERADE rule are applied by @@ -379,12 +376,14 @@ owner: root group: root mode: "0755" + when: docker_daemon_check.stat.exists tags: [lxc_iptables] - name: Apply DOCKER-USER iptables rules now (this session) ansible.builtin.command: /usr/local/bin/lxc-docker-user-iptables-reconcile.bash register: _lxc_iptables_reconcile changed_when: "'LXC-IPTABLES-RECONCILE-CHANGED' in _lxc_iptables_reconcile.stdout" + when: docker_daemon_check.stat.exists tags: [lxc_iptables] # PartOf=docker.service makes systemd re-run this unit whenever docker restarts @@ -398,6 +397,7 @@ owner: root group: root mode: "0644" + when: docker_daemon_check.stat.exists tags: [lxc_iptables] # state: started (not restarted) — ANS-09 convention (see lxc.service above): the @@ -409,6 +409,7 @@ daemon_reload: true enabled: true state: started + when: docker_daemon_check.stat.exists tags: [lxc_iptables] # ── Sanity Checks ────────────────────────────────────────────────────────── diff --git a/playbooks/playbook-main.yml b/playbooks/playbook-main.yml index 2f4b3ffc..eac9a37e 100755 --- a/playbooks/playbook-main.yml +++ b/playbooks/playbook-main.yml @@ -18,10 +18,10 @@ - import_playbook: imports/play-rpm-fusion.yml - import_playbook: imports/play-browsers.yml - import_playbook: imports/play-toolbox-install.yml -- import_playbook: imports/play-docker.yml -# LXC runs AFTER Docker so DOCKER-USER chain exists when LXC reconciles -# iptables for outbound connectivity (Docker coexistence). See the -# "Reconcile iptables" block in play-lxc-install-config.yml. +# Rootful Docker is OPTIONAL (podman-first policy, CLAUDE/ContainerEngines.md): +# imports/optional/common/play-docker.yml. On hosts that DO run it, run it +# before play-lxc-install-config.yml so the DOCKER-USER chain exists when LXC +# reconciles iptables — the LXC play detects Docker and adapts either way. # # LXC does NOT need to come after Podman — play-podman.yml installs rootless # Podman (slirp4netns/pasta networking), which does not touch host iptables. From 2bfab6a725c7615e3b9be9fbe0f91fee07613de4 Mon Sep 17 00:00:00 2001 From: joseph Date: Tue, 1 Sep 2026 14:10:24 +0000 Subject: [PATCH 3/3] Plan 00091: record PR #42 delivery and close-out handoff Co-Authored-By: Claude Fable 5 --- .../JOURNAL/00091-Journal-26-09-01.md | 6 ++++++ CLAUDE/Plan/00091-podman-first-docker-optional/PLAN.md | 9 +++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CLAUDE/Plan/00091-podman-first-docker-optional/JOURNAL/00091-Journal-26-09-01.md b/CLAUDE/Plan/00091-podman-first-docker-optional/JOURNAL/00091-Journal-26-09-01.md index 7f4ad63f..c6d35d1c 100644 --- a/CLAUDE/Plan/00091-podman-first-docker-optional/JOURNAL/00091-Journal-26-09-01.md +++ b/CLAUDE/Plan/00091-podman-first-docker-optional/JOURNAL/00091-Journal-26-09-01.md @@ -62,3 +62,9 @@ containerization.md, ContainerEngines.md. `CLAUDE/PlanWorkflow.md`'s mention is illustrative example in a daemon-deployed doc — left untouched. QA: qa-ansible-syntax, qa-ansible, qa-patterns, qa-discovery all pass; qa-docs fails only on pre-existing `.claude/rules/*` links to a missing daemon doc (unrelated to this plan). + +## 14:15 · handoff · T3.2 — PR open, awaiting review/merge + +PR https://github.com/LongTermSupport/fedora-desktop/pull/42 open against F44 (commits +989457d + 67ee5a5). PR #40 closed as superseded (skip-docker-env branch left in place). +Plan stays In Progress until the PR merges; on merge, flip to Complete and archive. diff --git a/CLAUDE/Plan/00091-podman-first-docker-optional/PLAN.md b/CLAUDE/Plan/00091-podman-first-docker-optional/PLAN.md index 85d4d5a7..4bd692df 100644 --- a/CLAUDE/Plan/00091-podman-first-docker-optional/PLAN.md +++ b/CLAUDE/Plan/00091-podman-first-docker-optional/PLAN.md @@ -51,15 +51,16 @@ that PR is closed. Remaining coexistence concerns are tracked in issue #41 (Refs ### Phase 3: QA and PR - [x] ✅ **Task 3.1**: Run the repo QA (`scripts/qa-all.bash` relevant gates) and fix findings. -- [ ] 🔄 **Task 3.2**: Push branch, open PR (Refs #41), close PR #40 as superseded. +- [x] ✅ **Task 3.2**: Push branch, open PR (Refs #41), close PR #40 as superseded. ## Success Criteria -- [ ] `ansible-playbook --syntax-check` passes for `playbook-main.yml` and the moved play. -- [ ] No functional reference to `playbooks/imports/play-docker.yml` remains outside +- [x] `ansible-playbook --syntax-check` passes for `playbook-main.yml` and the moved play. +- [x] No functional reference to `playbooks/imports/play-docker.yml` remains outside historical plan folders. -- [ ] PR open with rationale, migration notes, and bundle decision; PR #40 closed. +- [x] PR open with rationale, migration notes, and bundle decision; PR #40 closed. ## Delivery & Milestones +- Demotion delivered on branch podman-first-docker-optional (989457d, 67ee5a5); PR: https://github.com/LongTermSupport/fedora-desktop/pull/42 - Issue: https://github.com/LongTermSupport/fedora-desktop/issues/41