Add systemd timer fallback when crontab unavailable
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
- Try crontab first, fall back to systemd timer - If neither available, still deploy script but warn user - Update frontend to show scheduling method (cron/systemd/none) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -298,22 +298,61 @@ class MonitorService:
|
|||||||
"error": f"Failed to make script executable: {error_detail}",
|
"error": f"Failed to make script executable: {error_detail}",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add cronjob entry (remove existing entry first to avoid duplicates)
|
# Try to add cronjob entry (crontab may not be available on all systems)
|
||||||
cron_cmd = f"(crontab -l 2>/dev/null | grep -v '{script_filename}'; echo '{cronjob_entry}') | crontab -"
|
cron_cmd = f"(crontab -l 2>/dev/null | grep -v '{script_filename}'; echo '{cronjob_entry}') | crontab -"
|
||||||
cron_result = ssh.execute(hostname, cron_cmd, username, port)
|
cron_result = ssh.execute(hostname, cron_cmd, username, port)
|
||||||
if not cron_result.success:
|
|
||||||
return {
|
scheduling_method = None
|
||||||
"status": "failed",
|
scheduling_info = None
|
||||||
"error": f"Failed to add cronjob: {cron_result.stderr}",
|
|
||||||
}
|
if cron_result.success:
|
||||||
|
scheduling_method = "crontab"
|
||||||
|
scheduling_info = cronjob_entry
|
||||||
|
else:
|
||||||
|
# Try systemd timer as fallback
|
||||||
|
timer_name = f"kuma-push-{push_metric}-{monitor_id}"
|
||||||
|
timer_content = f"""[Unit]
|
||||||
|
Description=Kuma Push Monitor - {push_metric}
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnBootSec=1min
|
||||||
|
OnUnitActiveSec={interval_minutes}min
|
||||||
|
AccuracySec=1s
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
"""
|
||||||
|
service_content = f"""[Unit]
|
||||||
|
Description=Kuma Push Monitor - {push_metric}
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart={script_path}
|
||||||
|
"""
|
||||||
|
# Write timer and service files
|
||||||
|
timer_path = f"/etc/systemd/system/{timer_name}.timer"
|
||||||
|
service_path = f"/etc/systemd/system/{timer_name}.service"
|
||||||
|
|
||||||
|
timer_cmd = f"sudo tee {timer_path} > /dev/null << 'KUMA_TIMER_EOF'\n{timer_content}KUMA_TIMER_EOF"
|
||||||
|
service_cmd = f"sudo tee {service_path} > /dev/null << 'KUMA_SERVICE_EOF'\n{service_content}KUMA_SERVICE_EOF"
|
||||||
|
|
||||||
|
timer_result = ssh.execute(hostname, timer_cmd, username, port)
|
||||||
|
if timer_result.success:
|
||||||
|
service_result = ssh.execute(hostname, service_cmd, username, port)
|
||||||
|
if service_result.success:
|
||||||
|
# Enable and start the timer
|
||||||
|
enable_cmd = f"sudo systemctl daemon-reload && sudo systemctl enable --now {timer_name}.timer"
|
||||||
|
enable_result = ssh.execute(hostname, enable_cmd, username, port)
|
||||||
|
if enable_result.success:
|
||||||
|
scheduling_method = "systemd"
|
||||||
|
scheduling_info = f"{timer_name}.timer"
|
||||||
|
|
||||||
# Run the script once immediately to verify it works
|
# Run the script once immediately to verify it works
|
||||||
run_result = ssh.execute(hostname, script_path, username, port, timeout=30)
|
run_result = ssh.execute(hostname, script_path, username, port, timeout=30)
|
||||||
|
|
||||||
return {
|
result = {
|
||||||
"status": "deployed",
|
"status": "deployed",
|
||||||
"script_path": script_path,
|
"script_path": script_path,
|
||||||
"cronjob": cronjob_entry,
|
|
||||||
"initial_run": {
|
"initial_run": {
|
||||||
"success": run_result.success,
|
"success": run_result.success,
|
||||||
"stdout": run_result.stdout,
|
"stdout": run_result.stdout,
|
||||||
@@ -321,6 +360,19 @@ class MonitorService:
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if scheduling_method:
|
||||||
|
result["scheduling"] = {
|
||||||
|
"method": scheduling_method,
|
||||||
|
"info": scheduling_info,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
result["scheduling"] = {
|
||||||
|
"method": "none",
|
||||||
|
"warning": "Neither crontab nor systemd available. Script deployed but not scheduled.",
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(f"Failed to deploy push script to {hostname}")
|
logger.exception(f"Failed to deploy push script to {hostname}")
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -409,9 +409,17 @@ export default function DiscoveryResults({ scanId, scan, analysis, devMode, onCo
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{result.deployment.cronjob && (
|
{result.deployment.scheduling && (
|
||||||
<div className="mt-1 text-xs text-slate-500 font-mono">
|
<div className="mt-1 text-xs text-slate-500">
|
||||||
Cronjob: {result.deployment.cronjob}
|
{result.deployment.scheduling.method === 'crontab' && (
|
||||||
|
<span className="font-mono">Cron: {result.deployment.scheduling.info}</span>
|
||||||
|
)}
|
||||||
|
{result.deployment.scheduling.method === 'systemd' && (
|
||||||
|
<span>Systemd timer: {result.deployment.scheduling.info}</span>
|
||||||
|
)}
|
||||||
|
{result.deployment.scheduling.method === 'none' && (
|
||||||
|
<span className="text-amber-400">{result.deployment.scheduling.warning}</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user