Files
unitdore/docs/generated-units.md
T
warkanum f0827fcdd7 feat: podman-compose stack units and root/user execution scopes
- syncup: podman first, docker only as fallback (podman wins on name clash;
  existing docker units found in podman switch to podman)
- syncup: group podman-compose containers into one `kind: stack` unit per
  project (project, working_dir, compose_files, compose_bin from labels);
  disable existing member units ("part of stack <project>")
- generator: compose mode (podman-compose up/stop, WorkingDirectory) with
  pod start/stop fallback when compose binary/dir/files are missing
- reconcile: stacks disabled with "stack not found" when neither compose
  files nor pod exist
- root: scan root + rootless users listed in `users:` (podman only)
- non-root: config ~/.config/unitdore/units.yaml, own user units only
- sysuser package: runuser with XDG_RUNTIME_DIR/DBUS env, home/linger lookup
- install: warn when linger is not enabled for user units
- testdata/stack: podman-compose test stack and captured podman ps fixture
- docs: README, generated-units, man page, AGENTS, PLAN
2026-10-12 19:05:51 +02:00

342 lines
6.7 KiB
Markdown

# Generated Systemd Unit Files
Unitdore generates `.service` files from your `units.yaml` config.
This document shows every combination with annotated examples.
---
## System Unit (root, no user)
**Config:**
```yaml
units:
- name: nginx
runtime: podman
order: 1
enabled: true
```
**Written to:** `/etc/systemd/system/unitdore-nginx.service`
```ini
# /etc/systemd/system/unitdore-nginx.service
# Generated by unitdore — do not edit manually
[Unit]
Description=Unitdore: nginx (podman)
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/podman start -a nginx
ExecStop=/usr/bin/podman stop nginx
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
```
**Notes:**
- `After=network.target` ensures the network is up before starting
- `WantedBy=multi-user.target` means it starts in normal boot runlevel
- `Restart=on-failure` restarts the container if it exits unexpectedly
---
## System Unit (Docker)
**Config:**
```yaml
units:
- name: redis
runtime: docker
order: 1
enabled: true
```
**Written to:** `/etc/systemd/system/unitdore-redis.service`
```ini
# /etc/systemd/system/unitdore-redis.service
# Generated by unitdore — do not edit manually
[Unit]
Description=Unitdore: redis (docker)
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/docker start redis
ExecStop=/usr/bin/docker stop redis
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
```
**Notes:**
- Docker uses `docker start <name>` (no `-a` flag needed)
---
## User Unit (rootless container)
**Config:**
```yaml
units:
- name: myapp
runtime: podman
user: hein
order: 2
enabled: true
```
**Written to:** `/home/hein/.config/systemd/user/unitdore-myapp.service`
```ini
# ~/.config/systemd/user/unitdore-myapp.service
# Generated by unitdore — do not edit manually
[Unit]
Description=Unitdore: myapp (podman)
After=default.target
[Service]
Type=simple
ExecStart=/usr/bin/podman start -a myapp
ExecStop=/usr/bin/podman stop myapp
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
```
**Notes:**
- User units use `After=default.target` and `WantedBy=default.target`
- The file is written to the user's own systemd directory
- Unitdore calls `runuser -u hein -- systemctl --user` for enable/start/status
---
## Custom Command
**Config:**
```yaml
units:
- name: myscript
runtime: podman
command: /opt/myapp/start.sh
order: 3
enabled: true
```
**Written to:** `/etc/systemd/system/unitdore-myscript.service`
```ini
# /etc/systemd/system/unitdore-myscript.service
# Generated by unitdore — do not edit manually
[Unit]
Description=Unitdore: myscript (podman)
After=network.target
[Service]
Type=simple
ExecStart=/opt/myapp/start.sh
ExecStop=
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
```
**Notes:**
- When `command` is set, it is used verbatim as `ExecStart`
- `ExecStop` is left empty — systemd will send SIGTERM to the process group
---
## With Prefix and Suffix
**Config:**
```yaml
prefix: prod-
suffix: -svc
units:
- name: nginx
runtime: podman
order: 1
enabled: true
- name: api
runtime: docker
order: 2
enabled: true
```
**Written to:**
- `/etc/systemd/system/unitdore-prod-nginx-svc.service`
- `/etc/systemd/system/unitdore-prod-api-svc.service`
```ini
# /etc/systemd/system/unitdore-prod-nginx-svc.service
# Generated by unitdore — do not edit manually
[Unit]
Description=Unitdore: nginx (podman)
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/podman start -a nginx
ExecStop=/usr/bin/podman stop nginx
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
```
**Notes:**
- `prefix` and `suffix` apply to the **service file name only** — the container name stays unchanged
- Useful for distinguishing environments (`prod-`, `staging-`) or roles (`-web`, `-worker`)
---
## Container Named by Short ID
If a container has no name (e.g. started with `docker run` without `--name`), unitdore uses its short container ID (first 12 characters) as the unit name.
**Example:** Container ID `a3f2c1b9e4d7` with no name →
**Config entry added by `syncup`:**
```yaml
units:
- name: a3f2c1b9e4d7
runtime: docker
order: 1
enabled: true
```
**Written to:** `/etc/systemd/system/unitdore-a3f2c1b9e4d7.service`
**Tip:** After `syncup`, use `unitdore edit` to give it a proper name before running `install`.
---
## Startup Ordering Example
**Config:**
```yaml
units:
- name: postgres
runtime: podman
order: 1
enabled: true
- name: redis
runtime: podman
order: 1 # same order = starts in parallel
enabled: true
- name: api
runtime: podman
order: 2 # waits until order 1 group is started
enabled: true
- name: nginx
runtime: podman
order: 3
enabled: true
```
`unitdore active` starts units in ascending `order` value, lowest first.
Units with the **same order** are started together (parallel).
---
## Disabled Unit
**Config:**
```yaml
units:
- name: oldthing
runtime: podman
order: 1
enabled: false
disabled_reason: container not found
```
- `unitdore install` will **remove** the `.service` file if it exists
- `unitdore active` will **skip** disabled units
- `unitdore status` shows the reason in the REASON column
---
## Stack Unit (podman-compose, compose mode)
Used when `compose_bin`, `working_dir` and all `compose_files` exist.
```yaml
- name: shop
kind: stack
runtime: podman
project: shop
working_dir: /srv/shop
compose_files: [compose.yaml]
compose_bin: /usr/bin/podman-compose
enabled: true
```
```ini
# /etc/systemd/system/unitdore-shop.service
# Generated by unitdore — do not edit manually
[Unit]
Description=Unitdore: shop (podman-compose stack)
After=network.target
[Service]
Type=simple
WorkingDirectory=/srv/shop
ExecStart=/usr/bin/podman-compose -p shop -f compose.yaml up
ExecStop=-/usr/bin/podman-compose -p shop -f compose.yaml stop
[Install]
WantedBy=multi-user.target
```
---
## Stack Unit (pod fallback)
Used when the compose binary, working dir or a compose file is missing. Requires pod `pod_<project>`.
```ini
[Unit]
Description=Unitdore: shop (podman pod)
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/podman pod start pod_shop
ExecStop=-/usr/bin/podman pod stop pod_shop
```
---
## Quick Reference: Service File Locations
| Scenario | Path |
|---|---|
| System unit (root) | `/etc/systemd/system/unitdore-<name>.service` |
| User unit | `/home/<user>/.config/systemd/user/unitdore-<name>.service` |
| With prefix `prod-` | `/etc/systemd/system/unitdore-prod-<name>.service` |
| With suffix `-svc` | `/etc/systemd/system/unitdore-<name>-svc.service` |
| With both | `/etc/systemd/system/unitdore-prod-<name>-svc.service` |