From 4048b3327a3564993fe26869ca4fd8cf34c43728 Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Mallo Date: Fri, 23 May 2025 15:40:09 +0200 Subject: [PATCH] Add meteocat exporter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows us to track ambient temperature changes and estimate the temperature delta between the server room and exterior temperature. We should be able to predict when we would need to stop the machines due to excesive temperature as summer approaches. Reviewed-by: Aleix Boné --- m/hut/monitoring.nix | 2 + m/module/meteocat-exporter.nix | 17 ++++++++ pkgs/meteocat-exporter/default.nix | 25 +++++++++++ pkgs/meteocat-exporter/meteocat-exporter | 54 ++++++++++++++++++++++++ pkgs/meteocat-exporter/setup.py | 11 +++++ pkgs/overlay.nix | 1 + 6 files changed, 110 insertions(+) create mode 100644 m/module/meteocat-exporter.nix create mode 100644 pkgs/meteocat-exporter/default.nix create mode 100644 pkgs/meteocat-exporter/meteocat-exporter create mode 100644 pkgs/meteocat-exporter/setup.py diff --git a/m/hut/monitoring.nix b/m/hut/monitoring.nix index 4f1352e0..8f1bea44 100644 --- a/m/hut/monitoring.nix +++ b/m/hut/monitoring.nix @@ -3,6 +3,7 @@ { imports = [ ../module/slurm-exporter.nix + ../module/meteocat-exporter.nix ./gpfs-probe.nix ./nix-daemon-exporter.nix ]; @@ -110,6 +111,7 @@ "127.0.0.1:9341" # Slurm exporter "127.0.0.1:9966" # GPFS custom exporter "127.0.0.1:9999" # Nix-daemon custom exporter + "127.0.0.1:9929" # Meteocat custom exporter "127.0.0.1:${toString config.services.prometheus.exporters.blackbox.port}" ]; }]; diff --git a/m/module/meteocat-exporter.nix b/m/module/meteocat-exporter.nix new file mode 100644 index 00000000..ffc03385 --- /dev/null +++ b/m/module/meteocat-exporter.nix @@ -0,0 +1,17 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + systemd.services."prometheus-meteocat-exporter" = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + Restart = mkDefault "always"; + PrivateTmp = mkDefault true; + WorkingDirectory = mkDefault "/tmp"; + DynamicUser = mkDefault true; + ExecStart = "${pkgs.meteocat-exporter}/bin/meteocat-exporter"; + }; + }; +} diff --git a/pkgs/meteocat-exporter/default.nix b/pkgs/meteocat-exporter/default.nix new file mode 100644 index 00000000..5bc4f096 --- /dev/null +++ b/pkgs/meteocat-exporter/default.nix @@ -0,0 +1,25 @@ +{ python3Packages, lib }: + +python3Packages.buildPythonApplication rec { + pname = "meteocat-exporter"; + version = "1.0"; + + src = ./.; + + doCheck = false; + + build-system = with python3Packages; [ + setuptools + ]; + + dependencies = with python3Packages; [ + beautifulsoup4 + lxml + prometheus-client + ]; + + meta = with lib; { + description = "MeteoCat Prometheus Exporter"; + platforms = platforms.linux; + }; +} diff --git a/pkgs/meteocat-exporter/meteocat-exporter b/pkgs/meteocat-exporter/meteocat-exporter new file mode 100644 index 00000000..acc9f3e3 --- /dev/null +++ b/pkgs/meteocat-exporter/meteocat-exporter @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 + +import time +from prometheus_client import start_http_server, Gauge +from bs4 import BeautifulSoup +from urllib import request + +# Configuration ------------------------------------------- +meteo_station = "X8" # Barcelona - Zona Universitària +listening_port = 9929 +update_period = 60 * 5 # Each 5 min +# --------------------------------------------------------- + +metric_tmin = Gauge('meteocat_temp_min', 'Min temperature') +metric_tmax = Gauge('meteocat_temp_max', 'Max temperature') +metric_tavg = Gauge('meteocat_temp_avg', 'Average temperature') +metric_srad = Gauge('meteocat_solar_radiation', 'Solar radiation') + +def update(st): + url = 'https://www.meteo.cat/observacions/xema/dades?codi=' + st + response = request.urlopen(url) + data = response.read() + soup = BeautifulSoup(data, 'lxml') + table = soup.find("table", {"class" : "tblperiode"}) + rows = table.find_all('tr') + row = rows[-1] # Take the last row + row_data = [] + header = row.find('th') + header_text = header.text.strip() + row_data.append(header_text) + for col in row.find_all('td'): + row_data.append(col.text) + try: + # Sometimes it will return '(s/d)' and fail to parse + metric_tavg.set(float(row_data[1])) + metric_tmax.set(float(row_data[2])) + metric_tmin.set(float(row_data[3])) + metric_srad.set(float(row_data[10])) + #print("ok: temp_avg={}".format(float(row_data[1]))) + except: + print("cannot parse row: {}".format(row)) + metric_tavg.set(float("nan")) + metric_tmax.set(float("nan")) + metric_tmin.set(float("nan")) + metric_srad.set(float("nan")) + +if __name__ == '__main__': + start_http_server(port=listening_port, addr="localhost") + while True: + try: + update(meteo_station) + except: + print("update failed") + time.sleep(update_period) diff --git a/pkgs/meteocat-exporter/setup.py b/pkgs/meteocat-exporter/setup.py new file mode 100644 index 00000000..9cc74d3d --- /dev/null +++ b/pkgs/meteocat-exporter/setup.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +from setuptools import setup, find_packages + +setup(name='meteocat-exporter', + version='1.0', + # Modules to import from other scripts: + packages=find_packages(), + # Executables + scripts=["meteocat-exporter"], + ) diff --git a/pkgs/overlay.nix b/pkgs/overlay.nix index 2eb92295..995ceebe 100644 --- a/pkgs/overlay.nix +++ b/pkgs/overlay.nix @@ -54,4 +54,5 @@ final: prev: }); prometheus-slurm-exporter = prev.callPackage ./slurm-exporter.nix { }; + meteocat-exporter = prev.callPackage ./meteocat-exporter/default.nix { }; }