juntekim.com/mist_infra/arc/forgejo/metrics-exporter.yaml
2026-03-12 21:05:06 +00:00

146 lines
3.8 KiB
YAML

apiVersion: v1
kind: ConfigMap
metadata:
name: forgejo-metrics-script
namespace: forgejo-runners
data:
server.py: |
#!/usr/bin/env python3
"""
Polls the Forgejo API for waiting action tasks and exposes the count as JSON.
KEDA metrics-api scaler reads: { "value": <count> }
"""
import http.server
import json
import os
import threading
import time
import urllib.request
FORGEJO_URL = os.environ["FORGEJO_URL"].rstrip("/")
TOKEN = "69eccfc51f720c21c615cfd5caa422fb02f0ab43"
REFRESH = int(os.environ.get("REFRESH_INTERVAL", "20"))
_state = {"value": 0}
_lock = threading.Lock()
def fetch(path):
req = urllib.request.Request(
f"{FORGEJO_URL}/api/v1{path}",
headers={"Authorization": f"token {TOKEN}", "Accept": "application/json"},
)
with urllib.request.urlopen(req, timeout=10) as r:
return json.loads(r.read())
def count_pending_jobs():
total = 0
page = 1
while True:
repos = fetch(f"/repos/search?limit=50&page={page}")
items = repos.get("data", [])
for repo in items:
owner = repo["owner"]["login"]
name = repo["name"]
try:
result = fetch(
f"/repos/{owner}/{name}/actions/tasks?status=waiting&limit=1"
)
total += result.get("total_count", 0)
except Exception:
pass
if len(items) < 50:
break
page += 1
return total
def refresh_loop():
while True:
try:
count = count_pending_jobs()
with _lock:
_state["value"] = count
print(f"pending jobs: {count}", flush=True)
except Exception as e:
print(f"refresh error: {e}", flush=True)
time.sleep(REFRESH)
threading.Thread(target=refresh_loop, daemon=True).start()
class Handler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
with _lock:
val = _state["value"]
body = json.dumps({"value": val}).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(body)
def log_message(self, *_):
pass
http.server.HTTPServer(("", 8080), Handler).serve_forever()
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: forgejo-metrics-exporter
namespace: forgejo-runners
spec:
replicas: 1
selector:
matchLabels:
app: forgejo-metrics-exporter
template:
metadata:
labels:
app: forgejo-metrics-exporter
spec:
containers:
- name: exporter
image: python:3.12-alpine
command: ["python", "/scripts/server.py"]
env:
- name: FORGEJO_URL
value: https://git.juntekim.com
- name: FORGEJO_TOKEN
valueFrom:
secretKeyRef:
name: forgejo-api-secret
key: token
- name: REFRESH_INTERVAL
value: "20"
ports:
- containerPort: 8080
resources:
requests:
cpu: 10m
memory: 32Mi
limits:
cpu: 100m
memory: 64Mi
volumeMounts:
- name: scripts
mountPath: /scripts
volumes:
- name: scripts
configMap:
name: forgejo-metrics-script
---
apiVersion: v1
kind: Service
metadata:
name: forgejo-metrics-exporter
namespace: forgejo-runners
spec:
selector:
app: forgejo-metrics-exporter
ports:
- port: 8080
targetPort: 8080