Add push monitor script deployment via SSH
All checks were successful
Build and Push Container / build (push) Successful in 33s
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:
108
backend/app.py
108
backend/app.py
@@ -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():
|
||||
|
||||
Reference in New Issue
Block a user