@geekbeer/minion 2.23.0 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/minion-cli.sh +184 -0
- package/package.json +1 -1
- package/routes/routines.js +41 -1
package/minion-cli.sh
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#
|
|
6
6
|
# Usage:
|
|
7
7
|
# sudo minion-cli setup [options] # Set up minion agent service (root)
|
|
8
|
+
# sudo minion-cli reconfigure [options] # Re-register with new HQ credentials (root)
|
|
8
9
|
# sudo minion-cli start # Start agent service (root)
|
|
9
10
|
# sudo minion-cli stop # Stop agent service (root)
|
|
10
11
|
# sudo minion-cli restart # Restart agent service (root)
|
|
@@ -763,6 +764,177 @@ CFEOF
|
|
|
763
764
|
fi
|
|
764
765
|
}
|
|
765
766
|
|
|
767
|
+
# ============================================================
|
|
768
|
+
# reconfigure subcommand
|
|
769
|
+
# ============================================================
|
|
770
|
+
do_reconfigure() {
|
|
771
|
+
local HQ_URL=""
|
|
772
|
+
local MINION_ID=""
|
|
773
|
+
local API_TOKEN=""
|
|
774
|
+
|
|
775
|
+
# Parse arguments
|
|
776
|
+
while [[ $# -gt 0 ]]; do
|
|
777
|
+
case "$1" in
|
|
778
|
+
--hq-url)
|
|
779
|
+
HQ_URL="$2"
|
|
780
|
+
shift 2
|
|
781
|
+
;;
|
|
782
|
+
--minion-id)
|
|
783
|
+
MINION_ID="$2"
|
|
784
|
+
shift 2
|
|
785
|
+
;;
|
|
786
|
+
--api-token)
|
|
787
|
+
API_TOKEN="$2"
|
|
788
|
+
shift 2
|
|
789
|
+
;;
|
|
790
|
+
*)
|
|
791
|
+
echo "Unknown option: $1"
|
|
792
|
+
echo "Usage: sudo minion-cli reconfigure --hq-url <URL> --minion-id <UUID> --api-token <TOKEN>"
|
|
793
|
+
exit 1
|
|
794
|
+
;;
|
|
795
|
+
esac
|
|
796
|
+
done
|
|
797
|
+
|
|
798
|
+
# Validate required arguments
|
|
799
|
+
if [ -z "$HQ_URL" ] || [ -z "$MINION_ID" ] || [ -z "$API_TOKEN" ]; then
|
|
800
|
+
echo "ERROR: All three options are required: --hq-url, --minion-id, --api-token"
|
|
801
|
+
echo "Usage: sudo minion-cli reconfigure --hq-url <URL> --minion-id <UUID> --api-token <TOKEN>"
|
|
802
|
+
exit 1
|
|
803
|
+
fi
|
|
804
|
+
|
|
805
|
+
# Check that .env exists (setup must have been run before)
|
|
806
|
+
if [ ! -f /opt/minion-agent/.env ]; then
|
|
807
|
+
echo "ERROR: /opt/minion-agent/.env not found."
|
|
808
|
+
echo "It looks like minion-cli setup has not been run on this server."
|
|
809
|
+
echo "Please run 'sudo minion-cli setup' first for initial installation."
|
|
810
|
+
exit 1
|
|
811
|
+
fi
|
|
812
|
+
|
|
813
|
+
echo "========================================="
|
|
814
|
+
echo " @geekbeer/minion Reconfigure"
|
|
815
|
+
echo "========================================="
|
|
816
|
+
echo "HQ: $HQ_URL"
|
|
817
|
+
echo "Minion ID: $MINION_ID"
|
|
818
|
+
echo ""
|
|
819
|
+
|
|
820
|
+
# Step 1: Read existing .env and preserve non-credential keys
|
|
821
|
+
echo "[1/4] Updating .env credentials..."
|
|
822
|
+
local ENV_CONTENT=""
|
|
823
|
+
ENV_CONTENT+="# Minion Agent Configuration\n"
|
|
824
|
+
ENV_CONTENT+="# Reconfigured by minion-cli reconfigure\n\n"
|
|
825
|
+
ENV_CONTENT+="HQ_URL=${HQ_URL}\n"
|
|
826
|
+
ENV_CONTENT+="API_TOKEN=${API_TOKEN}\n"
|
|
827
|
+
ENV_CONTENT+="MINION_ID=${MINION_ID}\n"
|
|
828
|
+
|
|
829
|
+
# Preserve non-credential keys from existing .env
|
|
830
|
+
while IFS='=' read -r key value; do
|
|
831
|
+
[[ -z "$key" || "$key" == \#* ]] && continue
|
|
832
|
+
case "$key" in
|
|
833
|
+
HQ_URL|API_TOKEN|MINION_ID) ;; # Skip — already set above
|
|
834
|
+
*) ENV_CONTENT+="${key}=${value}\n" ;;
|
|
835
|
+
esac
|
|
836
|
+
done < /opt/minion-agent/.env
|
|
837
|
+
|
|
838
|
+
echo -e "$ENV_CONTENT" | $SUDO tee /opt/minion-agent/.env > /dev/null
|
|
839
|
+
echo " -> /opt/minion-agent/.env updated"
|
|
840
|
+
|
|
841
|
+
# Step 2: Update process manager config & restart service
|
|
842
|
+
echo "[2/4] Restarting minion-agent service..."
|
|
843
|
+
if [ -z "$PROC_MGR" ]; then
|
|
844
|
+
echo " WARNING: No supported process manager found"
|
|
845
|
+
echo " Please restart the minion-agent service manually"
|
|
846
|
+
elif [ "$PROC_MGR" = "supervisord" ]; then
|
|
847
|
+
# supervisord bakes env vars into conf — must regenerate
|
|
848
|
+
local CONF_FILE="/etc/supervisor/conf.d/minion-agent.conf"
|
|
849
|
+
if [ -f "$CONF_FILE" ]; then
|
|
850
|
+
# Read current conf to preserve command, user, and other settings
|
|
851
|
+
local CURRENT_COMMAND
|
|
852
|
+
CURRENT_COMMAND=$(grep '^command=' "$CONF_FILE" | head -1)
|
|
853
|
+
local CURRENT_DIRECTORY
|
|
854
|
+
CURRENT_DIRECTORY=$(grep '^directory=' "$CONF_FILE" | head -1)
|
|
855
|
+
local CURRENT_USER_LINE
|
|
856
|
+
CURRENT_USER_LINE=$(grep '^user=' "$CONF_FILE" || echo "")
|
|
857
|
+
|
|
858
|
+
# Rebuild environment line from updated .env
|
|
859
|
+
local ENV_LINE="environment="
|
|
860
|
+
# Detect home dir for the service user
|
|
861
|
+
local SVC_USER
|
|
862
|
+
SVC_USER=$(echo "$CURRENT_USER_LINE" | sed 's/user=//')
|
|
863
|
+
local SVC_HOME="$HOME"
|
|
864
|
+
if [ -n "$SVC_USER" ]; then
|
|
865
|
+
SVC_HOME=$(getent passwd "$SVC_USER" | cut -d: -f6 || echo "$HOME")
|
|
866
|
+
fi
|
|
867
|
+
local ENV_PAIRS=("HOME=\"${SVC_HOME}\"" "DISPLAY=\":99\"")
|
|
868
|
+
while IFS='=' read -r key value; do
|
|
869
|
+
[[ -z "$key" || "$key" == \#* ]] && continue
|
|
870
|
+
ENV_PAIRS+=("${key}=\"${value}\"")
|
|
871
|
+
done < /opt/minion-agent/.env
|
|
872
|
+
ENV_LINE+="$(IFS=,; echo "${ENV_PAIRS[*]}")"
|
|
873
|
+
|
|
874
|
+
$SUDO tee "$CONF_FILE" > /dev/null <<SUPEOF
|
|
875
|
+
[program:minion-agent]
|
|
876
|
+
${CURRENT_COMMAND}
|
|
877
|
+
${CURRENT_DIRECTORY}
|
|
878
|
+
${CURRENT_USER_LINE}
|
|
879
|
+
${ENV_LINE}
|
|
880
|
+
autorestart=true
|
|
881
|
+
priority=500
|
|
882
|
+
startsecs=3
|
|
883
|
+
stdout_logfile=/var/log/supervisor/minion-agent.log
|
|
884
|
+
stderr_logfile=/var/log/supervisor/minion-agent.log
|
|
885
|
+
SUPEOF
|
|
886
|
+
echo " -> supervisord conf updated"
|
|
887
|
+
fi
|
|
888
|
+
$SUDO supervisorctl reread > /dev/null 2>&1
|
|
889
|
+
$SUDO supervisorctl update > /dev/null 2>&1
|
|
890
|
+
echo " -> minion-agent restarted (supervisord)"
|
|
891
|
+
else
|
|
892
|
+
# systemd reads .env via EnvironmentFile — just restart
|
|
893
|
+
svc_control restart
|
|
894
|
+
echo " -> minion-agent restarted (systemd)"
|
|
895
|
+
fi
|
|
896
|
+
|
|
897
|
+
# Step 3: Health check
|
|
898
|
+
echo "[3/4] Verifying agent health..."
|
|
899
|
+
local HEALTH_OK=false
|
|
900
|
+
for i in $(seq 1 5); do
|
|
901
|
+
if curl -sf http://localhost:8080/api/health > /dev/null 2>&1; then
|
|
902
|
+
HEALTH_OK=true
|
|
903
|
+
break
|
|
904
|
+
fi
|
|
905
|
+
sleep 2
|
|
906
|
+
done
|
|
907
|
+
if [ "$HEALTH_OK" = true ]; then
|
|
908
|
+
echo " -> Agent is healthy"
|
|
909
|
+
else
|
|
910
|
+
echo " WARNING: Agent health check failed after 5 attempts"
|
|
911
|
+
echo " Check logs for details"
|
|
912
|
+
fi
|
|
913
|
+
|
|
914
|
+
# Step 4: Notify HQ (best-effort — heartbeat will also notify automatically)
|
|
915
|
+
echo "[4/4] Notifying HQ..."
|
|
916
|
+
local NOTIFY_RESPONSE
|
|
917
|
+
local HOSTNAME_VAL
|
|
918
|
+
HOSTNAME_VAL=$(hostname 2>/dev/null || echo "")
|
|
919
|
+
NOTIFY_RESPONSE=$(curl -sfL -X POST "${HQ_URL}/api/minion/setup-complete" \
|
|
920
|
+
-H "Content-Type: application/json" \
|
|
921
|
+
-H "Authorization: Bearer ${API_TOKEN}" \
|
|
922
|
+
-d "{\"internal_ip_address\":\"${HOSTNAME_VAL}\"}" 2>&1) || true
|
|
923
|
+
|
|
924
|
+
if echo "$NOTIFY_RESPONSE" | grep -q '"success":true' 2>/dev/null; then
|
|
925
|
+
echo " -> HQ notified successfully"
|
|
926
|
+
else
|
|
927
|
+
echo " -> Skipped (heartbeat will notify HQ within 30s)"
|
|
928
|
+
fi
|
|
929
|
+
|
|
930
|
+
echo ""
|
|
931
|
+
echo "========================================="
|
|
932
|
+
echo " Reconfigure Complete!"
|
|
933
|
+
echo "========================================="
|
|
934
|
+
echo ""
|
|
935
|
+
echo "The minion should appear online in HQ shortly."
|
|
936
|
+
}
|
|
937
|
+
|
|
766
938
|
# ============================================================
|
|
767
939
|
# Main command dispatch
|
|
768
940
|
# ============================================================
|
|
@@ -776,6 +948,12 @@ case "${1:-}" in
|
|
|
776
948
|
do_setup "$@"
|
|
777
949
|
;;
|
|
778
950
|
|
|
951
|
+
reconfigure)
|
|
952
|
+
require_root reconfigure
|
|
953
|
+
shift
|
|
954
|
+
do_reconfigure "$@"
|
|
955
|
+
;;
|
|
956
|
+
|
|
779
957
|
status)
|
|
780
958
|
curl -s "$AGENT_URL/api/status" | jq .
|
|
781
959
|
;;
|
|
@@ -866,6 +1044,7 @@ case "${1:-}" in
|
|
|
866
1044
|
echo ""
|
|
867
1045
|
echo "Usage:"
|
|
868
1046
|
echo " sudo minion-cli setup [options] # Set up agent service (root)"
|
|
1047
|
+
echo " sudo minion-cli reconfigure [options] # Re-register with new HQ credentials (root)"
|
|
869
1048
|
echo " sudo minion-cli start # Start agent service (root)"
|
|
870
1049
|
echo " sudo minion-cli stop # Stop agent service (root)"
|
|
871
1050
|
echo " sudo minion-cli restart # Restart agent service (root)"
|
|
@@ -882,6 +1061,11 @@ case "${1:-}" in
|
|
|
882
1061
|
echo " --api-token <TOKEN> API token (optional)"
|
|
883
1062
|
echo " --setup-tunnel Set up cloudflared tunnel (requires --hq-url, --api-token)"
|
|
884
1063
|
echo ""
|
|
1064
|
+
echo "Reconfigure options:"
|
|
1065
|
+
echo " --hq-url <URL> HQ server URL (required)"
|
|
1066
|
+
echo " --minion-id <UUID> Minion ID (required)"
|
|
1067
|
+
echo " --api-token <TOKEN> API token (required)"
|
|
1068
|
+
echo ""
|
|
885
1069
|
echo "Status values: online, offline, busy"
|
|
886
1070
|
echo ""
|
|
887
1071
|
echo "Environment:"
|
package/package.json
CHANGED
package/routes/routines.js
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Endpoints:
|
|
5
5
|
* - GET /api/routines - List all routines with status
|
|
6
|
-
* - POST /api/routines - Receive routines
|
|
6
|
+
* - POST /api/routines - Receive routines (upsert/additive)
|
|
7
7
|
* - POST /api/routines/sync - Pull routines from HQ and sync locally
|
|
8
8
|
* - PUT /api/routines/:id/schedule - Update a routine schedule (cron_expression, is_active)
|
|
9
9
|
* - DELETE /api/routines/:id - Remove a routine
|
|
10
|
+
* - POST /api/routines/bulk-toggle - Set is_active for all routines at once
|
|
10
11
|
* - POST /api/routines/trigger - Manual trigger for a routine
|
|
11
12
|
*/
|
|
12
13
|
|
|
@@ -218,6 +219,45 @@ async function routineRoutes(fastify) {
|
|
|
218
219
|
}
|
|
219
220
|
})
|
|
220
221
|
|
|
222
|
+
// Bulk toggle: set is_active for all routines at once
|
|
223
|
+
fastify.post('/api/routines/bulk-toggle', async (request, reply) => {
|
|
224
|
+
if (!verifyToken(request)) {
|
|
225
|
+
reply.code(401)
|
|
226
|
+
return { success: false, error: 'Unauthorized' }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const { is_active } = request.body || {}
|
|
230
|
+
|
|
231
|
+
if (typeof is_active !== 'boolean') {
|
|
232
|
+
reply.code(400)
|
|
233
|
+
return { success: false, error: 'is_active (boolean) is required' }
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
console.log(`[Routines] Bulk toggle: setting all routines is_active=${is_active}`)
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
const routines = await routineStore.load()
|
|
240
|
+
|
|
241
|
+
for (const routine of routines) {
|
|
242
|
+
routine.is_active = is_active
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
await routineStore.save(routines)
|
|
246
|
+
routineRunner.loadRoutines(routines)
|
|
247
|
+
|
|
248
|
+
const count = routines.length
|
|
249
|
+
return {
|
|
250
|
+
success: true,
|
|
251
|
+
message: `${count} routines set to is_active=${is_active}`,
|
|
252
|
+
count,
|
|
253
|
+
}
|
|
254
|
+
} catch (error) {
|
|
255
|
+
console.error(`[Routines] Failed to bulk toggle: ${error.message}`)
|
|
256
|
+
reply.code(500)
|
|
257
|
+
return { success: false, error: error.message }
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
|
|
221
261
|
// Manual trigger: run a routine immediately
|
|
222
262
|
fastify.post('/api/routines/trigger', async (request, reply) => {
|
|
223
263
|
if (!verifyToken(request)) {
|