install as service
This commit is contained in:
@@ -55,6 +55,13 @@ Run the service; host, port, and URL prefix all come from `config.yaml`:
|
||||
.venv/bin/python wsgi.py
|
||||
```
|
||||
|
||||
For production, use the Waitress entry point. It reads host, port, thread count,
|
||||
and all application settings from `config.yaml`:
|
||||
|
||||
```sh
|
||||
.venv/bin/python serve.py
|
||||
```
|
||||
|
||||
With the example settings, open <http://localhost:30225/w/>. Keep one application worker because the polling
|
||||
scheduler runs inside the service process. Alternatively set
|
||||
`collector.enabled: false` in web workers and invoke this from a system timer:
|
||||
@@ -78,6 +85,42 @@ The service account must have write permission on the log directory. Console
|
||||
logging remains enabled by default so `python wsgi.py` displays its listening
|
||||
address; set `logging.console: false` to use only the logfile.
|
||||
|
||||
## systemd installation
|
||||
|
||||
The included `deploy/netatmo.service` runs Waitress from `/srv/service_netatmo`
|
||||
under a dedicated, non-login `netatmo` account. As root, create the account and
|
||||
writable data directory:
|
||||
|
||||
```sh
|
||||
useradd --system --home-dir /srv/service_netatmo --shell /usr/sbin/nologin netatmo
|
||||
install -d -o netatmo -g netatmo -m 0750 /var/lib/rrd
|
||||
chown netatmo:netatmo /srv/service_netatmo/config.yaml
|
||||
chmod 0600 /srv/service_netatmo/config.yaml
|
||||
```
|
||||
|
||||
Create the virtual environment and install dependencies as that account:
|
||||
|
||||
```sh
|
||||
sudo -u netatmo python3 -m venv /srv/service_netatmo/.venv
|
||||
sudo -u netatmo /srv/service_netatmo/.venv/bin/pip install -r /srv/service_netatmo/requirements.txt
|
||||
```
|
||||
|
||||
Install and start the unit:
|
||||
|
||||
```sh
|
||||
install -o root -g root -m 0644 /srv/service_netatmo/deploy/netatmo.service /etc/systemd/system/netatmo.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now netatmo.service
|
||||
systemctl status netatmo.service
|
||||
```
|
||||
|
||||
Follow service output and the rotating application log with:
|
||||
|
||||
```sh
|
||||
journalctl -u netatmo.service -f
|
||||
tail -f /var/lib/rrd/netatmo_service.log
|
||||
```
|
||||
|
||||
## HTTP API
|
||||
|
||||
```text
|
||||
|
||||
+3
-2
@@ -2,6 +2,7 @@
|
||||
server:
|
||||
host: 127.0.0.1
|
||||
port: 30225
|
||||
threads: 4
|
||||
url_prefix: /w
|
||||
|
||||
storage:
|
||||
@@ -23,8 +24,8 @@ graphs:
|
||||
height: 240
|
||||
|
||||
netatmo:
|
||||
client_id: 6a93db3d7cdb0e40ea0c2655
|
||||
client_secret: c6uRbAzZ9e8STPtXas6PYKaZZiD68Y6QHFaKq2GEIa8
|
||||
client_id: REPLACE_ME
|
||||
client_secret: REPLACE_ME
|
||||
redirect_uri: http://www.example.com/w
|
||||
token_file: /var/lib/rrd/netatmo_tokens.json
|
||||
device_id: ""
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
[Unit]
|
||||
Description=Netatmo RRD Flask service (Waitress)
|
||||
Documentation=file:///srv/service_netatmo/README.md
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=netatmo
|
||||
Group=netatmo
|
||||
WorkingDirectory=/srv/service_netatmo
|
||||
ExecStart=/srv/service_netatmo/.venv/bin/python /srv/service_netatmo/serve.py
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
TimeoutStopSec=30
|
||||
UMask=0077
|
||||
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectHome=true
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/var/lib/rrd
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -20,7 +20,7 @@ def default_config(base: Path | None = None) -> dict[str, Any]:
|
||||
base = (base or Path.cwd()).resolve()
|
||||
rrd = base / "rrd"
|
||||
return {
|
||||
"HOST": "0.0.0.0", "PORT": 5000, "URL_PREFIX": "", "RRD_FOLDER": rrd,
|
||||
"HOST": "0.0.0.0", "PORT": 5000, "THREADS": 4, "URL_PREFIX": "", "RRD_FOLDER": rrd,
|
||||
"LOG_FILE": rrd / "netatmo_service.log", "LOG_LEVEL": "INFO",
|
||||
"LOG_MAX_BYTES": 5242880, "LOG_BACKUP_COUNT": 5, "LOG_CONSOLE": True,
|
||||
"NETATMO_TOKEN_FILE": rrd / "netatmo_tokens.json",
|
||||
@@ -63,6 +63,7 @@ def load_config(filename: str | Path | None = None) -> dict[str, Any]:
|
||||
result.update({
|
||||
"HOST": str(server.get("host", result["HOST"])),
|
||||
"PORT": int(server.get("port", result["PORT"])),
|
||||
"THREADS": int(server.get("threads", result["THREADS"])),
|
||||
"URL_PREFIX": _prefix(server.get("url_prefix", result["URL_PREFIX"])),
|
||||
"GRAPH_WIDTH": int(graphs.get("width", result["GRAPH_WIDTH"])),
|
||||
"GRAPH_HEIGHT": int(graphs.get("height", result["GRAPH_HEIGHT"])),
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
# run as root
|
||||
|
||||
useradd --system --home-dir /srv/service_netatmo --shell /usr/sbin/nologin netatmo
|
||||
install -d -o netatmo -g netatmo -m 0750 /var/lib/rrd
|
||||
|
||||
chown netatmo:netatmo /srv/service_netatmo/config.yaml
|
||||
chmod 0600 /srv/service_netatmo/config.yaml
|
||||
|
||||
# sudo -u netatmo python3 -m venv /srv/service_netatmo/.venv
|
||||
# sudo -u netatmo /srv/service_netatmo/.venv/bin/pip install \
|
||||
-r /srv/service_netatmo/requirements.txt
|
||||
|
||||
install -o root -g root -m 0644 \
|
||||
/srv/service_netatmo/deploy/netatmo.service \
|
||||
/etc/systemd/system/netatmo.service
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now netatmo.service
|
||||
systemctl status netatmo.service
|
||||
@@ -1,4 +1,5 @@
|
||||
Flask>=3.1,<4
|
||||
PyYAML>=6.0,<7
|
||||
waitress>=3.0,<4
|
||||
rrdtool-bindings # if python 3.14
|
||||
rrdtool # if python 3.12
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
"""Production entry point using Waitress and config.yaml."""
|
||||
|
||||
from waitress import serve
|
||||
|
||||
from wsgi import app
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
serve(
|
||||
app,
|
||||
host=app.config["HOST"],
|
||||
port=app.config["PORT"],
|
||||
threads=app.config["THREADS"],
|
||||
)
|
||||
@@ -8,6 +8,7 @@ def test_yaml_config_is_loaded_and_relative_paths_are_resolved(tmp_path):
|
||||
server:
|
||||
host: 127.0.0.1
|
||||
port: 12345
|
||||
threads: 6
|
||||
url_prefix: weather/
|
||||
storage:
|
||||
rrd_folder: data
|
||||
@@ -27,6 +28,7 @@ modules:
|
||||
config = load_config(config_file)
|
||||
assert config["HOST"] == "127.0.0.1"
|
||||
assert config["PORT"] == 12345
|
||||
assert config["THREADS"] == 6
|
||||
assert config["URL_PREFIX"] == "/weather"
|
||||
assert config["RRD_FOLDER"] == tmp_path / "data"
|
||||
assert config["LOG_FILE"] == tmp_path / "logs/service.log"
|
||||
|
||||
Reference in New Issue
Block a user