scripts/check-instances.py

v1.5.2
skunky-art/scripts/check-instances.py history · blame · raw

55 lines · 1492 bytes · executable

 1#!/usr/bin/env python3
 2"""Check every clearnet instance in instances.json.
 3
 4Fetches /api/instance from each and prints one line per instance. Exits 1 if
 5any is down, so a scheduled CI job turns red and INSTANCES.md does not keep
 6listing dead links. Tor, I2P and Yggdrasil addresses are skipped: the runner
 7cannot reach them.
 8"""
 9
10import json
11import sys
12import urllib.error
13import urllib.request
14
15TIMEOUT = 15
16
17
18def check(url):
19    req = urllib.request.Request(
20        url.rstrip("/") + "/api/instance",
21        headers={"User-Agent": "skunkyart-instance-check"},
22    )
23    try:
24        with urllib.request.urlopen(req, timeout=TIMEOUT) as resp:
25            info = json.load(resp)
26    except (urllib.error.URLError, json.JSONDecodeError, TimeoutError) as err:
27        return None, str(err)
28    return info.get("version", "?"), None
29
30
31def main():
32    with open("instances.json", encoding="utf-8") as f:
33        instances = json.load(f)["instances"]
34
35    failed = 0
36    for inst in instances:
37        url = inst.get("urls", {}).get("clearnet")
38        if not url:
39            print(f"{inst['title']}: no clearnet url, skipped")
40            continue
41        version, err = check(url)
42        if err:
43            failed += 1
44            print(f"{inst['title']}: DOWN {url} ({err})")
45        else:
46            print(f"{inst['title']}: ok {url} v{version}")
47
48    if failed:
49        print(f"{failed} instance(s) down")
50        return 1
51    return 0
52
53
54if __name__ == "__main__":
55    sys.exit(main())