Repository navigation
jcloud can now watch a server, not only check a tree. A new command gathers the observations on the host, jcloud.yml declares what the machine itself must be, and survey tells a new failure from one already known. Templates under contrib/ run all of it on a schedule. jcloud still reaches no network, keeps no state and alerts nobody: the transport, the last run and the alert stay the platform's.
observe: the collector, shipped with jcloud
jcloud observe [--root <dir>]runs on the host, in the deployed tree, and prints the linessurveyreads: each container docker has up and how it stands, the repo digest it runs, each service's pin frompin_file, and each compose profile a manifest declares (onwhenCOMPOSE_PROFILESnames it or one of its services is up). Names come fromjcloud.yml, so a platform no longer needs a collector of its own. A docker that cannot be asked is an error, never an empty answer.
host: in jcloud.yml
Absent, nothing about the host is asserted. A platform opts in by declaring:
host:
timers:
- japode-healthwatch # must be active, last run succeeded
- {name: japode-backup, max_age: 7h} # …and finished within 7h
paths:
- {path: ., mode: "750", owner: runner:runner}
firewall: ufw # installed and active
disks: [/, /var/lib/docker]
disk_free: 15%
certs: [caddy/certificates/*/*.crt] # a glob is allowed
cert_days: 14- Timers are read with
systemctl: active, how the unit they fire last ended, and when. An active timer whose job fails every night is reported, as is a backup older than itsmax_age. - Disks are held to a free-space floor (
df), and certificates to a number of days left, read from the file withcrypto/x509, never by connecting to the host name. - A fact that could not be read (
ufw statuswithout root, a failedstat) is reported as unread, never as a pass.
survey
--since <previous observations>marks each findingneworstandingand lists the onesgone. Findings are matched by a stable code and subject, so a reworded sentence, or a disk going from 9% to 8% free, is still the same finding. The exit code is still this run's verdict.--jsonprints{"findings": [...]}, each withcode(container.missing,digest.moved,timer.failed,backup.stale,disk.low,cert.expiring, …),subject,saysand, with--since,state. Nothing else goes to stdout in this mode.
contrib/: a watch that runs itself
Templates a platform copies; jcloud never runs them.
contrib/systemd/: a script, service and timer (every 15 minutes) that observe, survey against the last run and leavereport.jsonandreport.txt. The unit fails when the server diverges, so it shows insystemctl --failed.contrib/github/jcloud-watch.yml: a workflow for a self-hosted runner on the server that keeps one GitHub issue per finding: opened when new, updated only when its wording changes, closed when gone.
agree
- A compose environment value that is a number or boolean (
PORT: 2700) no longer stopsagree --composeat the decode. It is rendered as compose renders it and compared. - A file it could not read is named once, with slashes, on every OS. The message no longer repeats the absolute path from the OS error, and the Windows build no longer mixes
services\paste\…andservices/paste/…in one report.
Not yet
- A manifest's backup implying its own timer waits on Viglet Cloud's manifests (JCT23). Until then, list each timer under
host.timers.
Install
Download a binary below, or go install github.com/Japode/jcloud@v0.4.0.