Introducing Podman Quadlets, its automation using vscode tasks, and sanity testing using pytest#197
Conversation
…er Compose equivalent. Added podman compose build scripts
There was a problem hiding this comment.
Pull request overview
Adds Podman Quadlet-based deployment + automation tooling and introduces pytest-based “sanity” checks to validate DB/container readiness for both Docker Compose and Podman.
Changes:
- Added Podman Quadlet units (network/containers/volumes) and helper scripts to start/stop/restart/verify the stack via systemd user units.
- Added pytest sanity tests for Docker and Podman DB connectivity/credentials checks (reading env/quadlet config).
- Added Poetry-based Python tooling + VS Code tasks updates to automate common Docker/Podman workflows.
Reviewed changes
Copilot reviewed 23 out of 25 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
tests/test_podman_db.py |
Podman-based DB sanity tests using quadlet/env parsing. |
tests/test_docker_db.py |
Docker Compose-based DB sanity tests using .examples/docker/*.env. |
scripts/start |
Builds image + installs quadlets + starts systemd user services. |
scripts/stop |
Stops services and attempts to remove installed quadlets. |
scripts/restart |
Convenience wrapper to stop then start. |
scripts/verify |
End-to-end runtime verification (systemd + DB + HTTP checks). |
quadlets/*.container |
Quadlet definitions for app/db/cron containers. |
quadlets/*.network |
Quadlet network definition for the stack. |
quadlets/*.volume |
Persistent volume definitions for DB/uploads. |
quadlets/librebooking.env |
Runtime env file used by quadlets. |
quadlets/README.md |
Documentation for running via quadlets/systemd user units. |
pyproject.toml |
Adds Poetry/PEP-621 project config for tests/tooling. |
poetry.toml |
Configures in-project virtualenvs. |
poetry.lock |
Locks pytest + related dependencies. |
Dockerfile |
Removes heredoc usage; adjusts upstream fetch + supercronic install. |
.vscode/tasks.json |
Adds/updates tasks for Docker and Podman workflows. |
.vscode/settings.json |
Configures VS Code Python env/package manager to Poetry. |
.gitignore |
Ignores Python caches and .venv/. |
.examples/docker/docker-compose-local.yml |
Updates local compose stack (cron volume mount). |
.examples/docker/db.env |
Expands MariaDB env config to include DB/user/password. |
.examples/docker/crontab |
Adds a crontab file intended for cron scheduling override. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| -t localhost/librebooking:prod \ | ||
| "$PROJECT_ROOT" | ||
| mkdir -p ~/.config/containers/systemd/ | ||
| install -m 0644 $PROJECT_ROOT/quadlets/* ~/.config/containers/systemd/ |
There was a problem hiding this comment.
install -m 0644 $PROJECT_ROOT/quadlets/* ... uses unquoted variables/globs, which can break if the project path contains spaces and can produce confusing errors if the glob doesn’t match. Quote $PROJECT_ROOT and consider handling the no-match case explicitly.
| install -m 0644 $PROJECT_ROOT/quadlets/* ~/.config/containers/systemd/ | |
| shopt -s nullglob | |
| quadlet_files=("$PROJECT_ROOT"/quadlets/*) | |
| shopt -u nullglob | |
| if ((${#quadlet_files[@]} == 0)); then | |
| echo "No quadlet files found in $PROJECT_ROOT/quadlets" >&2 | |
| exit 1 | |
| fi | |
| install -m 0644 "${quadlet_files[@]}" ~/.config/containers/systemd/ |
| rm -rf .git | ||
| EORUN | ||
| RUN set -eux; \ | ||
| GIT_TREE="$(basename "${APP_GH_REF}")"; \ |
There was a problem hiding this comment.
ARG GIT_TREE is now effectively unused because the RUN step always overwrites GIT_TREE from APP_GH_REF. Either remove the build arg or honor it (e.g., only derive from APP_GH_REF when GIT_TREE is unset) to avoid confusing/ineffective build parameters.
| GIT_TREE="$(basename "${APP_GH_REF}")"; \ | |
| : "${GIT_TREE:=$(basename "${APP_GH_REF}")}"; \ |
|
Hi @barakiva , thank you very much for your PR. Please give me a few days to test and review your changes. |
Make testing not leak credentials Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Hey no problem. I'm new to this copilot code review thing. Is there a way to pipe/transfer these suggestions to the IDE so I can test them as I try to incorporate each one? |
| rm -rf .git | ||
| EORUN | ||
| RUN set -eux; \ | ||
| GIT_TREE="$(basename "${APP_GH_REF}")"; \ |
There was a problem hiding this comment.
On my side, I have no issues with the heredoc construct (RUN <<EORUN). I am using Debian-13 (trixie) with podman version 5.4.2.
Could you confirm that podman build fails in your environment? If yes, can you give us more details on your environment (linux distribution, podman version,...) ?
There was a problem hiding this comment.
Running the unmodified Dockerfile as it exists in the upstream repo gives the following:
[2/4] STEP 8/15: set -eux
ERRO[0000] +(UNHANDLED LOGLEVEL) &imagebuilder.Step{Env:[]string{"APP_GH_ADD_SHA=false", "APP_GH_REF=refs/heads/develop", "UPSTREAM_URL=https://github.com/librebooking/librebooking", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}, Command:"set", Args:[]string{""}, Flags:[]string{}, Attrs:map[string]bool(nil), Message:"SET ", Original:"set -eux"}
Error: building at STEP "SET ": Build error: Unknown instruction: "SET" &imagebuilder.Step{Env:[]string{"APP_GH_ADD_SHA=false", "APP_GH_REF=refs/heads/develop", "UPSTREAM_URL=https://github.com/librebooking/librebooking", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}, Command:"set", Args:[]string{""}, Flags:[]string{}, Attrs:map[string]bool(nil), Message:"SET ", Original:"set -eux"}
* The terminal process "/bin/bash '-c', '/home/bar/Development/Projects/Bookme/bookme/scripts/start'" failed to launch (exit code: 125).
The Buildah repo has the following discussion here containers/buildah#3474. Theres also a PR for adding heredoc support for RUN .
As to why its still a problem on my machine, I assume it's because im using podman 4.9.3 on Pop OS 24.04 (ubuntu distro) and Ubuntu is yet to have heredoc support as shown in HEREDOC: Not available in 1.33.5 1.33.7 1.34 on Ubuntu, Debian, etc? · Issue #5474 · containers/buildah
containers/buildah#5474.
If the inclusion of heredoc is critical, maybe could you tell me what it's intended to achieve and I could come up with a suitable alternative?
There was a problem hiding this comment.
Nothing critical: it's just that we found heredoc easier to read and less error prone (no need to end each line with ; \.
We switched quite recently to heredoc with librebooking/docker release 3.3.0 and I am not keen on reverting back the heredoc construct...
There was a problem hiding this comment.
I can propose an alternative: instead of having 2 setup scripts (sys and app) we could have only one. We would call it with 1 argument that would indicate which code to execute. For instance: setup app or setup sys etc… This way, we would have in Dockerfile something like ˋRUN setup sys`.
What do you think?
There was a problem hiding this comment.
@ikke-t , @JohnVillalovos : what is your opinion? I like Bar's PR and I'd like to put in prod, but we need to fix the heredoc issue that affects users who use an old version of podman...
There was a problem hiding this comment.
I can propose an alternative: instead of having 2 setup scripts (sys and app) we could have only one. We would call it with 1 argument that would indicate which code to execute. For instance: setup app or setup sys etc… This way, we would have in Dockerfile something like ˋRUN setup sys`.
What do you think?
Hey check my recent commit. I'm calling the script & passing the arguments. No need for a heredox and you get syntax highlighting. Is that satisfactory?
There was a problem hiding this comment.
Who does such an old issue of podman still hit? Seems the discussion is from 2023, so is it valid problem still? Apparently it's a problem if it hits you still.
OTOH, I don't mind how it's done as long as it works. It don't know if it causes useless layer rebuilds in case of nothing changes in dockerfile, or does something not get noticed if e.g. the script changes but Dockerfile doesn't. I haven't really gone so deep into looking what affects rebuilds.
… compromise for not using heredox.
There was a problem hiding this comment.
Why pull=never? The statup fails if image is not pulled ever. Perhaps missing would be better, so that start always succeeds as long as the registry is reachable.
There was a problem hiding this comment.
That's because images are built & pulled locally as you can see in Image=localhost/librebooking:prod. I cannot recall why i've opted to manually build the image and pull from localhost. But it has something to do with configuration/rootpath/env not working when you pull from the registry.
pull=never tightly enforced the contract i've laid down in Image=localhost/librebooking:prod which gives me greater control over how the image is built and makes the overall process much more idempotent and reproducible.
There was a problem hiding this comment.
I was blind and missed it, sorry. That's good for dev and testing.
Then I'd change the Readme into (testing). For a newbie trying out librebooking with these it would immediately fail. Or perhaps a comment into file that if you are not building locally, change this to "missing" and change the image url to point to dockerhub? E.g. commented lines having the options set.
Having folder named quadlets with test setup and readme saying production might lead to misunderstanding. Minor thing, but perhaps we would save 15 mins of someones time failing for the first time trying quadlets.
There was a problem hiding this comment.
I was blind and missed it, sorry. That's good for dev and testing.
Then I'd change the Readme into (testing).
Could you clarify what you mean by chaging the readme into (testing)? As in change the H1 in the readme, or add a testing directory under quadlets?
For a newbie trying out librebooking with these it would immediately fail. Or perhaps a comment into file that if you are not building locally, change this to "missing" and change the image url to point to dockerhub? E.g. commented lines having the options set.
I guess I have been using Quadlets too much to forget what a newbie would make of it trying it for the first time. What did you feel was missing from the documentation? The user doesnt have to write any command. The utility scripts under /scripts do it all from building, to creating system unit files to lauching the containers.
Having folder named quadlets with test setup and readme saying production might lead to misunderstanding. Minor thing, but perhaps we would save 15 mins of someones time failing for the first time trying quadlets.
Sorry but I don't really understand. You suggest adding a test setup to the quadlets folder? Or adding documentation on a production setup for the quadlets workflow?
There was a problem hiding this comment.
Sorry I was unclear. Yes, the README in your repo says "(production)":
The quadlets however are really for local testing while having pull not there and localhost as image url. So it's just a bit conflicting in my thought. The run.sh implements local build, which wouldn't be needed/wanted if one just wants to run official release.
Building locally feels more like dev and test instead of production. Which is useful and good for such use. I would assume for production average Joe runs the official images from dockerhub?
Perhaps start-localbuilt.sh or start-prod.sh would be more clear? Or start.sh [--released|--localbuilt] where one can be default. Whatever the options are named, could be --stable or --latest if such tags exist in dockerub. Then the script would write the proper lines to quadlet depending on the case.
There was a problem hiding this comment.
Now i understand. Admittedly I notice I have been developing this from a "local" bias.
You are right that there should be focus given to production configuration. Would that be fine though if the production configuration would be a separate PR?
This PR is already becoming really large (partly due to me being green to OSS). IMO I should adopt a profiles approach of a prod.env and dev.env and somewhere the user changes "dev" to "prod" and the entire project follows suit.
Before that though i need to give some time to testing and CI as it takes up a big chunk of my time.
There was a problem hiding this comment.
Totally fine by me. Thanks for working on this.
There was a problem hiding this comment.
same thing here, I'd go with Pull=missing
There was a problem hiding this comment.
Please see my reply on your previous comment
|
Good stuff. I don't really have comments other than I added to pull policy missing causing failure if local image isn't there. If you are up to it, one future improvement would be to move passwords as podman secrets. But this is of course future developement, just mentioning if you are interested to do it at once while at it. https://oneuptime.com/blog/post/2026-03-17-use-secrets-podman-quadlet/view |
Hey thanks. Yeah thats a good suggestion but the PR is already getting unwieldy. I'd happily work on it once it gets merged! |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
@barakiva, I committed the suggestion from Copilot regarding the mapping of host file I accept the PR and I will make a few changes (taking into account the remarks from @ikke-t ) in the coming days. Please monitor the branch Again, thank you very much for your contribution. |
|
Once I am satisfied, I will issue a new release: |
Happy to hear. Thank you all for the feedback. |
Following up on #188 i've added automated deployment of the entire project stack using podman. I have also added santiy testing in python that MASSIVELY saves time to make sure everything works (containers actually created, database listening at the right port, users created according to the .env etc). A bit of a tangent but i'm really happy not having to browse localhost:8080/Web/install anymore to make sure I have the right credentials for the databse.
I have also introduced Podman qualets to the project. Quadlets is Podmans equivalent of Docker Compose. While it is possible for podman to read a docker-compose.yaml, it's extremely error prone, unreliable and a real pain. The Podman team also heavily recommends using Quadlets over podman-compose, which is why I have chosen using it to replicate the docker-compose.yaml for those wanting to use Podman.
The last big change is introducing pytest for sanity testing. ATM the tests exist for (IMO) the biggest time sink which is making sure the database is up, at the right port, with all the credentials set up during image creation.
Out of all the changes the testing one was the hardest for me. I have considered and used various tools like Goss, BaTS or raw Bash. Goss is unmaintained, BaTS seems too complex (you have to add it a submodule fundamentally changing the project) and IMO python is more readable than writing a test. Im still however most conflicted about pytest so if anyone has any suggestions I can improve sanity testing in a future PR.
Another important point regarding the Dockerfile edits is that we should stop using heredoc as Buildah (Podman) cannot parse it like BuildKit (docker) can. For the project to be truly compatible across docker and podman i've removed all heredox from the Dockerfile and request other people to not re-introduce it as it breaks podman (a good idea for a CI/CD step right here!).
Sorry for the PR being massive I realized I had to include testing in the middle of everything and I assume I messed up the rebases and syncs but im still learning being new to open source contribution.