Skip to content

Introducing Podman Quadlets, its automation using vscode tasks, and sanity testing using pytest#197

Merged
colisee merged 23 commits intoLibreBooking:masterfrom
barakiva:automation-podman
Apr 20, 2026
Merged

Introducing Podman Quadlets, its automation using vscode tasks, and sanity testing using pytest#197
colisee merged 23 commits intoLibreBooking:masterfrom
barakiva:automation-podman

Conversation

@barakiva
Copy link
Copy Markdown
Contributor

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.

@JohnVillalovos JohnVillalovos requested a review from Copilot April 14, 2026 15:18
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread tests/test_docker_db.py Outdated
Comment thread quadlets/db.container
Comment thread scripts/stop Outdated
Comment thread scripts/start
-t localhost/librebooking:prod \
"$PROJECT_ROOT"
mkdir -p ~/.config/containers/systemd/
install -m 0644 $PROJECT_ROOT/quadlets/* ~/.config/containers/systemd/
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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/

Copilot uses AI. Check for mistakes.
Comment thread Dockerfile Outdated
rm -rf .git
EORUN
RUN set -eux; \
GIT_TREE="$(basename "${APP_GH_REF}")"; \
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
GIT_TREE="$(basename "${APP_GH_REF}")"; \
: "${GIT_TREE:=$(basename "${APP_GH_REF}")}"; \

Copilot uses AI. Check for mistakes.
Comment thread pyproject.toml
Comment thread .examples/docker/docker-compose-local.yml Outdated
Comment thread .vscode/tasks.json Outdated
Comment thread scripts/verify Outdated
Comment thread scripts/stop Outdated
@colisee
Copy link
Copy Markdown
Collaborator

colisee commented Apr 14, 2026

Hi @barakiva , thank you very much for your PR.
Please review the suggestions from Copilot and adapt according to your judgement.

Please give me a few days to test and review your changes.

barakiva and others added 2 commits April 14, 2026 22:05
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>
@barakiva
Copy link
Copy Markdown
Contributor Author

Hi @barakiva , thank you very much for your PR. Please review the suggestions from Copilot and adapt according to your judgement.

Please give me a few days to test and review your changes.

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?

Comment thread Dockerfile Outdated
rm -rf .git
EORUN
RUN set -eux; \
GIT_TREE="$(basename "${APP_GH_REF}")"; \
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,...) ?

Copy link
Copy Markdown
Contributor Author

@barakiva barakiva Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@colisee colisee added the enhancement New feature or request label Apr 18, 2026
Comment thread quadlets/app.container
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I was unclear. Yes, the README in your repo says "(production)":

image

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally fine by me. Thanks for working on this.

Comment thread quadlets/cron.container
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same thing here, I'd go with Pull=missing

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my reply on your previous comment

@ikke-t
Copy link
Copy Markdown
Collaborator

ikke-t commented Apr 20, 2026

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

@barakiva
Copy link
Copy Markdown
Contributor Author

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>
@colisee
Copy link
Copy Markdown
Collaborator

colisee commented Apr 20, 2026

@barakiva, I committed the suggestion from Copilot regarding the mapping of host file crontab in file docker-compose-local.yml

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 barakiva in my forked repo and wait until they are pushed to this repo before adding new and welcome enhancements.

Again, thank you very much for your contribution.

@colisee
Copy link
Copy Markdown
Collaborator

colisee commented Apr 20, 2026

Once I am satisfied, I will issue a new release: 3.4.0

@colisee colisee merged commit f22139b into LibreBooking:master Apr 20, 2026
3 checks passed
@barakiva
Copy link
Copy Markdown
Contributor Author

@barakiva, I committed the suggestion from Copilot regarding the mapping of host file crontab in file docker-compose-local.yml

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 barakiva in my forked repo and wait until they are pushed to this repo before adding new and welcome enhancements.

Again, thank you very much for your contribution.

Happy to hear. Thank you all for the feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants