summaryrefslogtreecommitdiff
path: root/README.md
blob: e4c83a68cc29828cf7df635c11d5b42f046528f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# umbrella

A safety-critical game server admin daemon written in C11. Monitors
multiple server processes via log file tailing, RCON, and A2S probing,
and exposes a Unix socket for CLI clients to attach, send commands, and
receive real-time output.

## Features

- Live log tailing via inotify with symlink resolution
- Pluggable per-unit output filters (any stdin→stdout executable)
- RCON command dispatch (Valve protocol)
- A2S health probing (Valve UDP)
- systemd unit state queries over D-Bus
- Ring buffer — 500 lines × 1024 bytes per unit, replayed on attach
- Reload without restart via SIGHUP

## Build

```bash
# Dependencies: libyaml-dev, libsystemd-dev
make
sudo make install
```

Compiler flags: `-Wall -Wextra -Wpedantic -std=c11 -D_GNU_SOURCE -O2`

## Install layout

| Path | Purpose |
|------|---------|
| `/usr/local/sbin/umbrella` | Daemon |
| `/usr/local/bin/umbrella-cli` | CLI client |
| `/etc/umbrella/umbrella.conf` | Daemon config |
| `/etc/umbrella/units/*.yaml` | Unit descriptors |
| `/usr/lib/umbrella/filters/` | Bundled log filters |
| `/run/umbrella/umbrella.sock` | Unix socket |
| `/run/umbrella/umbrella.pid` | PID file |
| `/var/log/umbrella/umbrella.log` | Daemon log |

## Unit descriptor format

```yaml
name: tf2                          # used in CLI commands
display: "TF2 — novemen"
service: tf2-server.service        # systemd unit for state queries

console:
  type: rcon                       # rcon | stdin
  host: 127.0.0.1
  port: 27015
  password_env: TF_RCON_PASSWORD   # or: password: plaintext

health:
  type: a2s                        # a2s | tcp | none
  host: 127.0.0.1
  port: 27015
  timeout_ms: 5000

logs:
  - /path/to/logs/current.log      # up to 4 paths; symlinks resolved

# Optional filter — any executable reading stdin, writing stdout
log_filter: /usr/lib/umbrella/filters/source.py

broadcast_cmd: "say {msg}"         # template for !broadcast

actions:
  update:  /path/to/update.sh
  restart: /usr/bin/systemctl restart tf2-server.service
```

## Bundled filters

| Filter | Targets |
|--------|---------|
| `source.py` | TF2, GMod, CS2 — strips `server_cvar`/stuck spam, strips timestamp prefix |
| `minecraft.py` | vanilla/Paper/Spigot — strips keepAlive/autosave noise, strips `[HH:MM:SS] [thread]` prefix |
| `terraria.py` | vanilla/tModLoader — strips blank lines and mod-loading spam |

Custom filters: any executable at any path that reads stdin and flushes
stdout after each write works. Python, shell, compiled binary — anything.

## Log file setup

srcds and most dedicated servers create new log files per session.
Point `logs:` at a stable symlink and update it on each server start:

```bash
# In your startup script / ExecStartPre:
ln -sf /srv/game/logs/L0222000.log /srv/game/logs/current.log
# Then SIGHUP umbrella so it re-resolves the symlink:
kill -HUP $(cat /run/umbrella/umbrella.pid)
```

With `sv_log_onefile 1` (Source engine), the log file is fixed for the
server's lifetime, so the symlink only needs updating on restarts.

## CLI usage

```bash
umbrella-cli list
umbrella-cli status <unit>
umbrella-cli attach <unit>         # live output; Ctrl+D to detach
umbrella-cli tail <unit>           # dump ring buffer and exit
umbrella-cli input <unit> <cmd>    # send RCON command or stdin line
umbrella-cli action <unit> <name>  # run a named action script
umbrella-cli broadcast <message>   # send to all units' broadcast_cmd
```

## Reload

```bash
kill -HUP $(cat /run/umbrella/umbrella.pid)
```

Reloads unit YAML files, restarts log tails and filter subprocesses.
Running processes are not touched.