From 5f31a0882c9b0b5bfc082d0cbab1f04733877ccb Mon Sep 17 00:00:00 2001 From: "Arnaud (Arhuman) ASSAD" Date: Sun, 10 Aug 2025 12:19:49 +0200 Subject: [PATCH] remove console download links, improve nexus url in install_minion.sh --- internal/web/handlers.go | 57 ++++-- internal/web/handlers_test.go | 10 +- internal/web/server.go | 6 +- internal/web/templates/install_minion.sh | 239 +++++++++++++++++++++++ 4 files changed, 291 insertions(+), 21 deletions(-) create mode 100644 internal/web/templates/install_minion.sh diff --git a/internal/web/handlers.go b/internal/web/handlers.go index eb7e2ed..d5d280f 100644 --- a/internal/web/handlers.go +++ b/internal/web/handlers.go @@ -6,6 +6,7 @@ import ( "fmt" "html/template" "net/http" + "os" "strings" "time" @@ -106,21 +107,47 @@ func (ws *WebServer) serveDownloadIndex(w http.ResponseWriter, _ *http.Request) macOS x64 macOS ARM64 -
-

Console Binaries

- Linux x64 - Linux ARM64 - Windows x64 - Windows ARM64 - macOS x64 - macOS ARM64 -

← Back to Dashboard

` w.Write([]byte(html)) } +// handleInstallScript serves the dynamically generated install script +func (ws *WebServer) handleInstallScript(w http.ResponseWriter, r *http.Request) { + ws.setSecurityHeaders(w) + + if r.Method != http.MethodGet { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + // Build the base URL using NEXUS_SERVER environment variable + nexusServer := os.Getenv("NEXUS_SERVER") + if nexusServer == "" { + nexusServer = "localhost" + } + baseURL := fmt.Sprintf("http://%s:%d", nexusServer, ws.config.WebPort) + + // Template data + data := struct { + BaseURL string + }{ + BaseURL: baseURL, + } + + // Set appropriate headers for shell script + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("Content-Disposition", "inline; filename=install_minion.sh") + + // Execute template + if err := ws.templates.ExecuteTemplate(w, "install_minion.sh", data); err != nil { + ws.logger.Error("Failed to execute install script template", zap.Error(err)) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } +} + // handleAPIStatus serves the /api/status endpoint func (ws *WebServer) handleAPIStatus(w http.ResponseWriter, r *http.Request) { ws.setJSONHeaders(w) @@ -373,12 +400,12 @@ func (ws *WebServer) serveBinaryFile(w http.ResponseWriter, r *http.Request, pat return } - component := parts[0] // minion or console + component := parts[0] // minion platform := parts[1] // linux-amd64, windows-amd64.exe, etc. // Validate component - if component != "minion" && component != "console" { - http.Error(w, "Invalid component. Must be 'minion' or 'console'", http.StatusBadRequest) + if component != "minion" { + http.Error(w, "Invalid component. Must be 'minion'", http.StatusBadRequest) return } @@ -406,6 +433,12 @@ func (ws *WebServer) serveBinaryFile(w http.ResponseWriter, r *http.Request, pat zap.String("path", binaryPath), zap.String("remote_addr", r.RemoteAddr)) + // Check if file exists before serving + if _, err := os.Stat(binaryPath); os.IsNotExist(err) { + http.Error(w, fmt.Sprintf("Binary for %s/%s not available", component, platform), http.StatusNotFound) + return + } + // Set appropriate headers for binary download filename := component if strings.HasSuffix(platform, ".exe") { diff --git a/internal/web/handlers_test.go b/internal/web/handlers_test.go index dace0e4..d47760d 100644 --- a/internal/web/handlers_test.go +++ b/internal/web/handlers_test.go @@ -256,8 +256,8 @@ func TestHandleDownloadBinary(t *testing.T) { expectedStatus int expectedHeader string }{ - {"/download/minion/linux-amd64", http.StatusNotFound, "application/octet-stream"}, - {"/download/console/windows-amd64.exe", http.StatusNotFound, "application/octet-stream"}, + {"/download/minion/linux-amd64", http.StatusNotFound, ""}, + {"/download/console/windows-amd64.exe", http.StatusBadRequest, ""}, {"/download/invalid/linux-amd64", http.StatusBadRequest, ""}, {"/download/minion/invalid-platform", http.StatusBadRequest, ""}, {"/download/minion", http.StatusBadRequest, ""}, @@ -299,10 +299,10 @@ func TestServeBinaryFileValidation(t *testing.T) { expectedBody: "Binary for minion/linux-amd64 not available", }, { - name: "Valid console binary", + name: "Invalid console binary", path: "console/windows-amd64.exe", - expectedStatus: http.StatusNotFound, - expectedBody: "Binary for console/windows-amd64.exe not available", + expectedStatus: http.StatusBadRequest, + expectedBody: "Invalid component. Must be 'minion'", }, { name: "Invalid component", diff --git a/internal/web/server.go b/internal/web/server.go index bf12cfc..fdff727 100644 --- a/internal/web/server.go +++ b/internal/web/server.go @@ -37,10 +37,8 @@ func StartWebServer(cfg *config.NexusConfig, nexusServer *nexus.Server, logger * // Binary downloads mux.HandleFunc("/download/", webServer.loggingMiddleware(webServer.handleDownload)) - // Installation script (redirect to static file) - mux.HandleFunc("/install_minion.sh", webServer.loggingMiddleware(func(w http.ResponseWriter, r *http.Request) { - http.Redirect(w, r, "/static/install_minion.sh", http.StatusMovedPermanently) - })) + // Installation script (dynamically generated) + mux.HandleFunc("/install_minion.sh", webServer.loggingMiddleware(webServer.handleInstallScript)) // API endpoints mux.HandleFunc("/api/status", webServer.loggingMiddleware(webServer.handleAPIStatus)) diff --git a/internal/web/templates/install_minion.sh b/internal/web/templates/install_minion.sh new file mode 100644 index 0000000..d30e865 --- /dev/null +++ b/internal/web/templates/install_minion.sh @@ -0,0 +1,239 @@ +#!/bin/bash + +# Script d'installation de Minion +# Usage: curl {{.BaseURL}}/install_minion.sh | sh + +set -e + +# Couleurs pour l'affichage +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Configuration +BASE_URL="{{.BaseURL}}" +BINARY_NAME="minion" + +# Fonction pour afficher les messages +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Fonction pour détecter l'OS +detect_os() { + case "$(uname -s)" in + Linux*) OS="linux" ;; + Darwin*) OS="darwin" ;; + CYGWIN*|MINGW*|MSYS*) OS="windows" ;; + *) OS="unknown" ;; + esac + + if [ "$OS" = "unknown" ]; then + log_error "OS non supporté: $(uname -s)" + exit 1 + fi + + log_info "OS détecté: $OS" +} + +# Fonction pour détecter l'architecture +detect_arch() { + ARCH=$(uname -m) + + case "$ARCH" in + x86_64|amd64) ARCH="amd64" ;; + aarch64|arm64) ARCH="arm64" ;; + armv7l) ARCH="arm" ;; + i386|i686) ARCH="386" ;; + *) + log_error "Architecture non supportée: $ARCH" + exit 1 + ;; + esac + + log_info "Architecture détectée: $ARCH" +} + +# Fonction pour construire le nom du binaire +build_binary_name() { + local suffix="" + + # Déterminer le suffixe selon la plateforme + case "$OS" in + linux) + if [ "$ARCH" = "amd64" ]; then + suffix="-linux" + fi + ;; + windows) + suffix=".exe" + if [ "$ARCH" = "amd64" ]; then + suffix="-windows.exe" + fi + ;; + darwin) + if [ "$ARCH" = "amd64" ]; then + suffix="-darwin" + fi + ;; + esac + + BINARY_FILE="${BINARY_NAME}${suffix}" + DOWNLOAD_URL="${BASE_URL}/download/minion/${OS}-${ARCH}${suffix}" + + log_info "Binaire cible: $BINARY_FILE" + log_info "URL de téléchargement: $DOWNLOAD_URL" +} + +# Fonction pour télécharger le binaire +download_binary() { + local temp_file="/tmp/${BINARY_FILE}" + + log_info "Téléchargement du binaire..." + + # Utiliser curl ou wget selon ce qui est disponible + if command -v curl >/dev/null 2>&1; then + if ! curl -L -o "$temp_file" "$DOWNLOAD_URL"; then + log_error "Échec du téléchargement avec curl" + exit 1 + fi + elif command -v wget >/dev/null 2>&1; then + if ! wget -O "$temp_file" "$DOWNLOAD_URL"; then + log_error "Échec du téléchargement avec wget" + exit 1 + fi + else + log_error "curl ou wget requis pour le téléchargement" + exit 1 + fi + + # Vérifier que le fichier a été téléchargé + if [ ! -f "$temp_file" ]; then + log_error "Le fichier n'a pas été téléchargé" + exit 1 + fi + + # Vérifier la taille du fichier + if [ ! -s "$temp_file" ]; then + log_error "Le fichier téléchargé est vide" + rm -f "$temp_file" + exit 1 + fi + + log_info "Téléchargement terminé avec succès" + + # Déplacer le binaire vers le répertoire de destination + local install_dir="/usr/local/bin" + local final_path="${install_dir}/${BINARY_NAME}" + + # Créer le répertoire s'il n'existe pas + if [ ! -d "$install_dir" ]; then + log_warn "Création du répertoire $install_dir" + sudo mkdir -p "$install_dir" + fi + + # Copier et rendre exécutable + log_info "Installation du binaire vers $final_path" + sudo cp "$temp_file" "$final_path" + sudo chmod +x "$final_path" + + # Nettoyer le fichier temporaire + rm -f "$temp_file" + + log_info "Installation terminée avec succès" +} + +# Fonction pour vérifier l'installation +verify_installation() { + if command -v "$BINARY_NAME" >/dev/null 2>&1; then + log_info "Vérification de l'installation..." + local version_output + if version_output=$("$BINARY_NAME" --version 2>/dev/null); then + log_info "Version installée: $version_output" + else + log_warn "Impossible d'obtenir la version, mais le binaire est installé" + fi + return 0 + else + log_error "Le binaire n'est pas accessible dans le PATH" + return 1 + fi +} + +# Fonction pour exécuter le binaire +run_minion() { + log_info "Démarrage de Minion..." + + # Vérifier si des paramètres ont été passés via des variables d'environnement + local minion_args="" + + if [ -n "$NEXUS_SERVER" ]; then + minion_args="$minion_args --server $NEXUS_SERVER" + fi + + if [ -n "$MINION_NAME" ]; then + minion_args="$minion_args --name $MINION_NAME" + fi + + if [ -n "$MINION_TAGS" ]; then + minion_args="$minion_args --tags $MINION_TAGS" + fi + + if [ -z "$minion_args" ]; then + log_info "Aucune configuration fournie. Utilisation des paramètres par défaut." + log_info "Variables d'environnement disponibles:" + log_info " NEXUS_SERVER - Adresse du serveur Nexus" + log_info " MINION_NAME - Nom du minion" + log_info " MINION_TAGS - Tags du minion" + log_info "" + log_info "Exemple:" + log_info " NEXUS_SERVER=nexus.example.com:8080 MINION_NAME=web-server-01 $0" + fi + + # Exécuter le minion + log_info "Commande exécutée: $BINARY_NAME $minion_args" + exec "$BINARY_NAME" $minion_args +} + +# Fonction principale +main() { + log_info "=== Installation de Minion ===" + + # Vérifier les prérequis + if [ "$EUID" -eq 0 ]; then + log_warn "Attention: exécution en tant que root" + fi + + # Détecter l'environnement + detect_os + detect_arch + + # Construire les informations de téléchargement + build_binary_name + + # Télécharger et installer + download_binary + + # Vérifier l'installation + if verify_installation; then + log_info "=== Installation réussie ===" + + # Exécuter le minion + run_minion + else + log_error "=== Échec de l'installation ===" + exit 1 + fi +} + +# Exécuter le script principal +main "$@" \ No newline at end of file