From 6760bc5c2e98ebdc89b74b84e8f8e93e4881e2dd Mon Sep 17 00:00:00 2001 From: jwansek Date: Tue, 8 Apr 2025 23:08:19 +0100 Subject: Re-added the services page --- .gitignore | 2 + app.py | 13 +++++- requirements.txt | 8 ++-- services.py | 74 +++++++++++++++++++++++++++++-- static/index.md | 2 + templates/services.html.j2 | 106 ++++++++++++++------------------------------- 6 files changed, 123 insertions(+), 82 deletions(-) diff --git a/.gitignore b/.gitignore index 2c678d3..087b0b3 100755 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +*.pem +*.pub homelab-wiki/wiki.env homelab-wiki/images/* edaweb.conf diff --git a/app.py b/app.py index 50d5b5b..985bcac 100755 --- a/app.py +++ b/app.py @@ -2,7 +2,7 @@ from paste.translogger import TransLogger from waitress import serve from PIL import Image import configparser -import webbrowser +import transmission_rpc import downloader import datetime import database @@ -78,6 +78,17 @@ def index(): def robots(): return flask.send_from_directory("static", "robots.txt") +@app.route("/services") +def serve_services(): + with database.Database() as db: + return flask.render_template( + "services.html.j2", + **get_template_items("services", db), + docker = services.get_all_docker_containers(CONFIG.get("ssh", "docker_key_path")), + trans = services.get_torrent_stats(), + pihole = services.get_pihole_stats() + ) + @app.route("/discord") def discord(): with database.Database() as db: diff --git a/requirements.txt b/requirements.txt index 0ce280b..581cd7c 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,15 +1,13 @@ itsdangerous==2.0.1 PyMySQL==1.0.2 -python_qbittorrent==0.4.2 +transmission_rpc==4.1.0 Werkzeug==2.3.7 Flask==2.2.2 PiHole_api -transmission-clutch dataclasses docker -PiHole-api +APiHole Pillow==9.4.0 -python-qbittorrent==0.4.2 PyGithub lxml requests @@ -19,3 +17,5 @@ houdini.py Pygments mistune==2.0.3 twython==3.8.2 +fabric +paramiko \ No newline at end of file diff --git a/services.py b/services.py index b56a07d..5fb7d81 100755 --- a/services.py +++ b/services.py @@ -3,8 +3,9 @@ from io import StringIO from lxml import html, etree from github import Github import multiprocessing -import pihole as ph -import qbittorrent +import paramiko.client +from APiHole import PiHole +import transmission_rpc import configparser import math as maths import requests @@ -12,6 +13,8 @@ import datetime import urllib import docker import random +import subprocess +import fabric import queue import json import time @@ -266,6 +269,68 @@ def scrape_whispa(whispa_url, since): }) return qnas +def get_docker_containers(host, ssh_key_path): + result = fabric.Connection( + host = host, + user = "root", + connect_kwargs = { + "key_filename": ssh_key_path, + "look_for_keys": False + } + ).run('docker ps -a -s --format "table {{.Names}};{{.Status}};{{.Image}}"', hide = True) + return [line.split(";") for line in result.stdout.split("\n")[1:-1]] + +def get_all_docker_containers(ssh_key_path): + containers = {} + for host, name in CONFIG["docker_hosts"].items(): + print(host) + containers[(host, name)] = get_docker_containers(host, ssh_key_path) + return containers + +def timeout(func): + # cant get this to work with queue.Queue() for some reason? + # this works but Manager() uses an extra thread than Queue() + manager = multiprocessing.Manager() + returnVan = manager.list() + # ti = time.time() + + def runFunc(q, func): + q.append(func()) + + def beginTimeout(): + t = multiprocessing.Process(target = runFunc, args = (returnVan, func)) + t.start() + + t.join(timeout = CONFIG["servicetimeout"].getint("seconds")) + + # print("Request took:", time.time() - ti) + try: + return returnVan[0] + except IndexError: + if t.is_alive(): + t.terminate() + + return beginTimeout + +@timeout +def get_torrent_stats(): + client = transmission_rpc.client.Client( + host = CONFIG.get("transmission", "host") + ) + s = vars(client.session_stats())["fields"] + return { + "Active torrents:": s["activeTorrentCount"], + "Downloaded:": humanbytes(s["cumulative-stats"]["downloadedBytes"]), + "Uploaded:": humanbytes(s["cumulative-stats"]["uploadedBytes"]), + "Active time:": str(datetime.timedelta(seconds = s["cumulative-stats"]["secondsActive"])), + "Files added:": s["cumulative-stats"]["filesAdded"], + "Current upload speed": humanbytes(s["uploadSpeed"]) + "s/S", + "Current download speed:": humanbytes(s["downloadSpeed"]) + "s/S" + } + +@timeout +def get_pihole_stats(): + return PiHole.GetSummary(CONFIG.get("pihole", "url"), CONFIG.get("pihole", "key"), True) if __name__ == "__main__": # print(get_trans_stats()) @@ -277,4 +342,7 @@ if __name__ == "__main__": # print(request_recent_commits(since = datetime.datetime.now() - datetime.timedelta(days=30))) - print(scrape_whispa(CONFIG.get("qnas", "url"), datetime.datetime.fromtimestamp(0.0))) + # print(scrape_whispa(CONFIG.get("qnas", "url"), datetime.datetime.fromtimestamp(0.0))) + # print(get_all_docker_containers(os.path.join(os.path.dirname(__file__), "edaweb-docker.pem"))) + + print(get_torrent_stats()) diff --git a/static/index.md b/static/index.md index 99bfa0c..39bbc7c 100755 --- a/static/index.md +++ b/static/index.md @@ -16,6 +16,8 @@ i'll post my thoughts on here sometimes, and use this site to link to other stuf - [git server - github alternative](https://git.eda.gay/) - [jellyfin - web player for ~~legally downloaded~~ TV and films](https://jellyfin.eda.gay) - RIP emby! +[see the services im running right now](/services) (takes a couple seconds to load) + these sites are hosted on my [homelab system](https://wiki.eda.gay) ![startech 8u rack cropped](/img/GcyexeCW0AAYssz.jpg?w=300&h=5000) diff --git a/templates/services.html.j2 b/templates/services.html.j2 index ebf8ebd..9c9e5ec 100755 --- a/templates/services.html.j2 +++ b/templates/services.html.j2 @@ -3,96 +3,54 @@

docker

- {% if docker == None %} -

Couldn't access the docker API. Is sherpa running?

- {% else %} - - {% for name, status in docker.items() %} - - - {% if status == "running" %} - - {% else %} - - {% endif %} - - {% endfor %} -
{{name}}{{status}}{{status}}
- {% endif %} +
    + {% for host, containers in docker.items() %} +

    {{ "%s - %s" % (host[0], host[1]) }}

    + + {% for name, status, image in containers %} + + + {% if "Up" in status %} + + {% else %} + + {% endif %} + + + {% endfor %} +
    {{ name }}{{ status }}{{ status }}{{ image }}
    + {% endfor %} +
+

transmission

{% if trans == None %}

Couldn't access the transmission API. Is docker container running?

{% else %} - - - - - - - - - - - - - - - - - - - - + {% for k, v in trans.items() %} + + + + + {% endfor %}
downloaded{{trans["bytes_dl"]}}
uploaded{{trans["bytes_up"]}}
torrents{{trans["num"]}}
ratio{{trans["ratio"]}}
active for{{trans["active_for"]}}
{{ k }}{{ v }}
{% endif %} -
- statistics of some old torrent clients which were shut down recently ;_; -
- - -
+

pihole

{% if pihole == None %}

Couldn't access the pihole API. Is docker container running?

{% else %} - - - {% if pihole["status"] == "enabled" %} - - {% else %} - - {% endif %} - - - - - - - - - - - - - - - - - - - - - - - - - + {% for k, v in pihole.items() %} + + + + + {% endfor %}
status{{pihole["status"]}}{{pihole["status"]}}
queries{{pihole["queries"]}}
clients{{pihole["clients"]}}
percentage blocked{{pihole["percentage"]}}%
blocked requests{{pihole["blocked"]}}
domains in blocklist{{pihole["domains"]}}
last updated{{pihole["last_updated"]}}
{{ k }}{{ v }}
{% endif %}
-- cgit v1.2.3