pyrtan / sourcev0.19.0 · main

pyrtan / examples / site-status / site-status.toml

2,167 bytes · last changed 2026-10-26 in Watches and growing from a gap: trees that run when something speaks, and the branch a gap asks for drafted by rules; release 0.9.0

1# Is a site up? The host comes from the sentence, so it cannot be checked
2# at load time; the runtime refuses anything outside `hosts`, and this tree
3# allows any host on purpose, with the wildcard spelled out.
4
5name = "site-status"
6version = 2
7namespace = "pyrtan"
8description = "Whether a web site answers, and how quickly."
9tags = ["ops", "read-only"]
10license = "MIT"
11hosts = ["*"]
12start = "probe"
13
14[[triggers]]
15pattern = "is {host:host} up"
16[[triggers]]
17pattern = "is {host:host} down"
18[[triggers]]
19pattern = "[check] status of {host:host}"
20
21[inputs.host]
22type = "str"
23pattern = "(?i)^[a-z0-9.\\-]+(:[0-9]+)?$"
24description = "A host name, with no scheme"
25
26# On its own, every quarter hour, for one host; `pyrtan watches` shows the
27# last run and whether the path changed since the run before (up -> down).
28[[watches]]
29name = "example.com"
30every = "15m"
31inputs = { host = "example.com" }
32
33[nodes.probe]
34kind = "observe"
35http = { method = "GET", url = "https://{{ inputs.host | lower }}/" }
36into = "resp"
37timeout = 8
38retries = 1
39next = "status"
40
41[nodes.status]
42kind = "decide"
43on = "resp.status"
44branches = [
45 { when = { between = [200, 399] }, then = "up" },
46 { when = { between = [400, 499] }, then = "refusing" },
47 { when = { gte = 500 }, then = "erroring" },
48 { else = "odd" },
49]
50
51[nodes.up]
52kind = "done"
53say = "{{ inputs.host }} is up: {{ state.resp.status }} in {{ state.resp.elapsed_ms }} ms."
54output = { host = "{{ inputs.host }}", up = true, status = "{{ state.resp.status }}", elapsed_ms = "{{ state.resp.elapsed_ms }}" }
55
56[nodes.refusing]
57kind = "done"
58say = "{{ inputs.host }} answers but refuses the front page ({{ state.resp.status }}); the server is up."
59output = { host = "{{ inputs.host }}", up = true, status = "{{ state.resp.status }}", note = "client error on /" }
60
61[nodes.erroring]
62kind = "fail"
63reason = "server-error"
64say = "{{ inputs.host }} is answering {{ state.resp.status }}: up, but broken."
65output = { host = "{{ inputs.host }}", up = false, status = "{{ state.resp.status }}" }
66
67[nodes.odd]
68kind = "fail"
69reason = "unexpected-status"
70say = "{{ inputs.host }} answered {{ state.resp.status }}, which this tree has no branch for."