16 KiB
🎯 Ansible Playbook Editor - Design & Architecture
Résumé Exécutif
Refonte complète de l'éditeur de playbooks Ansible pour offrir une expérience IDE-like avec:
- Éditeur CodeMirror 6 avec coloration syntaxique Ansible/YAML avancée
- Intégration ansible-lint non-bloquante avec feedback temps réel
- Score de qualité et historique par playbook
- UX professionnelle inspirée de VS Code/GitHub Actions
1. Vision UX Globale
Philosophie Design
- Clarté avant tout: Interface sobre, focalisée sur le code
- Feedback intelligent: Guidage proactif sans interruption du flux
- Progressive disclosure: Complexité révélée au bon moment
- Performance: Réactivité < 100ms pour les interactions
Principes UX
| Principe | Application |
|---|---|
| Non-bloquant | Lint en arrière-plan, édition jamais interrompue |
| Contextuel | Erreurs affichées à leur emplacement exact |
| Actionnable | Chaque diagnostic propose une correction |
| Discret | Pas de popup intrusif, indicateurs subtils |
2. Design de l'Éditeur
2.1 Architecture de l'Éditeur
┌─────────────────────────────────────────────────────────────────┐
│ 📄 playbook-name.yml [Quality: 92/100 ✓] │
├─────────────────────────────────────────────────────────────────┤
│ ┌──────┬────────────────────────────────────────────────────┐ │
│ │ LINT │ ERRORS (2) WARNINGS (3) INFO (1) │ │
│ ├──────┴────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ [Gutter] [Code Editor Area] │ │
│ │ ⚠ 1 --- │ │
│ │ 2 - name: Deploy application │ │
│ │ 3 hosts: all │ │
│ │ ⛔ 4 become: yes │ │
│ │ ╭──────────────────────────────────────────╮ │ │
│ │ │ ⛔ risky-file-permissions: Missing mode │ │ │
│ │ │ for file operation │ │ │
│ │ │ 📖 Learn more | ✨ Auto-fix │ │ │
│ │ ╰──────────────────────────────────────────╯ │ │
│ │ 5 vars: │ │
│ │ 6 category: deploy │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ [✓ YAML Valid] [⚠ 5 issues] [Ln 4, Col 5] [Annuler] [Save] │
└─────────────────────────────────────────────────────────────────┘
2.2 Coloration Syntaxique Ansible
Tokens à highlighter
| Type | Exemples | Couleur (thème sombre) |
|---|---|---|
| Clés Ansible | hosts, tasks, vars, handlers, become |
#c792ea (violet) |
| Modules | ansible.builtin.copy, community.docker.docker_container |
#82aaff (bleu) |
| Variables Jinja | {{ var }}, {% if %} |
#c3e88d (vert) |
| Valeurs booléennes | true, false, yes, no |
#f78c6c (orange) |
| Commentaires | # comment |
#546e7a (gris) |
| Strings | "text", 'text' |
#c3e88d (vert clair) |
| Nombres | 123, 0.5 |
#f78c6c (orange) |
| Ancres YAML | &anchor, *reference |
#89ddff (cyan) |
2.3 Fonctionnalités Éditeur
- Auto-indentation YAML (2 espaces)
- Bracket matching pour
{{ }},{% %},[],{} - Fold/Unfold des blocs YAML
- Minimap optionnelle
- Search & Replace avec regex
- Multi-curseur
3. Intégration ansible-lint
3.1 Bouton Lint Intelligent
États visuels
┌─────────────────────────────────────────────────────────────┐
│ État │ Icône │ Couleur │ Animation │
├─────────────┼───────────┼────────────┼────────────────────┤
│ Idle │ 🔍 │ Gris │ Aucune │
│ Running │ ⟳ │ Bleu │ Rotation │
│ Success │ ✓ │ Vert │ Pulse subtil │
│ Warnings │ ⚠ (3) │ Jaune │ Aucune │
│ Errors │ ⛔ (2) │ Rouge │ Aucune │
└─────────────────────────────────────────────────────────────┘
3.2 Affichage des Résultats
Gutter Markers
- Icône colorée dans la marge gauche à la ligne concernée
- Survol = tooltip avec résumé
- Clic = panneau détaillé
Inline Diagnostics
- name: Copy config
ansible.builtin.copy:
src: config.yml
dest: /etc/app/config.yml
# ⛔ risky-file-permissions: File permissions unset or incorrect
# 💡 Ajouter: mode: '0644'
Panneau Problèmes (optionnel)
Liste scrollable de tous les problèmes, filtrable par sévérité.
3.3 Workflow Utilisateur
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Ouvrir │────▶│ Éditer │────▶│ Lint │
│ playbook │ │ contenu │ │ (auto/btn) │
└──────────────┘ └──────────────┘ └──────┬───────┘
│
┌────────────────────────────────────────┤
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Afficher │ │ Sauvegarder │
│ résultats │ │ (possible) │
└──────────────┘ └──────┬───────┘
│
▼
┌──────────────┐
│ Exécuter │
│ (bloqué si │
│ erreurs*) │
└──────────────┘
* Configurable
3.4 Comportement Non-Bloquant
| Action | Lint bloque ? | Sauvegarde bloque ? | Exécution bloque ? |
|---|---|---|---|
| Lint en cours | ❌ | ❌ | ❌ |
| Warnings | ❌ | ❌ | ❌ |
| Errors | ❌ | ❌ | ⚠️ Avertissement |
4. Architecture Technique
4.1 Backend - API ansible-lint
Endpoint
POST /api/playbooks/{filename}/lint
Request
{
"content": "---\n- name: My playbook\n hosts: all\n...",
"rules": ["yaml", "risky-file-permissions"], // optionnel
"skip_rules": ["no-changed-when"] // optionnel
}
Response
{
"success": true,
"execution_time_ms": 342,
"summary": {
"total": 5,
"errors": 2,
"warnings": 2,
"info": 1
},
"quality_score": 72,
"issues": [
{
"rule_id": "risky-file-permissions",
"severity": "error",
"message": "File permissions unset or incorrect",
"filename": "playbook.yml",
"line": 12,
"column": 5,
"context": " ansible.builtin.copy:",
"help_url": "https://ansible-lint.readthedocs.io/rules/risky-file-permissions/",
"fix_suggestion": "Add 'mode: \"0644\"' parameter"
}
]
}
Implémentation Backend
# app/routes/lint.py
import asyncio
import json
import tempfile
from pathlib import Path
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
router = APIRouter()
class LintRequest(BaseModel):
content: str
rules: list[str] | None = None
skip_rules: list[str] | None = None
class LintIssue(BaseModel):
rule_id: str
severity: str # error, warning, info
message: str
line: int
column: int
context: str | None = None
help_url: str | None = None
fix_suggestion: str | None = None
class LintResponse(BaseModel):
success: bool
execution_time_ms: int
summary: dict
quality_score: int
issues: list[LintIssue]
@router.post("/{filename}/lint")
async def lint_playbook(filename: str, request: LintRequest):
"""Exécute ansible-lint sur le contenu d'un playbook."""
start_time = asyncio.get_event_loop().time()
# Créer fichier temporaire
with tempfile.NamedTemporaryFile(
mode='w', suffix='.yml', delete=False
) as f:
f.write(request.content)
temp_path = f.name
try:
# Construire commande ansible-lint
cmd = [
'ansible-lint',
'--format', 'json',
'--nocolor',
temp_path
]
if request.skip_rules:
for rule in request.skip_rules:
cmd.extend(['--skip-list', rule])
# Exécuter
process = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await process.communicate()
# Parser JSON
issues = parse_ansible_lint_output(stdout.decode(), temp_path, filename)
# Calculer score
score = calculate_quality_score(issues, len(request.content.split('\n')))
execution_time = int((asyncio.get_event_loop().time() - start_time) * 1000)
return LintResponse(
success=True,
execution_time_ms=execution_time,
summary={
"total": len(issues),
"errors": sum(1 for i in issues if i.severity == "error"),
"warnings": sum(1 for i in issues if i.severity == "warning"),
"info": sum(1 for i in issues if i.severity == "info")
},
quality_score=score,
issues=issues
)
finally:
Path(temp_path).unlink(missing_ok=True)
4.2 Frontend - Composants
Structure des composants
PlaybookEditor/
├── EditorContainer # Container principal
├── CodeMirrorEditor # Instance CodeMirror 6
├── LintButton # Bouton avec états
├── LintResultsPanel # Panneau latéral/bas
├── GutterMarkers # Marqueurs dans la marge
├── InlineDiagnostics # Diagnostics inline
├── QualityBadge # Score de qualité
└── StatusBar # Barre de statut
Gestion d'état
const editorState = {
// Contenu
content: '',
originalContent: '',
isDirty: false,
// Lint
lintStatus: 'idle', // idle | running | success | warnings | errors
lintResults: null,
lastLintTime: null,
// Qualité
qualityScore: null,
// UI
showProblemsPanel: false,
activeIssueIndex: null,
// Config
lintOnSave: true,
blockExecutionOnErrors: true
};
Stratégie de Performance
- Debounce: Lint auto après 1500ms d'inactivité
- Abort Controller: Annuler lint précédent si nouvelle édition
- Virtual Scrolling: Pour longs playbooks (>1000 lignes)
- Web Worker: Parser YAML en background (optionnel)
5. Idées Bonus à Forte Valeur
5.1 📊 Quality Score Dashboard
Score 0-100 basé sur:
- Nombre d'erreurs (-20 pts/erreur)
- Nombre de warnings (-5 pts/warning)
- Bonnes pratiques suivies (+5 pts)
- Historique (trend: amélioration ou dégradation)
┌────────────────────────────────────────┐
│ Quality Score: 87/100 ↑ +5 │
│ ████████████████████░░░░ │
│ │
│ ✓ No deprecated modules │
│ ✓ FQCN used consistently │
│ ⚠ 2 missing task names │
│ ⚠ 1 risky permission │
└────────────────────────────────────────┘
5.2 🔧 Auto-Fix Suggestions
Pour certaines règles, proposer des corrections automatiques:
no-free-form: Convertir en syntaxe structuréerisky-file-permissions: Ajoutermode: '0644'fqcn: Convertircopy→ansible.builtin.copyyaml[truthy]: Convertiryes→true
5.3 📈 Lint History par Playbook
Stocker l'historique des scores pour chaque playbook:
{
"playbook": "deploy-app.yml",
"history": [
{"date": "2025-01-15", "score": 65, "errors": 3, "warnings": 5},
{"date": "2025-01-16", "score": 78, "errors": 1, "warnings": 3},
{"date": "2025-01-17", "score": 92, "errors": 0, "warnings": 1}
]
}
5.4 💡 Assistant Bonnes Pratiques
Suggestions proactives basées sur le contexte:
- "Cette tâche modifie des fichiers. Ajoutez un handler notify."
- "Utilisez become_user au lieu de become pour plus de sécurité."
- "Préférez ansible.builtin.command à shell pour les commandes simples."
5.5 🔄 Pré-validation Commit
Hook optionnel pour valider avant git commit (documentation fournie).
6. Plan d'Implémentation
Phase 1: Backend Lint API ✅
- Endpoint
/api/playbooks/{filename}/lint - Parsing JSON ansible-lint
- Calcul quality score
- Suggestions de correction par règle
- URLs de documentation
Phase 2: Éditeur CodeMirror 6 ✅
- Intégration CDN CodeMirror 6 (avec fallback textarea)
- Configuration YAML + thème personnalisé
- Coloration Ansible avancée
Phase 3: UI ansible-lint ✅
- LintButton avec états (idle, running, success, warnings, errors)
- Panneau problèmes avec navigation vers ligne
- Badge de qualité coloré
- Onglets Éditeur / Problèmes
Phase 4: Bonus ✅
- Quality Score (0-100) avec bonus/malus
- Suggestions de fix par règle
- Liens vers documentation ansible-lint
Tests ✅
- 24 tests unitaires (100% passing)
- Tests parsing JSON/texte
- Tests endpoint API
- Tests calcul score qualité
7. Résumé Pitch Produit
Éditeur Ansible IDE-like pour votre Homelab
Passez de "ça marche peut-être" à "je suis sûr que c'est correct" avec notre éditeur de playbooks intelligent.
✨ Coloration syntaxique Ansible - Modules, variables Jinja, clés YAML 🔍 ansible-lint intégré - Feedback en temps réel, sans bloquer 📊 Score de qualité - Suivez l'évolution de vos playbooks ⚡ Non-bloquant - Éditez, sauvegardez, le lint tourne en arrière-plan 🎯 Actionnable - Chaque erreur avec explication et suggestion de fix