first commit
This commit is contained in:
commit
21bee026ff
65
.dockerignore
Normal file
65
.dockerignore
Normal file
@ -0,0 +1,65 @@
|
||||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Python
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.Python
|
||||
*.so
|
||||
.eggs
|
||||
*.egg-info
|
||||
.pytest_cache
|
||||
.mypy_cache
|
||||
.tox
|
||||
.nox
|
||||
.coverage
|
||||
htmlcov
|
||||
.hypothesis
|
||||
|
||||
# Virtual environments
|
||||
venv
|
||||
.venv
|
||||
env
|
||||
ENV
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
.vscode
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Docker
|
||||
Dockerfile
|
||||
docker-compose.yml
|
||||
.dockerignore
|
||||
|
||||
# Documentation
|
||||
*.md
|
||||
!README.md
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
logs/
|
||||
|
||||
# Environment files (contient des secrets)
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Tests
|
||||
tests/
|
||||
test_*.py
|
||||
*_test.py
|
||||
|
||||
# Temporary files
|
||||
tmp/
|
||||
temp/
|
||||
*.tmp
|
||||
22
.env.example
Normal file
22
.env.example
Normal file
@ -0,0 +1,22 @@
|
||||
# Configuration du Homelab Automation Dashboard
|
||||
# Copier ce fichier en .env et adapter les valeurs
|
||||
|
||||
# Clé API pour l'authentification (changer en production!)
|
||||
API_KEY=dev-key-12345
|
||||
|
||||
# Utilisateur SSH pour Ansible (doit exister sur les hôtes cibles)
|
||||
SSH_USER=automation
|
||||
|
||||
# Répertoire contenant les clés SSH sur la machine hôte
|
||||
# Sera monté en lecture seule dans le container
|
||||
SSH_KEY_DIR=~/.ssh
|
||||
|
||||
# Répertoire des logs de tâches (fichiers markdown classés par YYYY/MM/JJ)
|
||||
# Ce répertoire sera monté dans le container et contiendra l'historique
|
||||
# des exécutions de tâches au format markdown
|
||||
# Exemple Windows: C:\Obsidian_doc\SessionsManager\60-TACHES\LOGS
|
||||
# Exemple Linux: /home/user/tasks_logs
|
||||
DIR_LOGS_TASKS=./tasks_logs
|
||||
|
||||
# Optionnel: Chemin spécifique de la clé privée SSH
|
||||
# SSH_KEY_PATH=/path/to/id_rsa
|
||||
46
.gitignore
vendored
Normal file
46
.gitignore
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# Virtual environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Logs de tâches (gardent la structure mais pas les fichiers md)
|
||||
tasks_logs/**/*.md
|
||||
tasks_logs/**/.adhoc_history.json
|
||||
!tasks_logs/.gitkeep
|
||||
|
||||
# Docker
|
||||
*.log
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
55
Dockerfile
Normal file
55
Dockerfile
Normal file
@ -0,0 +1,55 @@
|
||||
# Dockerfile pour Homelab Automation Dashboard avec Ansible
|
||||
FROM python:3.11-slim
|
||||
|
||||
# Métadonnées
|
||||
LABEL maintainer="Homelab Automation"
|
||||
LABEL description="Dashboard d'automatisation Homelab avec FastAPI et Ansible"
|
||||
LABEL version="1.0"
|
||||
|
||||
# Variables d'environnement
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV ANSIBLE_HOST_KEY_CHECKING=False
|
||||
ENV ANSIBLE_RETRY_FILES_ENABLED=False
|
||||
|
||||
# Répertoire de travail
|
||||
WORKDIR /app
|
||||
|
||||
# Installation des dépendances système pour Ansible et SSH
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
openssh-client \
|
||||
sshpass \
|
||||
ansible \
|
||||
git \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean
|
||||
|
||||
# Création du répertoire SSH et configuration
|
||||
RUN mkdir -p /root/.ssh && chmod 700 /root/.ssh
|
||||
|
||||
# Copie des requirements et installation des dépendances Python
|
||||
COPY app/requirements.txt ./
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copie du code de l'application
|
||||
COPY app/ ./
|
||||
|
||||
# Copie de la configuration Ansible
|
||||
COPY ansible/ /ansible/
|
||||
|
||||
# Création du répertoire pour les clés SSH (sera monté en volume)
|
||||
RUN mkdir -p /app/ssh_keys
|
||||
|
||||
# Configuration Ansible pour utiliser le bon répertoire
|
||||
ENV ANSIBLE_CONFIG=/ansible/ansible.cfg
|
||||
|
||||
# Exposition du port
|
||||
EXPOSE 8000
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:8000/api/health || exit 1
|
||||
|
||||
# Commande de démarrage
|
||||
CMD ["python", "-m", "uvicorn", "app_optimized:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
BIN
OKComputer_Optimiser UI_UX.zip
Normal file
BIN
OKComputer_Optimiser UI_UX.zip
Normal file
Binary file not shown.
426
README.md
Normal file
426
README.md
Normal file
@ -0,0 +1,426 @@
|
||||
# Homelab Automation Dashboard
|
||||
|
||||
Une application moderne et professionnelle pour la gestion automatisée d'homelab, avec une interface utilisateur élégante et une API REST puissante.
|
||||
|
||||
## ✨ Fonctionnalités
|
||||
|
||||
### Interface Utilisateur
|
||||
- **Design Moderne** : Interface élégante avec thème sombre et animations fluides
|
||||
- **Tableau de Bord Temps Réel** : Métriques et statistiques en direct
|
||||
- **Gestion des Hôtes** : Ajout, suppression et surveillance des serveurs
|
||||
- **Gestion des Tâches** : Création et suivi des tâches automatisées
|
||||
- **Logs Système** : Journalisation complète avec filtrage
|
||||
- **WebSocket** : Mises à jour en temps réel sans rechargement
|
||||
- **Animations** : Effets visuels professionnels avec Anime.js
|
||||
|
||||
### API REST
|
||||
- **Endpoints Complets** : Gestion complète des hôtes, tâches et logs
|
||||
- **Validation Pydantic** : Validation automatique des données
|
||||
- **WebSocket Support** : Communication temps réel
|
||||
- **Authentification API** : Sécurité renforcée avec clés API
|
||||
- **Documentation Interactive** : Swagger UI et ReDoc
|
||||
- **CORS Support** : Compatible avec les applications web modernes
|
||||
|
||||
### Intégration Ansible
|
||||
- **Exécution de Playbooks** : Lancer des playbooks Ansible depuis le dashboard
|
||||
- **Inventaire Dynamique** : Lecture automatique de l'inventaire Ansible
|
||||
- **Actions Rapides** : Upgrade, Reboot, Health-check, Backup en un clic
|
||||
- **Groupes Ansible** : Sélection des cibles par groupe (proxmox, lab, prod, etc.)
|
||||
|
||||
## 🛠️ Technologies Utilisées
|
||||
|
||||
### Frontend
|
||||
- **HTML5 & CSS3** : Structure et styles modernes
|
||||
- **Tailwind CSS** : Framework CSS utilitaire
|
||||
- **Anime.js** : Bibliothèque d'animations
|
||||
- **Font Awesome** : Icônes professionnelles
|
||||
- **Google Fonts (Inter)** : Typographie moderne
|
||||
|
||||
### Backend
|
||||
- **FastAPI** : Framework web Python moderne et rapide
|
||||
- **Pydantic** : Validation de données
|
||||
- **WebSockets** : Communication temps réel
|
||||
- **Uvicorn** : Serveur ASGI performant
|
||||
|
||||
## 📁 Structure du Projet
|
||||
|
||||
```
|
||||
homelab-automation-api-v2/
|
||||
├── app/
|
||||
│ ├── app_optimized.py # Backend FastAPI avec intégration Ansible
|
||||
│ ├── index.html # Interface principale du dashboard
|
||||
│ ├── main.js # Logique JavaScript (appels API)
|
||||
│ └── requirements.txt # Dépendances Python
|
||||
├── ansible/
|
||||
│ ├── ansible.cfg # Configuration Ansible
|
||||
│ ├── inventory/
|
||||
│ │ └── hosts.yml # Inventaire des hôtes
|
||||
│ ├── group_vars/
|
||||
│ │ └── homelab.yml # Variables de groupe
|
||||
│ └── playbooks/
|
||||
│ ├── vm-upgrade.yml # Mise à jour des systèmes
|
||||
│ ├── vm-reboot.yml # Redémarrage des hôtes
|
||||
│ ├── health-check.yml # Vérification de santé
|
||||
│ └── backup-config.yml # Sauvegarde de configuration
|
||||
└── README.md # Documentation
|
||||
```
|
||||
|
||||
## 🚀 Installation et Lancement
|
||||
|
||||
### Prérequis
|
||||
- Python 3.10+ (testé avec Python 3.14)
|
||||
- Ansible (pour l'exécution des playbooks)
|
||||
- Navigateur moderne (Chrome, Firefox, Safari, Edge)
|
||||
|
||||
### Installation d'Ansible (optionnel mais recommandé)
|
||||
```bash
|
||||
# Sur Debian/Ubuntu
|
||||
sudo apt install ansible
|
||||
|
||||
# Sur Windows (via pip)
|
||||
pip install ansible
|
||||
|
||||
# Sur macOS
|
||||
brew install ansible
|
||||
```
|
||||
|
||||
### Installation
|
||||
|
||||
1. **Cloner le projet**
|
||||
```bash
|
||||
git clone <url-du-repo>
|
||||
cd homelab-automation-api-v2/app
|
||||
```
|
||||
|
||||
2. **Installer les dépendances Python**
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
3. **Lancer le serveur backend (recommandé)**
|
||||
```bash
|
||||
python -m uvicorn app_optimized:app --host 0.0.0.0 --port 8000 --reload
|
||||
```
|
||||
|
||||
Ou directement via le script Python :
|
||||
```bash
|
||||
python app_optimized.py
|
||||
```
|
||||
|
||||
4. **Ouvrir le dashboard frontend complet** (interface de l'image 1)
|
||||
|
||||
Naviguez vers :
|
||||
- `http://localhost:8000/ui` → Dashboard Homelab (frontend HTML/JS)
|
||||
|
||||
5. **Accéder à la page API** (interface de l'image 2)
|
||||
|
||||
Naviguez vers :
|
||||
- `http://localhost:8000` → Page d'accueil API avec liens vers la documentation
|
||||
|
||||
## 📖 Utilisation
|
||||
|
||||
### Interface Web
|
||||
|
||||
1. **Tableau de Bord** : Vue d'ensemble des métriques système
|
||||
2. **Gestion des Hôtes** :
|
||||
- Ajouter de nouveaux hôtes avec le bouton "Ajouter Host"
|
||||
- Surveiller l'état des hôtes en temps réel
|
||||
- Exécuter des actions (connexion, mise à jour, redémarrage)
|
||||
3. **Gestion des Tâches** :
|
||||
- Créer des tâches d'automatisation
|
||||
- Suivre la progression en temps réel
|
||||
- Voir les détails et les logs
|
||||
4. **Logs Système** : Consulter l'historique des événements
|
||||
|
||||
### API REST
|
||||
|
||||
#### Authentification
|
||||
Toutes les requêtes API nécessitent une clé API dans le header `X-API-Key`:
|
||||
```bash
|
||||
curl -H "X-API-Key: dev-key-12345" http://localhost:8000/api/hosts
|
||||
```
|
||||
|
||||
#### Endpoints Principaux
|
||||
|
||||
**Hôtes**
|
||||
- `GET /api/hosts` - Liste tous les hôtes
|
||||
- `POST /api/hosts` - Crée un nouvel hôte
|
||||
- `GET /api/hosts/{id}` - Récupère un hôte spécifique
|
||||
- `DELETE /api/hosts/{id}` - Supprime un hôte
|
||||
|
||||
**Tâches**
|
||||
- `GET /api/tasks` - Liste toutes les tâches
|
||||
- `POST /api/tasks` - Crée une nouvelle tâche
|
||||
- `GET /api/tasks/{id}` - Récupère une tâche spécifique
|
||||
- `DELETE /api/tasks/{id}` - Supprime une tâche
|
||||
|
||||
**Logs**
|
||||
- `GET /api/logs` - Récupère les logs récents
|
||||
- `POST /api/logs` - Ajoute un nouveau log
|
||||
- `DELETE /api/logs` - Efface tous les logs
|
||||
|
||||
**Métriques**
|
||||
- `GET /api/metrics` - Métriques système
|
||||
- `GET /api/health/{host}` - Health check d'un hôte
|
||||
|
||||
**WebSocket**
|
||||
- `WS /ws` - Connexion WebSocket pour les mises à jour temps réel
|
||||
|
||||
**Ansible** (nouveaux endpoints)
|
||||
- `GET /api/ansible/playbooks` - Liste les playbooks disponibles
|
||||
- `GET /api/ansible/inventory` - Récupère l'inventaire Ansible (hôtes et groupes)
|
||||
- `GET /api/ansible/groups` - Liste les groupes Ansible
|
||||
- `POST /api/ansible/execute` - Exécute un playbook directement
|
||||
- `POST /api/ansible/adhoc` - Exécute une commande ad-hoc sur les hôtes
|
||||
- `POST /api/ansible/bootstrap` - Bootstrap un hôte pour Ansible (crée user, SSH, sudo, Python)
|
||||
- `GET /api/ansible/ssh-config` - Diagnostic de la configuration SSH
|
||||
|
||||
#### Exemples d'utilisation Ansible
|
||||
|
||||
**Lister les playbooks disponibles :**
|
||||
```bash
|
||||
curl -H "X-API-Key: dev-key-12345" http://localhost:8000/api/ansible/playbooks
|
||||
```
|
||||
|
||||
**Voir l'inventaire Ansible :**
|
||||
```bash
|
||||
curl -H "X-API-Key: dev-key-12345" http://localhost:8000/api/ansible/inventory
|
||||
```
|
||||
|
||||
**Exécuter un playbook (ex: mise à jour sur le groupe "lab") :**
|
||||
```bash
|
||||
curl -X POST -H "X-API-Key: dev-key-12345" -H "Content-Type: application/json" \
|
||||
-d '{"playbook": "vm-upgrade.yml", "target": "lab"}' \
|
||||
http://localhost:8000/api/ansible/execute
|
||||
```
|
||||
|
||||
**Créer une tâche Ansible via l'API tasks :**
|
||||
```bash
|
||||
curl -X POST -H "X-API-Key: dev-key-12345" -H "Content-Type: application/json" \
|
||||
-d '{"action": "upgrade", "group": "proxmox"}' \
|
||||
http://localhost:8000/api/tasks
|
||||
```
|
||||
|
||||
**Exécuter une commande ad-hoc :**
|
||||
```bash
|
||||
# Vérifier l'espace disque sur tous les hôtes
|
||||
curl -X POST -H "X-API-Key: dev-key-12345" -H "Content-Type: application/json" \
|
||||
-d '{"target": "all", "command": "df -h /", "module": "shell"}' \
|
||||
http://localhost:8000/api/ansible/adhoc
|
||||
|
||||
# Redémarrer un service avec sudo
|
||||
curl -X POST -H "X-API-Key: dev-key-12345" -H "Content-Type: application/json" \
|
||||
-d '{"target": "web-servers", "command": "systemctl restart nginx", "become": true}' \
|
||||
http://localhost:8000/api/ansible/adhoc
|
||||
```
|
||||
|
||||
### Documentation API
|
||||
|
||||
- **Swagger UI** : `http://localhost:8000/api/docs`
|
||||
- **ReDoc** : `http://localhost:8000/api/redoc`
|
||||
|
||||
## 🎨 Personnalisation
|
||||
|
||||
### Thèmes
|
||||
L'application supporte les thèmes clair et sombre. Utilisez le bouton en haut à droite pour basculer.
|
||||
|
||||
### Couleurs
|
||||
Les couleurs principales peuvent être modifiées dans les variables CSS :
|
||||
```css
|
||||
:root {
|
||||
--primary-bg: #0a0a0a;
|
||||
--accent-color: #7c3aed;
|
||||
--success-color: #10b981;
|
||||
--error-color: #ef4444;
|
||||
}
|
||||
```
|
||||
|
||||
### Animations
|
||||
Les animations sont gérées par Anime.js dans `main.js`. Vous pouvez ajuster :
|
||||
- La durée des animations
|
||||
- Les effets de transition
|
||||
- Les comportements au scroll
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Variables d'Environnement
|
||||
|
||||
Créez un fichier `.env` pour configurer l'application :
|
||||
|
||||
```env
|
||||
API_KEY=votre-cle-api-secrete
|
||||
SSH_REMOTE_USER=automation
|
||||
LOGS_DIR=/var/log/homelab
|
||||
ANSIBLE_DIR=/etc/ansible
|
||||
```
|
||||
|
||||
### Base de Données
|
||||
|
||||
Par défaut, l'application utilise une base de données en mémoire. Pour une utilisation en production, configurez PostgreSQL ou SQLite en modifiant la classe `InMemoryDB`.
|
||||
|
||||
## 🚀 Déploiement
|
||||
|
||||
### Production
|
||||
|
||||
1. **Configuration de la base de données**
|
||||
```python
|
||||
# Remplacer InMemoryDB par une vraie base de données
|
||||
```
|
||||
|
||||
2. **Sécurité**
|
||||
- Utilisez une clé API forte
|
||||
- Activez HTTPS
|
||||
- Configurez les pare-feu
|
||||
- Limitez les origines CORS
|
||||
|
||||
3. **Performance**
|
||||
- Utilisez un serveur de production (Gunicorn)
|
||||
- Configurez Redis pour le cache
|
||||
- Activez la compression
|
||||
|
||||
### Docker
|
||||
|
||||
Le projet inclut un Dockerfile et docker-compose.yml prêts à l'emploi avec Ansible intégré.
|
||||
|
||||
#### Démarrage rapide avec Docker Compose
|
||||
|
||||
```bash
|
||||
# 1. Copier le fichier d'exemple d'environnement
|
||||
cp .env.example .env
|
||||
|
||||
# 2. Éditer .env pour configurer vos clés SSH
|
||||
nano .env
|
||||
|
||||
# 3. Lancer le container
|
||||
docker-compose up -d
|
||||
|
||||
# 4. Accéder au dashboard
|
||||
# http://localhost:8000/ui
|
||||
```
|
||||
|
||||
#### Configuration des clés SSH
|
||||
|
||||
Par défaut, docker-compose monte votre répertoire `~/.ssh` en lecture seule. Assurez-vous que :
|
||||
|
||||
1. Votre clé privée SSH existe : `~/.ssh/id_rsa`
|
||||
2. Votre clé publique existe : `~/.ssh/id_rsa.pub`
|
||||
|
||||
Ou spécifiez un répertoire différent dans `.env` :
|
||||
```bash
|
||||
SSH_KEY_DIR=/chemin/vers/vos/cles/ssh
|
||||
```
|
||||
|
||||
#### Variables d'environnement
|
||||
|
||||
| Variable | Description | Défaut |
|
||||
|----------|-------------|--------|
|
||||
| `API_KEY` | Clé API pour l'authentification | `dev-key-12345` |
|
||||
| `SSH_USER` | Utilisateur SSH pour Ansible | `automation` |
|
||||
| `SSH_KEY_DIR` | Répertoire des clés SSH sur l'hôte | `~/.ssh` |
|
||||
| `SSH_KEY_PATH` | Chemin de la clé privée dans le container | `/app/ssh_keys/id_rsa` |
|
||||
|
||||
#### Construction manuelle de l'image
|
||||
|
||||
```bash
|
||||
# Construire l'image
|
||||
docker build -t homelab-dashboard .
|
||||
```
|
||||
|
||||
```bash
|
||||
# Exécuter le container
|
||||
docker run -d \
|
||||
-p 8000:8000 \
|
||||
-v ~/.ssh:/app/ssh_keys:ro \
|
||||
-v ./ansible/inventory:/ansible/inventory:ro \
|
||||
-e API_KEY=votre-cle-api-secrete \
|
||||
--name homelab-dashboard \
|
||||
homelab-dashboard
|
||||
```
|
||||
|
||||
```bash
|
||||
# se connecter au container
|
||||
docker exec -it homelab-dashboard /bin/bash
|
||||
```
|
||||
|
||||
## 🔧 Bootstrap SSH
|
||||
|
||||
Le dashboard inclut une fonctionnalité de **Bootstrap** pour préparer automatiquement un hôte à recevoir des commandes Ansible.
|
||||
|
||||
### Ce que fait le Bootstrap
|
||||
|
||||
1. **Crée l'utilisateur d'automatisation** (par défaut: `automation`)
|
||||
2. **Configure l'authentification SSH par clé** (copie votre clé publique)
|
||||
3. **Installe et configure sudo** sans mot de passe pour cet utilisateur
|
||||
4. **Installe Python3** (requis par Ansible)
|
||||
5. **Vérifie la connexion SSH** par clé après configuration
|
||||
|
||||
### Systèmes supportés
|
||||
|
||||
- **Debian/Ubuntu** (apt)
|
||||
- **Alpine Linux** (apk)
|
||||
- **FreeBSD** (pkg)
|
||||
|
||||
### Utilisation via l'interface
|
||||
|
||||
1. Cliquez sur le bouton **Bootstrap** (jaune) sur la carte d'un hôte
|
||||
2. Entrez le **mot de passe root** de l'hôte distant
|
||||
3. Optionnel : modifiez le nom de l'utilisateur d'automatisation
|
||||
4. Cliquez sur **Lancer le Bootstrap**
|
||||
|
||||
### Utilisation via l'API
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/api/ansible/bootstrap \
|
||||
-H "X-API-Key: dev-key-12345" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"host": "192.168.1.100",
|
||||
"root_password": "votre-mot-de-passe-root",
|
||||
"automation_user": "automation"
|
||||
}'
|
||||
```
|
||||
|
||||
### Prérequis
|
||||
|
||||
- **sshpass** doit être installé sur la machine qui exécute le dashboard
|
||||
- L'hôte cible doit accepter les connexions SSH avec mot de passe (pour la configuration initiale)
|
||||
- Le compte root doit être accessible via SSH
|
||||
|
||||
```bash
|
||||
# Installation de sshpass
|
||||
# Debian/Ubuntu
|
||||
apt install sshpass
|
||||
|
||||
# Alpine
|
||||
apk add sshpass
|
||||
|
||||
# macOS
|
||||
brew install hudochenkov/sshpass/sshpass
|
||||
```
|
||||
|
||||
## 🤝 Contribution
|
||||
|
||||
Les contributions sont les bienvenues ! Veuillez :
|
||||
|
||||
1. Fork le projet
|
||||
2. Créer une branche pour votre fonctionnalité
|
||||
3. Commit vos changements
|
||||
4. Push vers la branche
|
||||
5. Ouvrir une Pull Request
|
||||
|
||||
## 📄 Licence
|
||||
|
||||
Ce projet est sous licence MIT. Voir le fichier LICENSE pour plus de détails.
|
||||
|
||||
## 🆘 Support
|
||||
|
||||
Pour toute question ou problème :
|
||||
|
||||
1. Consultez la documentation
|
||||
2. Vérifiez les logs du serveur
|
||||
3. Ouvrez une issue sur GitHub
|
||||
4. Contactez l'équipe de développement
|
||||
|
||||
---
|
||||
|
||||
**Développé avec ❤️ pour la communauté homelab**
|
||||
9
ansible/ansible.cfg
Normal file
9
ansible/ansible.cfg
Normal file
@ -0,0 +1,9 @@
|
||||
[defaults]
|
||||
inventory = ./inventory/hosts.yml
|
||||
host_key_checking = False
|
||||
retry_files_enabled = False
|
||||
stdout_callback = default
|
||||
bin_ansible_callbacks = True
|
||||
|
||||
[callback_default]
|
||||
result_format = yaml
|
||||
4
ansible/inventory/group_vars/env_homelab.yml
Normal file
4
ansible/inventory/group_vars/env_homelab.yml
Normal file
@ -0,0 +1,4 @@
|
||||
ansible_port: 22
|
||||
ansible_user: automation
|
||||
ansible_ssh_private_key_file: /app/ssh_keys/id_automation_ansible
|
||||
|
||||
4
ansible/inventory/group_vars/env_lab.yml
Normal file
4
ansible/inventory/group_vars/env_lab.yml
Normal file
@ -0,0 +1,4 @@
|
||||
ansible_port: 22
|
||||
ansible_user: automation
|
||||
ansible_ssh_private_key_file: /app/ssh_keys/id_automation_ansible
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
4
ansible/inventory/group_vars/env_prod.yml
Normal file
4
ansible/inventory/group_vars/env_prod.yml
Normal file
@ -0,0 +1,4 @@
|
||||
ansible_port: 22
|
||||
ansible_user: automation
|
||||
ansible_ssh_private_key_file: /app/ssh_keys/id_automation_ansible
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
4
ansible/inventory/group_vars/role_proxmox.yml
Normal file
4
ansible/inventory/group_vars/role_proxmox.yml
Normal file
@ -0,0 +1,4 @@
|
||||
ansible_port: 22
|
||||
ansible_user: automation
|
||||
ansible_ssh_private_key_file: /app/ssh_keys/id_automation_ansible
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
4
ansible/inventory/group_vars/role_sbc.yml
Normal file
4
ansible/inventory/group_vars/role_sbc.yml
Normal file
@ -0,0 +1,4 @@
|
||||
ansible_port: 22
|
||||
ansible_user: automation
|
||||
ansible_ssh_private_key_file: /app/ssh_keys/id_automation_ansible
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
1
ansible/inventory/group_vars/role_truenas.yml
Normal file
1
ansible/inventory/group_vars/role_truenas.yml
Normal file
@ -0,0 +1 @@
|
||||
ansible_python_interpreter: /usr/local/bin/python3
|
||||
52
ansible/inventory/hosts.yml
Normal file
52
ansible/inventory/hosts.yml
Normal file
@ -0,0 +1,52 @@
|
||||
all:
|
||||
children:
|
||||
env_homelab:
|
||||
hosts:
|
||||
ali2v.xeon.home: null
|
||||
hp.nas.home: null
|
||||
hp2.i7.home: null
|
||||
hp3.i5.home: null
|
||||
mimi.pc.home: null
|
||||
orangepi.pc.home: null
|
||||
raspi.4gb.home: null
|
||||
raspi.8gb.home: null
|
||||
env_lab:
|
||||
hosts:
|
||||
media.labb.home: null
|
||||
dev.lab.home: null
|
||||
env_prod:
|
||||
hosts:
|
||||
hp.truenas.home: null
|
||||
ali2v.truenas.home: null
|
||||
jump.point.home: null
|
||||
automate.prod.home: null
|
||||
dev.prod.home: null
|
||||
role_proxmox:
|
||||
hosts:
|
||||
ali2v.xeon.home: null
|
||||
hp.nas.home: null
|
||||
hp2.i7.home: null
|
||||
hp3.i5.home: null
|
||||
mimi.pc.home: null
|
||||
role_lab_servers:
|
||||
hosts:
|
||||
media.labb.home: null
|
||||
dev.lab.home: null
|
||||
role_truenas:
|
||||
hosts:
|
||||
hp.truenas.home: null
|
||||
ali2v.truenas.home:
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
role_prod_servers:
|
||||
hosts:
|
||||
jump.point.home: null
|
||||
automate.prod.home: null
|
||||
dev.prod.home: null
|
||||
role_sbc:
|
||||
hosts:
|
||||
orangepi.pc.home: null
|
||||
raspi.4gb.home: null
|
||||
raspi.8gb.home: null
|
||||
role_docker:
|
||||
hosts:
|
||||
dev.lab.home: null
|
||||
55
ansible/inventory/hosts.yml.bak
Normal file
55
ansible/inventory/hosts.yml.bak
Normal file
@ -0,0 +1,55 @@
|
||||
all:
|
||||
children:
|
||||
env_homelab:
|
||||
hosts:
|
||||
ali2v.xeon.home: null
|
||||
hp.nas.home: null
|
||||
hp2.i7.home: null
|
||||
hp3.i5.home: null
|
||||
mimi.pc.home: null
|
||||
orangepi.pc.home: null
|
||||
raspi.4gb.home: null
|
||||
raspi.8gb.home: null
|
||||
env_lab:
|
||||
hosts:
|
||||
media.labb.home: null
|
||||
toto:
|
||||
ansible_host: toto.home
|
||||
dev.lab.home: null
|
||||
env_prod:
|
||||
hosts:
|
||||
hp.truenas.home: null
|
||||
ali2v.truenas.home: null
|
||||
jump.point.home: null
|
||||
automate.prod.home: null
|
||||
dev.prod.home: null
|
||||
role_proxmox:
|
||||
hosts:
|
||||
ali2v.xeon.home: null
|
||||
hp.nas.home: null
|
||||
hp2.i7.home: null
|
||||
hp3.i5.home: null
|
||||
mimi.pc.home: null
|
||||
role_lab_servers:
|
||||
hosts:
|
||||
media.labb.home: null
|
||||
toto: null
|
||||
dev.lab.home: null
|
||||
role_truenas:
|
||||
hosts:
|
||||
hp.truenas.home: null
|
||||
ali2v.truenas.home:
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
role_prod_servers:
|
||||
hosts:
|
||||
jump.point.home: null
|
||||
automate.prod.home: null
|
||||
dev.prod.home: null
|
||||
role_sbc:
|
||||
hosts:
|
||||
orangepi.pc.home: null
|
||||
raspi.4gb.home: null
|
||||
raspi.8gb.home: null
|
||||
role_docker:
|
||||
hosts:
|
||||
dev.lab.home: null
|
||||
47
ansible/playbooks/backup-config.yml
Normal file
47
ansible/playbooks/backup-config.yml
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
- name: Backup configuration files
|
||||
hosts: all
|
||||
become: true
|
||||
gather_facts: true
|
||||
vars:
|
||||
category: backup
|
||||
subcategory: configuration
|
||||
backup_dir: /tmp/config_backup
|
||||
timestamp: "{{ ansible_date_time.iso8601_basic_short }}"
|
||||
tasks:
|
||||
- name: Create backup directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ backup_dir }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Backup /etc directory (essential configs)
|
||||
ansible.builtin.archive:
|
||||
path:
|
||||
- /etc/hostname
|
||||
- /etc/hosts
|
||||
- /etc/passwd
|
||||
- /etc/group
|
||||
- /etc/shadow
|
||||
- /etc/sudoers
|
||||
- /etc/ssh/sshd_config
|
||||
dest: "{{ backup_dir }}/etc_backup_{{ timestamp }}.tar.gz"
|
||||
format: gz
|
||||
ignore_errors: true
|
||||
|
||||
- name: Backup crontabs
|
||||
ansible.builtin.shell: |
|
||||
crontab -l > {{ backup_dir }}/crontab_{{ timestamp }}.txt 2>/dev/null || echo "No crontab"
|
||||
changed_when: false
|
||||
|
||||
- name: List backup files
|
||||
ansible.builtin.find:
|
||||
paths: "{{ backup_dir }}"
|
||||
patterns: "*{{ timestamp }}*"
|
||||
register: backup_files
|
||||
|
||||
- name: Display backup summary
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
Backup completed for {{ inventory_hostname }}
|
||||
Files created: {{ backup_files.files | map(attribute='path') | list }}
|
||||
229
ansible/playbooks/bootstrap-host.yml
Normal file
229
ansible/playbooks/bootstrap-host.yml
Normal file
@ -0,0 +1,229 @@
|
||||
---
|
||||
- name: Bootstrap host for Ansible automation
|
||||
hosts: all
|
||||
become: true
|
||||
gather_facts: false
|
||||
vars:
|
||||
category: maintenance
|
||||
subcategory: bootstrap
|
||||
automation_user: "{{ lookup('env', 'SSH_USER') | default('automation', true) }}"
|
||||
ssh_public_key_path: "/app/ssh_keys/id_rsa.pub"
|
||||
|
||||
tasks:
|
||||
- name: Detect OS type
|
||||
raw: |
|
||||
if command -v apk >/dev/null 2>&1; then
|
||||
echo "alpine"
|
||||
elif command -v pkg >/dev/null 2>&1 && [ -f /etc/freebsd-update.conf ]; then
|
||||
echo "freebsd"
|
||||
elif [ -f /etc/debian_version ]; then
|
||||
echo "debian"
|
||||
elif [ -f /etc/redhat-release ]; then
|
||||
echo "redhat"
|
||||
else
|
||||
echo "unknown"
|
||||
fi
|
||||
register: os_type_raw
|
||||
changed_when: false
|
||||
|
||||
- name: Detect OS variant (Armbian, Raspbian, etc.)
|
||||
raw: |
|
||||
if [ -f /etc/armbian-release ]; then
|
||||
echo "armbian"
|
||||
elif [ -f /etc/rpi-issue ] || grep -qi "raspberry" /proc/cpuinfo 2>/dev/null; then
|
||||
echo "raspbian"
|
||||
else
|
||||
echo "standard"
|
||||
fi
|
||||
register: os_variant_raw
|
||||
changed_when: false
|
||||
|
||||
- name: Set OS type fact
|
||||
set_fact:
|
||||
os_type: "{{ os_type_raw.stdout | trim }}"
|
||||
os_variant: "{{ os_variant_raw.stdout | trim }}"
|
||||
|
||||
- name: Display detected OS
|
||||
debug:
|
||||
msg: "[1/7] OS détecté: {{ os_type }} ({{ os_variant }})"
|
||||
|
||||
- name: Check if automation user exists
|
||||
raw: id {{ automation_user }} 2>/dev/null && echo "exists" || echo "not_exists"
|
||||
register: user_check
|
||||
changed_when: false
|
||||
|
||||
- name: Display user status
|
||||
debug:
|
||||
msg: "[2/7] Utilisateur {{ automation_user }}: {{ 'existant' if 'exists' in user_check.stdout else 'à créer' }}"
|
||||
|
||||
- name: Create automation user (Debian/Ubuntu)
|
||||
raw: useradd -m -s /bin/bash {{ automation_user }} || useradd -m -s /bin/sh {{ automation_user }}
|
||||
when:
|
||||
- "'not_exists' in user_check.stdout"
|
||||
- os_type == "debian"
|
||||
|
||||
- name: Create automation user (Alpine)
|
||||
raw: adduser -D {{ automation_user }}
|
||||
when:
|
||||
- "'not_exists' in user_check.stdout"
|
||||
- os_type == "alpine"
|
||||
|
||||
- name: Create automation user (FreeBSD)
|
||||
raw: pw useradd {{ automation_user }} -m -s /bin/sh
|
||||
when:
|
||||
- "'not_exists' in user_check.stdout"
|
||||
- os_type == "freebsd"
|
||||
|
||||
- name: Display user creation result
|
||||
debug:
|
||||
msg: "[3/7] Utilisateur {{ automation_user }} configuré"
|
||||
|
||||
- name: Unlock user account
|
||||
raw: |
|
||||
if command -v passwd >/dev/null 2>&1; then
|
||||
passwd -u {{ automation_user }} 2>/dev/null || true
|
||||
fi
|
||||
if command -v usermod >/dev/null 2>&1; then
|
||||
usermod -U {{ automation_user }} 2>/dev/null || true
|
||||
fi
|
||||
changed_when: false
|
||||
|
||||
- name: Get home directory
|
||||
raw: "getent passwd {{ automation_user }} | cut -d: -f6 || echo /home/{{ automation_user }}"
|
||||
register: home_dir_raw
|
||||
changed_when: false
|
||||
|
||||
- name: Set home directory fact
|
||||
set_fact:
|
||||
home_dir: "{{ home_dir_raw.stdout | trim }}"
|
||||
|
||||
- name: Create .ssh directory
|
||||
raw: |
|
||||
mkdir -p {{ home_dir }}/.ssh
|
||||
chown {{ automation_user }}:{{ automation_user }} {{ home_dir }}/.ssh
|
||||
chmod 700 {{ home_dir }}/.ssh
|
||||
changed_when: false
|
||||
|
||||
- name: Read local SSH public key
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
slurp:
|
||||
src: "{{ ssh_public_key_path }}"
|
||||
register: ssh_pub_key
|
||||
ignore_errors: true
|
||||
|
||||
- name: Try alternate SSH key paths
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
slurp:
|
||||
src: "{{ item }}"
|
||||
register: ssh_pub_key_alt
|
||||
loop:
|
||||
- "/app/ssh_keys/id_ed25519.pub"
|
||||
- "/app/ssh_keys/id_automation_ansible.pub"
|
||||
- "{{ lookup('env', 'HOME') }}/.ssh/id_rsa.pub"
|
||||
when: ssh_pub_key.failed | default(false)
|
||||
ignore_errors: true
|
||||
|
||||
- name: Set SSH public key content
|
||||
set_fact:
|
||||
ssh_key_content: "{{ (ssh_pub_key.content | b64decode | trim) if not (ssh_pub_key.failed | default(false)) else (ssh_pub_key_alt.results | selectattr('content', 'defined') | map(attribute='content') | first | b64decode | trim) }}"
|
||||
when: not (ssh_pub_key.failed | default(false)) or (ssh_pub_key_alt.results | selectattr('content', 'defined') | list | length > 0)
|
||||
|
||||
- name: Install SSH public key
|
||||
raw: |
|
||||
cat > {{ home_dir }}/.ssh/authorized_keys << 'SSHKEY_EOF'
|
||||
{{ ssh_key_content }}
|
||||
SSHKEY_EOF
|
||||
chown {{ automation_user }}:{{ automation_user }} {{ home_dir }}/.ssh/authorized_keys
|
||||
chmod 600 {{ home_dir }}/.ssh/authorized_keys
|
||||
when: ssh_key_content is defined
|
||||
|
||||
- name: Verify authorized_keys
|
||||
raw: test -s {{ home_dir }}/.ssh/authorized_keys && wc -l < {{ home_dir }}/.ssh/authorized_keys || echo "0"
|
||||
register: auth_keys_count
|
||||
changed_when: false
|
||||
|
||||
- name: Display SSH key status
|
||||
debug:
|
||||
msg: "[4/7] Clé SSH installée ({{ auth_keys_count.stdout | trim }} clé(s))"
|
||||
|
||||
- name: Install sudo (Debian/Ubuntu)
|
||||
raw: |
|
||||
if ! command -v sudo >/dev/null 2>&1; then
|
||||
apt-get update -qq && apt-get install -y sudo
|
||||
fi
|
||||
when: os_type == "debian"
|
||||
|
||||
- name: Install sudo (Alpine)
|
||||
raw: |
|
||||
if ! command -v sudo >/dev/null 2>&1; then
|
||||
apk add --no-cache sudo
|
||||
fi
|
||||
when: os_type == "alpine"
|
||||
|
||||
- name: Install sudo (FreeBSD)
|
||||
raw: |
|
||||
if ! command -v sudo >/dev/null 2>&1; then
|
||||
pkg install -y sudo
|
||||
fi
|
||||
when: os_type == "freebsd"
|
||||
|
||||
- name: Display sudo status
|
||||
debug:
|
||||
msg: "[5/7] sudo installé/vérifié"
|
||||
|
||||
- name: Configure sudoers
|
||||
raw: |
|
||||
mkdir -p /etc/sudoers.d
|
||||
echo "{{ automation_user }} ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/automation
|
||||
chmod 440 /etc/sudoers.d/automation
|
||||
changed_when: false
|
||||
|
||||
- name: Display sudoers status
|
||||
debug:
|
||||
msg: "[6/7] Sudoers configuré: /etc/sudoers.d/automation"
|
||||
|
||||
- name: Install Python3 (Debian/Ubuntu)
|
||||
raw: |
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
apt-get update -qq && apt-get install -y python3
|
||||
fi
|
||||
when: os_type == "debian"
|
||||
|
||||
- name: Install Python3 (Alpine)
|
||||
raw: |
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
apk add --no-cache python3
|
||||
fi
|
||||
when: os_type == "alpine"
|
||||
|
||||
- name: Install Python3 (FreeBSD)
|
||||
raw: |
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
pkg install -y python3
|
||||
fi
|
||||
when: os_type == "freebsd"
|
||||
|
||||
- name: Get Python version
|
||||
raw: python3 --version 2>&1 || echo "N/A"
|
||||
register: python_version
|
||||
changed_when: false
|
||||
|
||||
- name: Display Python status
|
||||
debug:
|
||||
msg: "[7/7] Python3 installé: {{ python_version.stdout | trim }}"
|
||||
|
||||
- name: Display bootstrap summary
|
||||
debug:
|
||||
msg: |
|
||||
═══════════════════════════════════════
|
||||
Bootstrap terminé avec succès!
|
||||
═══════════════════════════════════════
|
||||
Host: {{ inventory_hostname }}
|
||||
OS Type: {{ os_type }} ({{ os_variant }})
|
||||
User: {{ automation_user }}
|
||||
Home: {{ home_dir }}
|
||||
SSH Keys: {{ auth_keys_count.stdout | trim }}
|
||||
Python: {{ python_version.stdout | trim }}
|
||||
═══════════════════════════════════════
|
||||
83
ansible/playbooks/health-check.yml
Normal file
83
ansible/playbooks/health-check.yml
Normal file
@ -0,0 +1,83 @@
|
||||
---
|
||||
- name: Health check on target host
|
||||
hosts: all
|
||||
become: false
|
||||
gather_facts: false
|
||||
vars:
|
||||
category: monitoring
|
||||
subcategory: health
|
||||
tasks:
|
||||
- name: Check if host is reachable (ping)
|
||||
ansible.builtin.ping:
|
||||
register: ping_result
|
||||
|
||||
- name: Gather minimal facts
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- '!all'
|
||||
- '!min'
|
||||
- distribution
|
||||
ignore_errors: true
|
||||
register: facts_result
|
||||
|
||||
- name: Get system uptime
|
||||
ansible.builtin.command: uptime
|
||||
register: uptime_result
|
||||
changed_when: false
|
||||
ignore_errors: true
|
||||
|
||||
- name: Get disk usage
|
||||
ansible.builtin.shell: df -h / | tail -1 | awk '{print $5}'
|
||||
register: disk_usage
|
||||
changed_when: false
|
||||
ignore_errors: true
|
||||
|
||||
- name: Get memory usage (Linux)
|
||||
ansible.builtin.shell: |
|
||||
if command -v free >/dev/null 2>&1; then
|
||||
free -m | grep Mem | awk '{printf "%.1f%%", $3/$2 * 100}'
|
||||
else
|
||||
# Fallback for systems without free command
|
||||
cat /proc/meminfo | awk '/MemTotal/{total=$2} /MemAvailable/{avail=$2} END{printf "%.1f%%", (total-avail)/total*100}'
|
||||
fi
|
||||
register: memory_usage
|
||||
changed_when: false
|
||||
ignore_errors: true
|
||||
|
||||
- name: Get CPU temperature (ARM/SBC)
|
||||
ansible.builtin.shell: |
|
||||
if [ -f /sys/class/thermal/thermal_zone0/temp ]; then
|
||||
temp=$(cat /sys/class/thermal/thermal_zone0/temp)
|
||||
# Use awk instead of bc for better compatibility
|
||||
echo "${temp}" | awk '{printf "%.1f°C", $1/1000}'
|
||||
else
|
||||
echo "N/A"
|
||||
fi
|
||||
register: cpu_temp
|
||||
changed_when: false
|
||||
ignore_errors: true
|
||||
|
||||
- name: Get CPU load
|
||||
ansible.builtin.shell: |
|
||||
if [ -f /proc/loadavg ]; then
|
||||
cat /proc/loadavg | awk '{print $1}'
|
||||
else
|
||||
uptime | awk -F'load average:' '{print $2}' | awk -F',' '{print $1}' | tr -d ' '
|
||||
fi
|
||||
register: cpu_load
|
||||
changed_when: false
|
||||
ignore_errors: true
|
||||
|
||||
- name: Display health status
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
═══════════════════════════════════════
|
||||
Host: {{ inventory_hostname }}
|
||||
Status: {{ 'OK' if ping_result is success else 'UNREACHABLE' }}
|
||||
═══════════════════════════════════════
|
||||
Uptime: {{ uptime_result.stdout | default('N/A') }}
|
||||
Disk Usage: {{ disk_usage.stdout | default('N/A') }}
|
||||
Memory Usage: {{ memory_usage.stdout | default('N/A') }}
|
||||
CPU Load: {{ cpu_load.stdout | default('N/A') }}
|
||||
CPU Temp: {{ cpu_temp.stdout | default('N/A') }}
|
||||
═══════════════════════════════════════
|
||||
15
ansible/playbooks/mon-playbook.yml
Normal file
15
ansible/playbooks/mon-playbook.yml
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
# mon-playbook.yml
|
||||
# Créé le 03/12/2025
|
||||
|
||||
- name: mon playbook
|
||||
hosts: all
|
||||
become: yes
|
||||
vars:
|
||||
category: Test
|
||||
subcategory: other
|
||||
|
||||
tasks:
|
||||
- name: Exemple de tâche
|
||||
ansible.builtin.debug:
|
||||
msg: "Playbook mon-playbook exécuté avec succès!"
|
||||
44
ansible/playbooks/vm-install-jq.yml
Normal file
44
ansible/playbooks/vm-install-jq.yml
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
- name: Install jq on target host
|
||||
hosts: all
|
||||
become: true
|
||||
gather_facts: true
|
||||
vars:
|
||||
category: maintenance
|
||||
subcategory: system
|
||||
tasks:
|
||||
- name: Install jq
|
||||
ansible.builtin.package:
|
||||
name: jq
|
||||
state: present
|
||||
when: ansible_facts['os_family'] == 'Debian'
|
||||
- name: Install jq on RedHat family
|
||||
ansible.builtin.dnf:
|
||||
name: jq
|
||||
state: present
|
||||
when: ansible_facts['os_family'] == 'RedHat'
|
||||
- name: Install jq on Alpine
|
||||
ansible.builtin.apk:
|
||||
name: jq
|
||||
state: present
|
||||
when: ansible_facts['os_family'] == 'Alpine'
|
||||
- name: Install jq on FreeBSD
|
||||
ansible.builtin.pkg:
|
||||
name: jq
|
||||
state: present
|
||||
when: ansible_facts['os_family'] == 'FreeBSD'
|
||||
- name: Install jq on OpenBSD
|
||||
ansible.builtin.pkg_add:
|
||||
name: jq
|
||||
state: present
|
||||
when: ansible_facts['os_family'] == 'OpenBSD'
|
||||
- name: Install jq on macOS
|
||||
ansible.builtin.homebrew:
|
||||
name: jq
|
||||
state: present
|
||||
when: ansible_facts['os_family'] == 'Darwin'
|
||||
- name: Install jq on Windows
|
||||
ansible.builtin.win_chocolatey:
|
||||
name: jq
|
||||
state: present
|
||||
when: ansible_facts['os_family'] == 'Windows'
|
||||
23
ansible/playbooks/vm-reboot.yml
Normal file
23
ansible/playbooks/vm-reboot.yml
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
- name: Reboot target host
|
||||
hosts: all
|
||||
become: true
|
||||
vars:
|
||||
category: maintenance
|
||||
subcategory: system
|
||||
tasks:
|
||||
- name: Detect distribution
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- os_family
|
||||
|
||||
- name: Reboot the machine (Linux)
|
||||
ansible.builtin.reboot:
|
||||
reboot_timeout: 600
|
||||
when: ansible_facts['os_family'] != 'FreeBSD'
|
||||
|
||||
- name: Reboot the machine (FreeBSD)
|
||||
ansible.builtin.reboot:
|
||||
reboot_timeout: 600
|
||||
boot_time_command: sysctl kern.boottime
|
||||
when: ansible_facts['os_family'] == 'FreeBSD'
|
||||
34
ansible/playbooks/vm-upgrade.yml
Normal file
34
ansible/playbooks/vm-upgrade.yml
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
- name: Upgrade packages on target host
|
||||
hosts: all
|
||||
become: true
|
||||
vars:
|
||||
category: maintenance
|
||||
subcategory: system
|
||||
tasks:
|
||||
- name: Detect distribution
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- os_family
|
||||
|
||||
- name: Upgrade on Debian/Ubuntu
|
||||
ansible.builtin.apt:
|
||||
update_cache: yes
|
||||
upgrade: dist
|
||||
when: ansible_facts['os_family'] == 'Debian'
|
||||
|
||||
- name: Upgrade on Alpine
|
||||
ansible.builtin.shell: |
|
||||
apk update && apk upgrade
|
||||
when: ansible_facts['os_family'] == 'Alpine'
|
||||
|
||||
- name: Upgrade on RedHat family
|
||||
ansible.builtin.dnf:
|
||||
name: "*"
|
||||
state: latest
|
||||
when: ansible_facts['os_family'] == 'RedHat'
|
||||
|
||||
- name: Upgrade on FreeBSD
|
||||
ansible.builtin.shell: |
|
||||
pkg update && pkg upgrade -y
|
||||
when: ansible_facts['os_family'] == 'FreeBSD'
|
||||
3843
app/app_optimized.py
Normal file
3843
app/app_optimized.py
Normal file
File diff suppressed because it is too large
Load Diff
2540
app/index.html
Normal file
2540
app/index.html
Normal file
File diff suppressed because it is too large
Load Diff
6412
app/main.js
Normal file
6412
app/main.js
Normal file
File diff suppressed because it is too large
Load Diff
10
app/requirements.txt
Normal file
10
app/requirements.txt
Normal file
@ -0,0 +1,10 @@
|
||||
fastapi>=0.115.0
|
||||
uvicorn[standard]>=0.32.0
|
||||
pydantic>=2.12.0
|
||||
python-multipart>=0.0.9
|
||||
PyYAML>=6.0.2
|
||||
websockets>=14.0
|
||||
aiofiles>=24.1.0
|
||||
python-dotenv>=1.0.1
|
||||
requests>=2.32.0
|
||||
httpx>=0.28.0
|
||||
58
docker-compose.yml
Normal file
58
docker-compose.yml
Normal file
@ -0,0 +1,58 @@
|
||||
---
|
||||
services:
|
||||
homelab-dashboard:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: homelab-automation-dashboard
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8008:8000"
|
||||
environment:
|
||||
# Clé API pour l'authentification
|
||||
- API_KEY=${API_KEY:-dev-key-12345}
|
||||
# Utilisateur SSH pour Ansible
|
||||
- SSH_USER=${SSH_USER:-automation}
|
||||
# Chemin de la clé SSH dans le container
|
||||
- SSH_KEY_PATH=/app/ssh_keys/id_rsa
|
||||
# Désactiver la vérification des clés SSH (pour les tests)
|
||||
- ANSIBLE_HOST_KEY_CHECKING=False
|
||||
# Timeout SSH
|
||||
- ANSIBLE_TIMEOUT=30
|
||||
# Répertoire des logs de tâches (format YYYY/MM/JJ)
|
||||
- DIR_LOGS_TASKS=/app/tasks_logs
|
||||
# Ansible inventory
|
||||
- ANSIBLE_INVENTORY=./ansible/inventory
|
||||
# Ansible playbooks
|
||||
- ANSIBLE_PLAYBOOKS=./ansible/playbooks
|
||||
# Ansible group_vars
|
||||
- ANSIBLE_GROUP_VARS=./ansible/inventory/group_vars
|
||||
volumes:
|
||||
# Monter l'inventaire Ansible (permet de modifier sans rebuild)
|
||||
- ${ANSIBLE_INVENTORY:-./ansible/inventory}:/ansible/inventory
|
||||
# Monter les playbooks (permet de modifier sans rebuild)
|
||||
- ${ANSIBLE_PLAYBOOKS:-./ansible/playbooks}:/ansible/playbooks
|
||||
# Monter les variables de groupe
|
||||
- ${ANSIBLE_GROUP_VARS:-./ansible/inventory/group_vars}:/ansible/inventory/group_vars
|
||||
# Monter les clés SSH depuis le host
|
||||
- ${SSH_KEY_DIR:-~/.ssh}:/app/ssh_keys:ro
|
||||
# Volume pour les logs (optionnel)
|
||||
- homelab_logs:/app/logs
|
||||
# Monter le répertoire des logs de tâches depuis le host
|
||||
- ${DIR_LOGS_TASKS:-./tasks_logs}:/app/tasks_logs
|
||||
networks:
|
||||
- homelab-network
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000/api/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
networks:
|
||||
homelab-network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
homelab_logs:
|
||||
driver: local
|
||||
79
tasks_logs/.bootstrap_status.json
Normal file
79
tasks_logs/.bootstrap_status.json
Normal file
@ -0,0 +1,79 @@
|
||||
{
|
||||
"hosts": {
|
||||
"dev.lab.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T20:20:03.555927+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"media.labb.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T01:52:34.259129+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"ali2v.xeon.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T14:35:47.874004+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"raspi.4gb.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T16:09:22.961007+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"raspi.8gb.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T16:10:53.117121+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"orangepi.pc.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T16:11:47.008381+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"jump.point.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T18:56:57.635706+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"hp.nas.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T20:25:44.595352+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"hp2.i7.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T20:25:51.895846+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"hp3.i5.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T20:25:59.998069+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"mimi.pc.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T20:26:08.419143+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"dev.prod.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T21:02:48.893923+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"automate.prod.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T21:03:44.363353+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"ali2v.truenas.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-02T21:47:48.804941+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
},
|
||||
"hp.truenas.home": {
|
||||
"bootstrap_ok": true,
|
||||
"bootstrap_date": "2025-12-03T00:43:57.196419+00:00",
|
||||
"details": "Bootstrap réussi via API (user: automation)"
|
||||
}
|
||||
}
|
||||
}
|
||||
2
tasks_logs/.gitkeep
Normal file
2
tasks_logs/.gitkeep
Normal file
@ -0,0 +1,2 @@
|
||||
# Ce fichier garde le répertoire tasks_logs dans git
|
||||
# Les logs de tâches (*.md) seront créés ici dans le format YYYY/MM/JJ/
|
||||
Loading…
x
Reference in New Issue
Block a user