Add push monitor script deployment via SSH
All checks were successful
Build and Push Container / build (push) Successful in 33s

- Add push_scripts.py with bash templates for heartbeat, disk, memory, cpu, and updates monitoring
- Modify kuma_client.py to return push token from created monitors
- Add deploy_push_script() to monitors.py for SSH-based script deployment
- Add heartbeat push_metric type to Claude agent suggestions
- Add /api/monitors/<id>/deploy-script and /api/monitors/deploy-all-scripts endpoints
- Update frontend to show push monitors with deployment status and retry buttons

Scripts are deployed to /usr/local/bin/kuma-push-{metric}-{id}.sh with cron entries.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Debian
2026-01-05 08:36:48 +00:00
parent 908d147235
commit ae814c1aea
7 changed files with 577 additions and 21 deletions

View File

@@ -145,6 +145,7 @@ def analyze_with_claude(result: DiscoveryResult):
"port": m.port,
"interval": m.interval,
"reason": m.reason,
"push_metric": m.push_metric,
}
for m in response.monitors
],
@@ -190,6 +191,7 @@ def get_scan(scan_id):
"port": m.port,
"interval": m.interval,
"reason": m.reason,
"push_metric": m.push_metric,
}
for m in suggestions.monitors
],
@@ -308,6 +310,7 @@ def approve_request(approval_id):
"port": m.port,
"interval": m.interval,
"reason": m.reason,
"push_metric": m.push_metric,
}
for m in response.monitors
],
@@ -406,6 +409,111 @@ def create_suggested_monitors():
return jsonify({"created": created})
@app.route("/api/monitors/<int:monitor_id>/deploy-script", methods=["POST"])
def deploy_push_script(monitor_id):
"""Deploy a push monitoring script to a remote host for an existing push monitor."""
data = request.json
hostname = data.get("hostname")
push_metric = data.get("push_metric")
username = data.get("username", "root")
port = data.get("port", 22)
interval_minutes = data.get("interval_minutes", 5)
if not hostname:
return jsonify({"error": "hostname is required"}), 400
if not push_metric:
return jsonify({"error": "push_metric is required"}), 400
valid_metrics = ["heartbeat", "disk", "memory", "cpu", "updates"]
if push_metric not in valid_metrics:
return jsonify({"error": f"push_metric must be one of: {', '.join(valid_metrics)}"}), 400
try:
kuma = get_kuma_client()
push_token = kuma.get_monitor_push_token(monitor_id)
if not push_token:
return jsonify({"error": "Could not get push token. Is this a push monitor?"}), 400
monitor_service = get_monitor_service()
result = monitor_service.deploy_push_script(
hostname=hostname,
push_metric=push_metric,
push_token=push_token,
monitor_id=monitor_id,
interval_minutes=interval_minutes,
username=username,
port=port,
)
return jsonify(result)
except Exception as e:
return jsonify({"error": str(e)}), 500
@app.route("/api/monitors/deploy-all-scripts", methods=["POST"])
def deploy_all_push_scripts():
"""Deploy scripts for multiple push monitors at once."""
data = request.json
monitors = data.get("monitors", [])
if not monitors:
return jsonify({"error": "monitors array is required"}), 400
results = []
kuma = get_kuma_client()
monitor_service = get_monitor_service()
for monitor_config in monitors:
monitor_id = monitor_config.get("monitor_id")
hostname = monitor_config.get("hostname")
push_metric = monitor_config.get("push_metric")
username = monitor_config.get("username", "root")
port = monitor_config.get("port", 22)
interval_minutes = monitor_config.get("interval_minutes", 5)
if not monitor_id or not hostname or not push_metric:
results.append({
"monitor_id": monitor_id,
"status": "failed",
"error": "monitor_id, hostname, and push_metric are required",
})
continue
try:
push_token = kuma.get_monitor_push_token(monitor_id)
if not push_token:
results.append({
"monitor_id": monitor_id,
"status": "failed",
"error": "Could not get push token",
})
continue
result = monitor_service.deploy_push_script(
hostname=hostname,
push_metric=push_metric,
push_token=push_token,
monitor_id=monitor_id,
interval_minutes=interval_minutes,
username=username,
port=port,
)
result["monitor_id"] = monitor_id
results.append(result)
except Exception as e:
results.append({
"monitor_id": monitor_id,
"status": "failed",
"error": str(e),
})
return jsonify({"results": results})
# Uptime Kuma authentication endpoints
@app.route("/api/kuma/auth", methods=["GET"])
def kuma_auth_status():