From 5ad9f8a94e3ec7da9f88d98fc9b63fe6cf1116f8 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Thu, 15 Jan 2026 12:21:43 +0200 Subject: Disable Prometheus scraping of radicale service - add prometheus.io/scrape=false annotation and rename port to http --- f3s/radicale/helm-chart/templates/deployment.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/f3s/radicale/helm-chart/templates/deployment.yaml b/f3s/radicale/helm-chart/templates/deployment.yaml index 725fcba..b7022e5 100644 --- a/f3s/radicale/helm-chart/templates/deployment.yaml +++ b/f3s/radicale/helm-chart/templates/deployment.yaml @@ -55,11 +55,13 @@ kind: Service metadata: labels: app: radicale + annotations: + prometheus.io/scrape: "false" name: radicale-service namespace: services spec: ports: - - name: web + - name: http port: 80 protocol: TCP targetPort: 8080 -- cgit v1.2.3 From cf2f8a9c77adde891a85c6e4ab405ede95e6ec97 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Thu, 15 Jan 2026 19:31:19 +0200 Subject: Add IPv6 NAT and firewall rules to OpenBSD PF configuration Enable IPv6 support for WireGuard mesh network on OpenBSD gateways: - Added NAT66 rule using NPTv6 to translate ULA addresses to public IPv6 - Added IPv6 UDP pass rule for WireGuard port 56709 - Maintains existing IPv4 NAT and firewall rules This allows roaming clients to route IPv6 traffic through the VPN gateways and access IPv6 internet resources using the gateway's public IPv6 address. Co-Authored-By: Claude Sonnet 4.5 --- frontends/etc/pf.conf.tpl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/frontends/etc/pf.conf.tpl b/frontends/etc/pf.conf.tpl index 24c007e..5a33653 100644 --- a/frontends/etc/pf.conf.tpl +++ b/frontends/etc/pf.conf.tpl @@ -2,11 +2,16 @@ # # See pf.conf(5) and /etc/examples/pf.conf -# NAT for WireGuard clients to access internet +# NAT for WireGuard clients to access internet (IPv4) # This allows roaming clients (earth, pixel7pro) to route all traffic # through the VPN and access the internet via the gateway's public IP match out on vio0 from 192.168.2.0/24 to any nat-to (vio0) +# NAT66 for WireGuard clients to access internet (IPv6) +# This allows roaming clients to route IPv6 traffic through the VPN +# Uses NPTv6 (Network Prefix Translation) to translate ULA to public IPv6 +match out on vio0 inet6 from fd42:beef:cafe:2::/64 to any nat-to (vio0) + set skip on lo block return # block stateless traffic @@ -22,6 +27,7 @@ block return out log proto {tcp udp} user _pbuild # This permits traffic from VPN clients to access services on this host pass in on wg0 -# Allow all UDP traffic on WireGuard port +# Allow all UDP traffic on WireGuard port (IPv4 and IPv6) # This is required for WireGuard's encrypted tunnel communication pass in inet proto udp from any to any port 56709 +pass in inet6 proto udp from any to any port 56709 -- cgit v1.2.3 From 03eb96f968a6d2cecb2bdf1d23accf51a270188e Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Thu, 15 Jan 2026 19:32:46 +0200 Subject: Update monitoring and gogios configuration - Add node resources multi-select dashboard for Prometheus - Update gogios cron schedule and add HTML status file output - Update Prometheus scrape configs - Add gogios documentation Co-Authored-By: Claude Sonnet 4.5 --- f3s/prometheus/additional-scrape-configs.yaml | 30 + .../node-resources-multi-select-dashboard.yaml | 662 +++++++++++++++++++++ frontends/etc/gogios.cron.tpl | 2 +- frontends/etc/gogios.json.tpl | 1 + snippets/go/go-projects/gogios.md | 9 + 5 files changed, 703 insertions(+), 1 deletion(-) create mode 100644 f3s/prometheus/manifests/node-resources-multi-select-dashboard.yaml create mode 100644 snippets/go/go-projects/gogios.md diff --git a/f3s/prometheus/additional-scrape-configs.yaml b/f3s/prometheus/additional-scrape-configs.yaml index be118df..21cbf1f 100644 --- a/f3s/prometheus/additional-scrape-configs.yaml +++ b/f3s/prometheus/additional-scrape-configs.yaml @@ -18,4 +18,34 @@ - targets: - 'pushgateway.monitoring.svc.cluster.local:9091' +# Drop radicale service from being scraped (does not expose Prometheus metrics) +- job_name: 'radicale-drop' + static_configs: + - targets: + - 'radicale-service.services.svc.cluster.local:80' + relabel_configs: + - source_labels: [__address__] + action: drop + +# Kubernetes service discovery with radicale dropped +- job_name: 'kubernetes-services-no-radicale' + kubernetes_sd_configs: + - role: service + namespaces: + names: + - services + relabel_configs: + # Drop radicale service + - source_labels: [__meta_kubernetes_service_name] + regex: radicale-service + action: drop + # Keep only metrics ports + - source_labels: [__meta_kubernetes_service_port_name] + regex: metrics|prometheus + action: keep + - source_labels: [__meta_kubernetes_service_name] + target_label: job + - source_labels: [__meta_kubernetes_namespace] + target_label: namespace + diff --git a/f3s/prometheus/manifests/node-resources-multi-select-dashboard.yaml b/f3s/prometheus/manifests/node-resources-multi-select-dashboard.yaml new file mode 100644 index 0000000..05ec93a --- /dev/null +++ b/f3s/prometheus/manifests/node-resources-multi-select-dashboard.yaml @@ -0,0 +1,662 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: node-resources-multi-select-dashboard + namespace: monitoring + annotations: + argocd.argoproj.io/sync-wave: "4" + labels: + grafana_dashboard: '1' + app.kubernetes.io/instance: prometheus + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: kube-prometheus-stack + release: prometheus +data: + node-resources-multi.json: |- + { + "title": "Node Resources - Multi Select", + "uid": "node-resources-multi", + "timezone": "browser", + "schemaVersion": 38, + "refresh": "30s", + "tags": [ + "node-exporter", + "nodes", + "resources" + ], + "editable": true, + "templating": { + "list": [ + { + "name": "datasource", + "type": "datasource", + "query": "prometheus", + "hide": 0 + }, + { + "name": "instance", + "type": "query", + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "query": "label_values(node_uname_info, instance)", + "refresh": 2, + "hide": 0, + "label": "Nodes", + "includeAll": true, + "allValue": ".*", + "multi": true, + "sort": 1 + } + ] + }, + "panels": [ + { + "type": "row", + "collapsed": false, + "title": "CPU Usage", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + } + }, + { + "type": "timeseries", + "title": "CPU Usage % (all cores)", + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 1 + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "targets": [ + { + "expr": "100 - (avg(rate(node_cpu_seconds_total{mode=\"idle\",instance=~\"$instance\"}[5m])) by (instance) * 100)", + "legendFormat": "{{instance}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "custom": { + "fillOpacity": 20, + "showPoints": "never" + } + } + }, + "options": { + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true + } + } + }, + { + "type": "gauge", + "title": "CPU Usage % (Current)", + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 1 + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "targets": [ + { + "expr": "100 - (avg(rate(node_cpu_seconds_total{mode=\"idle\",instance=~\"$instance\"}[5m])) by (instance) * 100)", + "legendFormat": "{{instance}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "custom": { + "hideFrom": { + "tooltip": false, + "viz": false, + "legend": false + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 70 + }, + { + "color": "red", + "value": 90 + } + ] + } + } + }, + "options": { + "orientation": "auto", + "textMode": "value_and_name", + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ] + } + } + }, + { + "type": "row", + "collapsed": false, + "title": "Memory Usage", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + } + }, + { + "type": "timeseries", + "title": "Memory Usage %", + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 10 + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "targets": [ + { + "expr": "100 * (1 - ((node_memory_MemAvailable_bytes{instance=~\"$instance\"} or (node_memory_MemFree_bytes{instance=~\"$instance\"} + node_memory_Buffers_bytes{instance=~\"$instance\"} + node_memory_Cached_bytes{instance=~\"$instance\"})) / node_memory_MemTotal_bytes{instance=~\"$instance\"}))", + "legendFormat": "{{instance}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "custom": { + "fillOpacity": 20, + "showPoints": "never" + } + } + }, + "options": { + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true + } + } + }, + { + "type": "gauge", + "title": "Memory Usage % (Current)", + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 10 + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "targets": [ + { + "expr": "100 * (1 - ((node_memory_MemAvailable_bytes{instance=~\"$instance\"} or (node_memory_MemFree_bytes{instance=~\"$instance\"} + node_memory_Buffers_bytes{instance=~\"$instance\"} + node_memory_Cached_bytes{instance=~\"$instance\"})) / node_memory_MemTotal_bytes{instance=~\"$instance\"}))", + "legendFormat": "{{instance}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 70 + }, + { + "color": "red", + "value": 90 + } + ] + } + } + }, + "options": { + "orientation": "auto", + "textMode": "value_and_name", + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ] + } + } + }, + { + "type": "row", + "collapsed": false, + "title": "Disk Usage", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 18 + } + }, + { + "type": "timeseries", + "title": "Disk Usage % (root /)", + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 19 + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "targets": [ + { + "expr": "100 * (node_filesystem_size_bytes{instance=~\"$instance\",mountpoint=\"/\",fstype!=\"tmpfs\"} - node_filesystem_avail_bytes{instance=~\"$instance\",mountpoint=\"/\",fstype!=\"tmpfs\"}) / node_filesystem_size_bytes{instance=~\"$instance\",mountpoint=\"/\",fstype!=\"tmpfs\"}", + "legendFormat": "{{instance}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "custom": { + "fillOpacity": 20, + "showPoints": "never" + } + } + }, + "options": { + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true + } + } + }, + { + "type": "gauge", + "title": "Disk Usage % (root / - Current)", + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 19 + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "targets": [ + { + "expr": "100 * (node_filesystem_size_bytes{instance=~\"$instance\",mountpoint=\"/\",fstype!=\"tmpfs\"} - node_filesystem_avail_bytes{instance=~\"$instance\",mountpoint=\"/\",fstype!=\"tmpfs\"}) / node_filesystem_size_bytes{instance=~\"$instance\",mountpoint=\"/\",fstype!=\"tmpfs\"}", + "legendFormat": "{{instance}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 70 + }, + { + "color": "red", + "value": 85 + } + ] + } + } + }, + "options": { + "orientation": "auto", + "textMode": "value_and_name", + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ] + } + } + }, + { + "type": "row", + "collapsed": false, + "title": "Network I/O", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + } + }, + { + "type": "timeseries", + "title": "Network Bytes Received", + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 28 + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "targets": [ + { + "expr": "rate(node_network_receive_bytes_total{instance=~\"$instance\",device!~\"^(lo|veth.*|docker.*|br.*|virbr.*)$\"}[5m])", + "legendFormat": "{{instance}} - {{device}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "Bps", + "custom": { + "fillOpacity": 20, + "showPoints": "never" + } + } + }, + "options": { + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true + } + } + }, + { + "type": "timeseries", + "title": "Network Bytes Transmitted", + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 28 + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "targets": [ + { + "expr": "rate(node_network_transmit_bytes_total{instance=~\"$instance\",device!~\"^(lo|veth.*|docker.*|br.*|virbr.*)$\"}[5m])", + "legendFormat": "{{instance}} - {{device}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "Bps", + "custom": { + "fillOpacity": 20, + "showPoints": "never" + } + } + }, + "options": { + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true + } + } + }, + { + "type": "row", + "collapsed": false, + "title": "Disk I/O", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 36 + } + }, + { + "type": "timeseries", + "title": "Disk Read Rate (bytes/sec)", + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 37 + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "targets": [ + { + "expr": "rate(node_disk_read_bytes_total{instance=~\"$instance\",device!~\"^(loop|sr)\"}[5m])", + "legendFormat": "{{instance}} - {{device}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "Bps", + "custom": { + "fillOpacity": 20, + "showPoints": "never" + } + } + }, + "options": { + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true + } + } + }, + { + "type": "timeseries", + "title": "Disk Write Rate (bytes/sec)", + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 37 + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "targets": [ + { + "expr": "rate(node_disk_written_bytes_total{instance=~\"$instance\",device!~\"^(loop|sr)\"}[5m])", + "legendFormat": "{{instance}} - {{device}}" + } + ], + "fieldConfig": { + "defaults": { + "unit": "Bps", + "custom": { + "fillOpacity": 20, + "showPoints": "never" + } + } + }, + "options": { + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true + } + } + }, + { + "type": "row", + "collapsed": false, + "title": "System Load & Processes", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 45 + } + }, + { + "type": "timeseries", + "title": "System Load Average", + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 46 + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "targets": [ + { + "expr": "node_load1{instance=~\"$instance\"}", + "legendFormat": "{{instance}} - 1m" + }, + { + "expr": "node_load5{instance=~\"$instance\"}", + "legendFormat": "{{instance}} - 5m" + }, + { + "expr": "node_load15{instance=~\"$instance\"}", + "legendFormat": "{{instance}} - 15m" + } + ], + "fieldConfig": { + "defaults": { + "custom": { + "fillOpacity": 10, + "showPoints": "never" + } + } + }, + "options": { + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true + } + } + }, + { + "type": "stat", + "title": "Running Processes", + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 46 + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "targets": [ + { + "expr": "node_processes_running{instance=~\"$instance\"}", + "legendFormat": "{{instance}}" + } + ], + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "tooltip": false, + "viz": false, + "legend": false + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + } + }, + "options": { + "orientation": "auto", + "textMode": "value_and_name", + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ] + } + } + } + ], + "time": { + "from": "now-6h", + "to": "now" + } + } diff --git a/frontends/etc/gogios.cron.tpl b/frontends/etc/gogios.cron.tpl index 56af0af..21f8bfe 100644 --- a/frontends/etc/gogios.cron.tpl +++ b/frontends/etc/gogios.cron.tpl @@ -1,3 +1,3 @@ 0 7 * * * <%= $gogios_path %> -renotify >/dev/null 2>&1 -*/5 8-22 * * * -s <%= $gogios_path %> >/dev/null 2>&1 +*/5 8-22 * * * <%= $gogios_path %> >/dev/null 2>&1 0 3 * * 0 <%= $gogios_path %> -force >/dev/null 2>&1 diff --git a/frontends/etc/gogios.json.tpl b/frontends/etc/gogios.json.tpl index 0f88868..d30d255 100644 --- a/frontends/etc/gogios.json.tpl +++ b/frontends/etc/gogios.json.tpl @@ -5,6 +5,7 @@ "CheckTimeoutS": 10, "CheckConcurrency": 3, "StateDir": "/var/run/gogios", + "HTMLStatusFile": "/var/www/htdocs/buetow.org/self/gogios/index.html", "PrometheusHosts": ["r0.wg0:30090", "r1.wg0:30090", "r2.wg0:30090"], "Checks": { <% for my $host (qw(master standby)) { -%> diff --git a/snippets/go/go-projects/gogios.md b/snippets/go/go-projects/gogios.md new file mode 100644 index 0000000..62d6c40 --- /dev/null +++ b/snippets/go/go-projects/gogios.md @@ -0,0 +1,9 @@ +# Gogios + +To deploy Gogios, do + +* `mage buildOpenbsd deployOpenbsd` +* Change to ~/git/conf/frontends +* `rex gogios_install` + + -- cgit v1.2.3