pyrtan / examples / disk-space / disk-space.toml
2,148 bytes · last changed 2026-10-26 in The catalog grows up: namespaces, publishing by pull request through the gate, gap reports gossiped back to authors; release 0.8.0
| 1 | # How full a filesystem is, by asking df on the box this tree runs on. A |
| 2 | # shell node runs one program by name, with its arguments as a list: no |
| 3 | # shell reads the line, so nothing in an argument is ever a command. |
| 4 | # `commands` is the allow-list, as `hosts` is for HTTP; `df` is all this |
| 5 | # tree may run. A service started with --egress public refuses shell nodes |
| 6 | # altogether: a hosted box is not lent out. |
| 7 | |
| 8 | name = "disk-space" |
| 9 | version = 2 |
| 10 | namespace = "pyrtan" |
| 11 | description = "How full a filesystem is, from df on the box this tree runs on." |
| 12 | tags = ["ops", "box", "read-only"] |
| 13 | license = "MIT" |
| 14 | commands = ["df"] |
| 15 | start = "df" |
| 16 | |
| 17 | [[triggers]] |
| 18 | pattern = "[how] full is the disk" |
| 19 | [[triggers]] |
| 20 | pattern = "disk space" |
| 21 | [[triggers]] |
| 22 | pattern = "disk space on {mount:word}" |
| 23 | |
| 24 | [inputs.mount] |
| 25 | type = "str" |
| 26 | default = "/" |
| 27 | description = "A mount point, or any path on the filesystem to measure" |
| 28 | |
| 29 | [nodes.df] |
| 30 | kind = "observe" |
| 31 | shell = { command = "df", args = ["-P", "{{ inputs.mount }}"] } |
| 32 | into = "df" # state.df = { command, args, status, ok, stdout, stderr, body, json, lines } |
| 33 | extract = [ |
| 34 | { into = "percent", regex = "(\\d+)%", group = 1 }, |
| 35 | { into = "mounted", regex = "%\\s+(\\S+)\\s*$", group = 1 }, |
| 36 | ] |
| 37 | next = "ran" |
| 38 | |
| 39 | [nodes.ran] |
| 40 | kind = "decide" |
| 41 | on = "df.ok" |
| 42 | branches = [{ when = { eq = true }, then = "number" }, { else = "failed" }] |
| 43 | |
| 44 | [nodes.number] |
| 45 | kind = "set" |
| 46 | set = { pct = "{{ state.percent | int }}" } |
| 47 | next = "level" |
| 48 | |
| 49 | [nodes.level] |
| 50 | kind = "decide" |
| 51 | on = "pct" |
| 52 | branches = [ |
| 53 | { when = { lt = 80 }, then = "fine" }, |
| 54 | { when = { lt = 95 }, then = "tight" }, |
| 55 | { else = "full" }, |
| 56 | ] |
| 57 | |
| 58 | [nodes.fine] |
| 59 | kind = "done" |
| 60 | say = "{{ state.mounted }} is {{ state.pct }}% full." |
| 61 | output = { mounted = "{{ state.mounted }}", percent = "{{ state.pct }}" } |
| 62 | |
| 63 | [nodes.tight] |
| 64 | kind = "done" |
| 65 | say = "{{ state.mounted }} is {{ state.pct }}% full; make room soon." |
| 66 | output = { mounted = "{{ state.mounted }}", percent = "{{ state.pct }}" } |
| 67 | |
| 68 | [nodes.full] |
| 69 | kind = "fail" |
| 70 | reason = "disk-full" |
| 71 | say = "{{ state.mounted }} is {{ state.pct }}% full." |
| 72 | |
| 73 | [nodes.failed] |
| 74 | kind = "fail" |
| 75 | reason = "df-failed" |
| 76 | say = "df could not measure {{ inputs.mount }}: {{ state.df.stderr | strip }}" |