fix(dashboard): servir le ZIP Lea complet autoportant à l'enrôlement Fleet
L'endpoint /api/fleet/download/<machine_id> servait deploy/Lea_v1.0.0.zip (sources seules, suppose Python système) → installation impossible chez un utilisateur non-IT sans Python. Désormais il sert en priorité le ZIP complet deploy/build/Lea_full_v1.0.1.zip (python-embed inclus), avec fallback sur l'ancien ZIP léger s'il est seul. Résolution du template à la volée (le ZIP complet peut être buildé après le démarrage du dashboard) + message d'erreur explicite. L'injection de Lea/config.txt est inchangée. Le title du bouton de téléchargement ne ment plus : 'installation autonome, sans Python — dézipper puis double-cliquer Lea.bat'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2219,8 +2219,33 @@ def proxy_fleet(endpoint):
|
||||
# Fleet — Téléchargement du ZIP installeur pré-configuré
|
||||
# =============================================================================
|
||||
|
||||
# Chemin du ZIP template Léa
|
||||
_LEA_ZIP_TEMPLATE = BASE_PATH / "deploy" / "Lea_v1.0.0.zip"
|
||||
# Chemin du ZIP template Léa.
|
||||
# ZIP COMPLET autoportant (runtime Python embedded inclus + source à jour) :
|
||||
# l'utilisateur dézippe puis double-clique Lea.bat, sans Python système ni UAC.
|
||||
# Construit par deploy/build_package_full.sh. Le placeholder Lea/config.txt
|
||||
# (CONFIGURE_ME) est remplacé à la volée par download_agent_package().
|
||||
# Fallback historique vers l'ancien ZIP léger (sources seules, suppose Python
|
||||
# système) uniquement s'il existe et que le complet est absent — pour ne pas
|
||||
# casser un environnement où le complet n'a pas encore été buildé.
|
||||
_LEA_ZIP_TEMPLATE_FULL = BASE_PATH / "deploy" / "build" / "Lea_full_v1.0.1.zip"
|
||||
_LEA_ZIP_TEMPLATE_LEGACY = BASE_PATH / "deploy" / "Lea_v1.0.0.zip"
|
||||
|
||||
|
||||
def _resolve_lea_zip_template():
|
||||
"""Résout le ZIP à servir, à la volée (le complet peut être buildé
|
||||
après le démarrage du dashboard). Préfère le ZIP complet autoportant ;
|
||||
retombe sur l'ancien ZIP léger uniquement s'il existe.
|
||||
Retourne None si aucun template n'est présent.
|
||||
"""
|
||||
if _LEA_ZIP_TEMPLATE_FULL.exists():
|
||||
return _LEA_ZIP_TEMPLATE_FULL
|
||||
if _LEA_ZIP_TEMPLATE_LEGACY.exists():
|
||||
return _LEA_ZIP_TEMPLATE_LEGACY
|
||||
return None
|
||||
|
||||
|
||||
# Compat : référence statique conservée pour le code/log historique.
|
||||
_LEA_ZIP_TEMPLATE = _resolve_lea_zip_template() or _LEA_ZIP_TEMPLATE_FULL
|
||||
|
||||
# URL publique du serveur (env ou fallback)
|
||||
_RPA_PUBLIC_URL = os.getenv(
|
||||
@@ -2356,17 +2381,23 @@ def download_agent_package(machine_id):
|
||||
"""Génère et sert un ZIP Léa pré-configuré pour ce machine_id.
|
||||
|
||||
- Vérifie que le machine_id est enregistré et actif dans la fleet.
|
||||
- Lit le ZIP template (deploy/Lea_v1.0.0.zip).
|
||||
- Remplace config.txt par une version personnalisée.
|
||||
- Lit le ZIP template complet autoportant (deploy/build/Lea_full_v*.zip),
|
||||
avec fallback sur l'ancien ZIP léger (deploy/Lea_v1.0.0.zip) s'il est seul.
|
||||
- Remplace Lea/config.txt par une version personnalisée.
|
||||
- Renvoie le ZIP modifié en téléchargement (tout en mémoire).
|
||||
"""
|
||||
# Sécurité : l'auth Basic est déjà gérée par before_request
|
||||
|
||||
# 1. Vérifier que le ZIP template existe
|
||||
if not _LEA_ZIP_TEMPLATE.exists():
|
||||
# 1. Résoudre + vérifier que le ZIP template existe (à la volée)
|
||||
zip_template = _resolve_lea_zip_template()
|
||||
if zip_template is None:
|
||||
return jsonify({
|
||||
'error': 'ZIP template introuvable',
|
||||
'detail': f'{_LEA_ZIP_TEMPLATE} absent — exécuter deploy/build_package.sh',
|
||||
'detail': (
|
||||
f'Ni {_LEA_ZIP_TEMPLATE_FULL} ni {_LEA_ZIP_TEMPLATE_LEGACY} '
|
||||
'présents — exécuter deploy/build_package_full.sh (ZIP complet '
|
||||
'autoportant) ou deploy/build_package.sh (ZIP léger).'
|
||||
),
|
||||
}), 500
|
||||
|
||||
# 2. Vérifier que le machine_id est enregistré
|
||||
@@ -2387,7 +2418,7 @@ def download_agent_package(machine_id):
|
||||
# 5. Créer le ZIP personnalisé en mémoire
|
||||
output_buffer = io.BytesIO()
|
||||
try:
|
||||
with zipfile.ZipFile(_LEA_ZIP_TEMPLATE, 'r') as src_zip:
|
||||
with zipfile.ZipFile(zip_template, 'r') as src_zip:
|
||||
with zipfile.ZipFile(output_buffer, 'w', zipfile.ZIP_DEFLATED) as dst_zip:
|
||||
for item in src_zip.infolist():
|
||||
if item.filename == 'Lea/config.txt':
|
||||
@@ -2399,7 +2430,7 @@ def download_agent_package(machine_id):
|
||||
except zipfile.BadZipFile:
|
||||
return jsonify({
|
||||
'error': 'ZIP template corrompu',
|
||||
'detail': f'{_LEA_ZIP_TEMPLATE} n\'est pas un ZIP valide.',
|
||||
'detail': f'{zip_template} n\'est pas un ZIP valide.',
|
||||
}), 500
|
||||
|
||||
output_buffer.seek(0)
|
||||
|
||||
@@ -2290,7 +2290,7 @@
|
||||
: '<span style="display:inline-block;padding:3px 10px;border-radius:12px;font-size:11px;font-weight:600;background:rgba(100,116,139,0.15);color:#64748b;">révoqué</span>';
|
||||
|
||||
const downloadBtn = isActive
|
||||
? `<a href="/api/fleet/download/${encodeURIComponent(agent.machine_id)}" class="btn btn-primary btn-small" style="text-decoration:none;font-size:11px;" title="Télécharger l'installeur pré-configuré">📥</a>`
|
||||
? `<a href="/api/fleet/download/${encodeURIComponent(agent.machine_id)}" class="btn btn-primary btn-small" style="text-decoration:none;font-size:11px;" title="Télécharger Léa (installation autonome, sans Python — dézipper puis double-cliquer Lea.bat)">📥</a>`
|
||||
: `<span style="font-size:16px;color:#475569;cursor:not-allowed;opacity:0.4;" title="Agent révoqué — installeur indisponible">📥</span>`;
|
||||
|
||||
return `<tr style="border-bottom:1px solid #334155;">
|
||||
|
||||
Reference in New Issue
Block a user