diff --git a/orchestrator/setup-crontab.sh b/orchestrator/setup-crontab.sh index c0bca59..fa3447c 100755 --- a/orchestrator/setup-crontab.sh +++ b/orchestrator/setup-crontab.sh @@ -12,7 +12,16 @@ SCRIPTS=( ) OS_TYPE=$(DetectOS) -LAUNCHD_DIR="$HOME/Library/LaunchAgents" + +# Determine LaunchAgent vs LaunchDaemon directory +# If running as root on macOS, use system-wide LaunchDaemons for headless operation +if [[ "$OS_TYPE" == "macos" && $EUID -eq 0 ]]; then + LAUNCHD_DIR="/Library/LaunchDaemons" + LAUNCHD_TYPE="daemon" +else + LAUNCHD_DIR="$HOME/Library/LaunchAgents" + LAUNCHD_TYPE="agent" +fi CheckScriptExists() { local script="$1" @@ -77,7 +86,7 @@ ManageLaunchAgent() { local plist_name="com.servermetrics.${script_name}.plist" local plist_path="${LAUNCHD_DIR}/${plist_name}" - # Ensure LaunchAgents directory exists + # Ensure LaunchAgents/LaunchDaemons directory exists if [[ ! -d "$LAUNCHD_DIR" ]]; then mkdir -p "$LAUNCHD_DIR" fi @@ -107,18 +116,39 @@ ManageLaunchAgent() { EOF if [[ $? -eq 0 ]]; then - LogInformation "Created LaunchAgent plist: $plist_path" + # Set proper ownership for LaunchDaemons + if [[ "$LAUNCHD_TYPE" == "daemon" ]]; then + chown root:wheel "$plist_path" + chmod 644 "$plist_path" + fi - # Unload if already loaded (ignore errors) - launchctl unload "$plist_path" 2>/dev/null || true + LogInformation "Created Launch${LAUNCHD_TYPE^} plist: $plist_path" - # Load the plist - if launchctl load "$plist_path" 2>/dev/null; then - LogInformation "Loaded LaunchAgent for $script" - return 0 + # Use appropriate launchctl commands based on type + if [[ "$LAUNCHD_TYPE" == "daemon" ]]; then + # Unload if already loaded (ignore errors) + launchctl bootout system "$plist_path" 2>/dev/null || true + + # Load the plist + if launchctl bootstrap system "$plist_path" 2>/dev/null; then + LogInformation "Loaded LaunchDaemon for $script" + return 0 + else + LogError "Failed to load LaunchDaemon for $script" + return 1 + fi else - LogError "Failed to load LaunchAgent for $script" - return 1 + # Unload if already loaded (ignore errors) + launchctl unload "$plist_path" 2>/dev/null || true + + # Load the plist + if launchctl load "$plist_path" 2>/dev/null; then + LogInformation "Loaded LaunchAgent for $script" + return 0 + else + LogError "Failed to load LaunchAgent for $script" + return 1 + fi fi else LogError "Failed to create plist for $script" @@ -170,7 +200,11 @@ ShowStatus() { LogInformation "Scheduled task status:" LogInformation "OS: $OS_TYPE" if [[ "$OS_TYPE" == "macos" ]]; then - LogInformation "Method: LaunchAgents" + if [[ "$LAUNCHD_TYPE" == "daemon" ]]; then + LogInformation "Method: LaunchDaemons (system-wide, runs at boot)" + else + LogInformation "Method: LaunchAgents (user-level, requires login)" + fi else LogInformation "Method: Crontab" fi @@ -213,9 +247,14 @@ ShowStatus() { if [[ $found_entries -gt 0 ]]; then LogInformation "Commands:" if [[ "$OS_TYPE" == "macos" ]]; then - LogInformation " List agents: launchctl list | grep servermetrics" - LogInformation " View logs: tail -f /tmp/*.out" - LogInformation " Unload agent: launchctl unload ~/Library/LaunchAgents/com.servermetrics.*.plist" + LogInformation " List ${LAUNCHD_TYPE}s: launchctl list | grep servermetrics" + if [[ "$LAUNCHD_TYPE" == "daemon" ]]; then + LogInformation " View logs: tail -f /tmp/*.out" + LogInformation " Bootout ${LAUNCHD_TYPE}: sudo launchctl bootout system $LAUNCHD_DIR/com.servermetrics.*.plist" + else + LogInformation " View logs: tail -f /tmp/*.out" + LogInformation " Unload agent: launchctl unload ~/Library/LaunchAgents/com.servermetrics.*.plist" + fi else LogInformation " View crontab: crontab -l" LogInformation " Edit crontab: crontab -e" @@ -230,30 +269,34 @@ RemoveCrontabEntries() { local removed_count=0 if [[ "$OS_TYPE" == "macos" ]]; then - # Remove LaunchAgents + # Remove LaunchAgents/LaunchDaemons for script in "${SCRIPTS[@]}"; do local script_name=$(basename "$script" .sh) local plist_name="com.servermetrics.${script_name}.plist" local plist_path="${LAUNCHD_DIR}/${plist_name}" if [[ -f "$plist_path" ]]; then - LogInformation "Removing LaunchAgent for $script_name..." + LogInformation "Removing Launch${LAUNCHD_TYPE^} for $script_name..." - # Unload the agent - launchctl unload "$plist_path" 2>/dev/null || true + # Unload the agent/daemon + if [[ "$LAUNCHD_TYPE" == "daemon" ]]; then + launchctl bootout system "$plist_path" 2>/dev/null || true + else + launchctl unload "$plist_path" 2>/dev/null || true + fi # Remove the plist file rm -f "$plist_path" ((removed_count++)) else - LogDebug "No LaunchAgent found for $script_name" + LogDebug "No Launch${LAUNCHD_TYPE^} found for $script_name" fi done if [[ $removed_count -gt 0 ]]; then - LogInformation "Removed $removed_count LaunchAgents" + LogInformation "Removed $removed_count Launch${LAUNCHD_TYPE^}s" else - LogWarning "No LaunchAgents were found to remove" + LogWarning "No Launch${LAUNCHD_TYPE^}s were found to remove" fi else # Remove crontab entries