feat: apply converges the overlays and Monit's checks of the manifests (0041 step 3) #58

Merged
marcos-mendez merged 5 commits from feat/manifest-apply into main 2026-09-30 15:45:04 -03:00
marcos-mendez commented 2026-09-30 14:48:40 -03:00 (Migrated from github.com)

Step 3 of the first implementation of handbook decision 0041, without the firewall: the spec's appliance, installation and overlays; apply --system converges the overlays' units and writes Monit's derived checks; inspect and diff read them. The firewall is #59, opt-in and for cloud advanced only, as the maintainer scoped it on 2026-09-30.

What changes

  • Spec (keel/spec/validate_appliance.py, keel/manifest/facts.py): the three sections, enabled or disabled only (on, off and ask refused with the reason), and rules 25 to 27 held against the manifests under the command's root: every overlay of the resolved chain written out, requires enabled, manifest-declared secrets accepted and rendered as KEEL_SECRET_<NAME> with generate refused where the manifest says never, app.options typed and required ones present. spec validate gains --root. A spec that names no appliance is checked exactly as before.
  • Units (keel/system/appliance.py): enabled enables and starts, disabled stops and disables, in requires order, only what differs. Never masks or unmasks; a masked unit is refused. systemctl --root under a tree.
  • CrowdSec identity (keel/system/crowdsec.py, tracker#47): on the first enable, the missing parts only: an empty online_api_credentials.yaml, cscli machines add --auto --force, cscli capi register as an Attempt (offline it is said and survived; CrowdSec runs on its local API alone), and cscli bouncers add, whose key goes from stdout to the .local file, mode 0600, and nowhere else. A pending-registration left by the Debian postinst is replaced too: it keeps the bouncer's unit from starting (found in the real test). Nothing is made under --root.
  • Monit (keel/manifest/monit.py): the appliance's own processes and checks and those of enabled overlays only; check program on systemctl is-active, restart through systemd, the manifest's restart limit then unmonitor and a keel notify --check restarts. Written always to /etc/keel/monit/keel-manifest.conf, linked from /etc/monit/conf.d/ only while monitor.enabled is true, then monit -t and a reload. keel notify gains --check service|restarts, --name, --unit.
  • inspect / diff: appliance.name from the top of the installed chain, overlay states from systemd, the mode and unit-less overlays from the emitted spec; diff compares states with systemd, the derived file whole and its include.

Real test (0041 criterion)

Fresh LXC container on the test VM from the B4 image, with keel_0.13.0 and the four common#20 packages built from 19.x and installed in one transaction, Core's manifest from the format, the identity files deleted as tracker#47 says the image build will. CrowdSec disabled, enabled, disabled: each converged, each second apply 0 change(s), 0 failed, each keel diff exit 0, monit -t OK after each, the Monit file gained exactly keel-unit-crowdsec, keel-unit-firewall-bouncer, keel-check-crowdsec-lapi and the file after disabling is byte-identical to the first. Offline CAPI (api.crowdsec.net pointed at ::1): capi register not done and said, both units active, LAPI answers, second apply 0 changes, diff clean.

Test plan

  • set -o pipefail; coverage run -m pytest tests: 2172 passed; coverage 99 percent, new modules 100
  • rendered Monit files given to monit -t (5.34.3) locally and on the container
  • the done criterion on a container with step 2's packages
  • CI green
  • firewall: split into #59, stacked on this one

Findings for other steps: keel-overlay-crowdsec under iptables-legacy needs ipset (the bouncer dies with "unable to find ipset"); tracker#47's image-build list should add /var/lib/crowdsec/pending-registration; Core's postfix check at ::1 fails on TurnKey (inet_interfaces = localhost binds 127.0.0.1 only), for keel-core in step 4.

Step 3 of the first implementation of handbook decision 0041, without the firewall: the spec's `appliance`, `installation` and `overlays`; `apply --system` converges the overlays' units and writes Monit's derived checks; `inspect` and `diff` read them. The firewall is #59, opt-in and for cloud advanced only, as the maintainer scoped it on 2026-09-30. ## What changes - **Spec** (`keel/spec/validate_appliance.py`, `keel/manifest/facts.py`): the three sections, `enabled` or `disabled` only (on, off and ask refused with the reason), and rules 25 to 27 held against the manifests under the command's root: every overlay of the resolved chain written out, requires enabled, manifest-declared secrets accepted and rendered as `KEEL_SECRET_<NAME>` with `generate` refused where the manifest says never, `app.options` typed and required ones present. `spec validate` gains `--root`. A spec that names no appliance is checked exactly as before. - **Units** (`keel/system/appliance.py`): enabled enables and starts, disabled stops and disables, in `requires` order, only what differs. Never masks or unmasks; a masked unit is refused. `systemctl --root` under a tree. - **CrowdSec identity** (`keel/system/crowdsec.py`, tracker#47): on the first enable, the missing parts only: an empty `online_api_credentials.yaml`, `cscli machines add --auto --force`, `cscli capi register` as an `Attempt` (offline it is said and survived; CrowdSec runs on its local API alone), and `cscli bouncers add`, whose key goes from stdout to the `.local` file, mode 0600, and nowhere else. A `pending-registration` left by the Debian postinst is replaced too: it keeps the bouncer's unit from starting (found in the real test). Nothing is made under `--root`. - **Monit** (`keel/manifest/monit.py`): the appliance's own processes and checks and those of enabled overlays only; `check program` on `systemctl is-active`, restart through systemd, the manifest's restart limit then `unmonitor` and a `keel notify --check restarts`. Written always to `/etc/keel/monit/keel-manifest.conf`, linked from `/etc/monit/conf.d/` only while `monitor.enabled` is true, then `monit -t` and a reload. `keel notify` gains `--check service|restarts`, `--name`, `--unit`. - **inspect / diff**: `appliance.name` from the top of the installed chain, overlay states from systemd, the mode and unit-less overlays from the emitted spec; diff compares states with systemd, the derived file whole and its include. ## Real test (0041 criterion) Fresh LXC container on the test VM from the B4 image, with `keel_0.13.0` and the four common#20 packages built from 19.x and installed in one transaction, Core's manifest from the format, the identity files deleted as tracker#47 says the image build will. CrowdSec disabled, enabled, disabled: each converged, each second apply `0 change(s), 0 failed`, each `keel diff` exit 0, `monit -t` OK after each, the Monit file gained exactly `keel-unit-crowdsec`, `keel-unit-firewall-bouncer`, `keel-check-crowdsec-lapi` and the file after disabling is byte-identical to the first. Offline CAPI (api.crowdsec.net pointed at ::1): `capi register` not done and said, both units active, LAPI answers, second apply 0 changes, diff clean. ## Test plan - [x] `set -o pipefail; coverage run -m pytest tests`: 2172 passed; coverage 99 percent, new modules 100 - [x] rendered Monit files given to `monit -t` (5.34.3) locally and on the container - [x] the done criterion on a container with step 2's packages - [ ] CI green - [x] firewall: split into #59, stacked on this one Findings for other steps: `keel-overlay-crowdsec` under iptables-legacy needs `ipset` (the bouncer dies with "unable to find ipset"); tracker#47's image-build list should add `/var/lib/crowdsec/pending-registration`; Core's `postfix` check at `::1` fails on TurnKey (`inet_interfaces = localhost` binds 127.0.0.1 only), for keel-core in step 4.
Sign in to join this conversation.
No description provided.