Remove Docker configuration and implementation documentation files, keeping only core application code and essential documentation
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# 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
|
||||
|
||||
# ===== NOTIFICATIONS NTFY =====
|
||||
# URL de base du serveur ntfy (self-hosted ou ntfy.sh)
|
||||
NTFY_BASE_URL=http://raspi.8gb.home:8150
|
||||
|
||||
# Topic par défaut pour les notifications générales
|
||||
NTFY_DEFAULT_TOPIC=homelab-events
|
||||
|
||||
# Activer/désactiver les notifications (true/false)
|
||||
NTFY_ENABLED=true
|
||||
|
||||
# Timeout pour les requêtes HTTP vers ntfy (en secondes)
|
||||
NTFY_TIMEOUT=5
|
||||
|
||||
# Types de notifications à envoyer :
|
||||
# - ALL : toutes les notifications (succès, warnings, erreurs)
|
||||
# - ERR : uniquement les erreurs
|
||||
# - WARN : uniquement les warnings (par ex. hôtes DOWN)
|
||||
# - ERR,WARN : erreurs + warnings, mais pas les succès
|
||||
NTFY_MSG_TYPE=ALL
|
||||
|
||||
# Authentification optionnelle (laisser vide si pas d'auth)
|
||||
# NTFY_USERNAME=
|
||||
# NTFY_PASSWORD=
|
||||
# Ou utiliser un token Bearer
|
||||
# NTFY_TOKEN=
|
||||
@@ -0,0 +1,60 @@
|
||||
# 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 /app/data
|
||||
|
||||
# Configuration Ansible pour utiliser le bon répertoire
|
||||
ENV ANSIBLE_CONFIG=/ansible/ansible.cfg
|
||||
|
||||
# Variables par défaut pour la base SQLite dans le conteneur
|
||||
ENV HOMELAB_DATA_DIR=/app/data
|
||||
ENV DB_PATH=/app/data/homelab.db
|
||||
ENV DATABASE_URL=sqlite+aiosqlite:////app/data/homelab.db
|
||||
|
||||
# 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"]
|
||||
@@ -0,0 +1,81 @@
|
||||
# Docker Configuration for Homelab Automation
|
||||
|
||||
Ce dossier contient tous les fichiers nécessaires pour conteneuriser et déployer l'application Homelab Automation API.
|
||||
|
||||
## Structure du dossier
|
||||
|
||||
- **Dockerfile** : Définition de l'image Docker.
|
||||
- **docker-compose.yml** : Définition de la stack (Container API + Volumes).
|
||||
- **.env.example** : Modèle de configuration des variables d'environnement.
|
||||
- **init.sh** : Script d'initialisation de l'environnement local.
|
||||
- **build-img.ps1** : Script PowerShell pour construire l'image (optimisé pour WSL).
|
||||
- **deploy-img.sh / .ps1** : Scripts pour pousser l'image vers un registre Docker privé.
|
||||
- **maj.sh** : Script pour mettre à jour la stack depuis le registre.
|
||||
|
||||
## Prérequis
|
||||
|
||||
- Docker Engine & Docker Compose
|
||||
- Pour Windows : WSL 2 activé (recommandé pour les scripts .ps1)
|
||||
|
||||
## Installation et Démarrage
|
||||
|
||||
### 1. Initialisation
|
||||
|
||||
Lancez le script d'initialisation pour préparer le fichier `.env` et les répertoires de données :
|
||||
|
||||
```bash
|
||||
# Dans le dossier docker/
|
||||
bash init.sh
|
||||
```
|
||||
|
||||
Ensuite, éditez le fichier `.env` généré pour configurer :
|
||||
- `API_KEY` : Votre clé secrète.
|
||||
- `SSH_USER` : L'utilisateur pour les connexions Ansible.
|
||||
- `NTFY_*` : La configuration des notifications (optionnel).
|
||||
|
||||
### 2. Démarrage (Local)
|
||||
|
||||
Pour lancer l'application localement avec Docker Compose :
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
L'API sera accessible sur `http://localhost:8008`.
|
||||
|
||||
## Construction et Déploiement (Avancé)
|
||||
|
||||
Si vous utilisez un registre Docker privé (ex: Nexus, Harbor, Registry local), vous pouvez utiliser les scripts de build et de déploiement.
|
||||
|
||||
### Configuration du Registre
|
||||
|
||||
Modifiez les variables dans `.env` (ou laissez les valeurs par défaut si elles conviennent) :
|
||||
- `REGISTRY_HOST`
|
||||
- `REGISTRY_PORT`
|
||||
- `IMAGE_NAME`
|
||||
|
||||
### Construction
|
||||
|
||||
Sous Windows (via PowerShell) :
|
||||
```powershell
|
||||
.\build-img.ps1
|
||||
```
|
||||
|
||||
Sous Linux :
|
||||
```bash
|
||||
docker build -f Dockerfile -t homelab-automation-api:latest ..
|
||||
```
|
||||
|
||||
### Déploiement
|
||||
|
||||
Pousse l'image vers le registre configuré :
|
||||
```powershell
|
||||
.\deploy-img.ps1
|
||||
```
|
||||
|
||||
### Mise à jour
|
||||
|
||||
Sur le serveur de destination, pour tirer la dernière image et redémarrer :
|
||||
```bash
|
||||
./maj.sh
|
||||
```
|
||||
@@ -0,0 +1,119 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Construit l'image Docker avec toutes les dépendances requises via PowerShell et WSL (Debian).
|
||||
.DESCRIPTION
|
||||
Ce script prépare les dépendances et construit l'image Docker sous WSL (Debian) avec BuildKit activé pour des builds plus rapides.
|
||||
.PARAMETRES
|
||||
-full : Si présent, effectue une construction complète de l'image Docker (équivalent à --no-cache).
|
||||
.EXEMPLE
|
||||
.\build-img.ps1 # Construction rapide (avec cache)
|
||||
.\build-img.ps1 -full # Construction complète sans cache
|
||||
.RETOURNE
|
||||
Affiche le succès ou les erreurs pendant la construction de l'image Docker.
|
||||
#>
|
||||
|
||||
param(
|
||||
[switch]$full
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
try {
|
||||
# Determine paths
|
||||
$scriptDir = $PSScriptRoot
|
||||
$projectRoot = (Get-Item (Join-Path $scriptDir '..')).FullName
|
||||
|
||||
# Convert Windows path to WSL path (manual, no wslpath)
|
||||
$wslProjectRoot = $projectRoot -replace '^([A-Za-z]):\\','/mnt/$1/' -replace '\\','/'
|
||||
$wslProjectRoot = $wslProjectRoot.ToLower()
|
||||
|
||||
# Check if Docker is available in WSL Debian
|
||||
Write-Host "Vérification de Docker dans WSL Debian..." -ForegroundColor Cyan
|
||||
$dockerCheck = wsl -d Debian bash -c "docker --version" 2>&1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "Docker n'est pas disponible dans WSL Debian : $dockerCheck"
|
||||
exit 1
|
||||
}
|
||||
Write-Host "Docker détecté : $dockerCheck" -ForegroundColor Green
|
||||
|
||||
# Check if the Dockerfile exists
|
||||
$dockerfilePath = Join-Path $scriptDir "Dockerfile"
|
||||
if (-not (Test-Path $dockerfilePath)) {
|
||||
Write-Error "Le fichier Dockerfile n'existe pas dans $scriptDir"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if .dockerignore exists, warn if not
|
||||
$dockerignorePath = Join-Path $projectRoot ".dockerignore"
|
||||
if (-not (Test-Path $dockerignorePath)) {
|
||||
Write-Warning "Aucun fichier .dockerignore trouvé. Créez-en un pour optimiser le build."
|
||||
Write-Host "Exemple de contenu :" -ForegroundColor Yellow
|
||||
Write-Host @"
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.git
|
||||
.vscode
|
||||
*.log
|
||||
.env
|
||||
"@ -ForegroundColor DarkGray
|
||||
}
|
||||
|
||||
# Compose build command with BuildKit enabled
|
||||
$noCache = if ($full) { '--no-cache' } else { '' }
|
||||
|
||||
# Escape spaces in path for bash
|
||||
$escapedPath = $wslProjectRoot -replace ' ','\\ '
|
||||
|
||||
# Build command parts
|
||||
$cdCmd = "cd `"$wslProjectRoot`""
|
||||
$dockerCmd = "docker build $noCache --progress=plain -t homelab-automation-api:latest -f docker/Dockerfile ."
|
||||
|
||||
# Complete command with BuildKit
|
||||
$innerCmd = "export DOCKER_BUILDKIT=1 && $cdCmd && $dockerCmd"
|
||||
|
||||
# Run build inside WSL Debian to use Linux Docker daemon
|
||||
Write-Host "Construction de l'image Docker homelab-automation-api:latest..." -ForegroundColor Cyan
|
||||
Write-Host "BuildKit activé pour un build optimisé avec cache" -ForegroundColor Cyan
|
||||
|
||||
$buildResult = wsl -d Debian bash -lc $innerCmd 2>&1
|
||||
|
||||
# Display build output
|
||||
$buildResult | ForEach-Object { Write-Host $_ }
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "Erreur lors de la construction de l'image Docker (code: $LASTEXITCODE)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Verify the image was built successfully
|
||||
$verifyCmd = "docker image inspect homelab-automation-api:latest --format='{{.Size}}'"
|
||||
Write-Host "`nVérification de l'image construite..." -ForegroundColor Cyan
|
||||
$imageSize = wsl -d Debian bash -lc $verifyCmd 2>&1
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "L'image Docker n'a pas été construite correctement : $imageSize"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Convert size to MB
|
||||
$sizeMB = [math]::Round([long]$imageSize / 1MB, 2)
|
||||
|
||||
Write-Host "`n================================================" -ForegroundColor Green
|
||||
Write-Host "✓ Image Docker construite avec succès" -ForegroundColor Green
|
||||
Write-Host " Nom: homelab-automation-api:latest" -ForegroundColor Green
|
||||
Write-Host " Taille: $sizeMB MB" -ForegroundColor Green
|
||||
Write-Host "================================================" -ForegroundColor Green
|
||||
|
||||
# Display tips for faster rebuilds
|
||||
if (-not $full) {
|
||||
Write-Host "`nConseils pour les prochains builds :" -ForegroundColor Cyan
|
||||
Write-Host " • Les dépendances Python sont mises en cache" -ForegroundColor Gray
|
||||
Write-Host " • Seuls les fichiers modifiés déclencheront un rebuild" -ForegroundColor Gray
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error "Erreur lors de la construction de l'image Docker : $_"
|
||||
exit 1
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Exécute le script deploy-img.sh dans WSL Debian.
|
||||
.DESCRIPTION
|
||||
Ce script PowerShell lance le script Bash deploy-img.sh dans le répertoire courant sous la distribution WSL Debian.
|
||||
Le script déploie l'image Docker locale vers le registre distant et gère les versions.
|
||||
.PARAMETRES
|
||||
Aucun paramètre requis actuellement.
|
||||
.EXEMPLE
|
||||
.\deploy-img.ps1
|
||||
.RETOURNE
|
||||
Affiche le succès ou les erreurs lors du déploiement de l'image Docker.
|
||||
#>
|
||||
|
||||
param()
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
try {
|
||||
Write-Verbose "[Étape 1] Détermination du répertoire du script."
|
||||
$scriptDir = $PSScriptRoot
|
||||
|
||||
Write-Verbose "[Étape 2] Conversion du chemin Windows vers WSL (manuel, sans wslpath)."
|
||||
# Remplacement manuel du préfixe du chemin Windows par le préfixe WSL
|
||||
$wslScriptDir = $scriptDir -replace '^([A-Za-z]):\\', '/mnt/$1/' -replace '\\','/'
|
||||
$wslScriptDir = $wslScriptDir.ToLower()
|
||||
|
||||
Write-Verbose "[Étape 3] Vérification des permissions du script bash."
|
||||
wsl -d Debian -- chmod +x "$wslScriptDir/deploy-img.sh"
|
||||
|
||||
Write-Verbose "[Étape 4] Construction de la commande Bash à exécuter."
|
||||
$innerCmd = "cd '$wslScriptDir' && ./deploy-img.sh"
|
||||
|
||||
Write-Verbose "[Étape 5] Exécution du script deploy-img.sh dans WSL Debian."
|
||||
wsl -d Debian bash -lc $innerCmd
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Le script de déploiement a échoué avec le code d'erreur: $LASTEXITCODE"
|
||||
}
|
||||
|
||||
Write-Host "Déploiement de l'image Docker homelab-automation-api:latest terminé avec succès." -ForegroundColor Green
|
||||
}
|
||||
catch {
|
||||
Write-Error "Erreur lors de l'exécution du déploiement de l'image Docker : $_"
|
||||
exit 1
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
#!/usr/bin/env bash
|
||||
# Script: deploy-img.sh
|
||||
# Description: Pousse l'image Docker locale vers un registre HTTP (insecure), gère le versioning semver et la rétention
|
||||
# Date: 2025-04-18
|
||||
# Mise à jour: 2025-09-19 - Vérification stricte du daemon (insecure-registries), compatibilité Windows/Linux
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
#####################################
|
||||
# CONFIG UTILISATEUR #
|
||||
#####################################
|
||||
|
||||
# Charger les variables depuis .env s'il existe
|
||||
if [[ -f ".env" ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source .env
|
||||
fi
|
||||
|
||||
IMAGE_NAME="${IMAGE_NAME:-homelab-automation-api}"
|
||||
REGISTRY_HOST="${REGISTRY_HOST:-docker-registry.dev.home}"
|
||||
REGISTRY_PORT="${REGISTRY_PORT:-5000}"
|
||||
MAX_VERSIONS="${MAX_VERSIONS:-5}" # nombre de versions (semver) à conserver
|
||||
LOCAL_TAG="${LOCAL_TAG:-latest}" # tag local source
|
||||
PUSH_LATEST="${PUSH_LATEST:-yes}" # yes/no : pousser aussi :latest
|
||||
|
||||
#####################################
|
||||
# DÉDUCTIONS & CONSTANTES #
|
||||
#####################################
|
||||
REGISTRY="${REGISTRY_HOST}:${REGISTRY_PORT}"
|
||||
REMOTE_REPO="${REGISTRY}/${IMAGE_NAME}"
|
||||
LOCAL_IMAGE="${IMAGE_NAME}:${LOCAL_TAG}"
|
||||
TEMP_DIR="/tmp/docker-deploy-$(date +%s)"
|
||||
CURL="curl -fsSL"
|
||||
JQ_BIN="${JQ_BIN:-jq}" # possibilité de surcharger via env
|
||||
|
||||
# Headers pour obtenir le digest (manifest v2)
|
||||
ACCEPT_MANIFEST='application/vnd.docker.distribution.manifest.v2+json'
|
||||
|
||||
#####################################
|
||||
# UTILITAIRES #
|
||||
#####################################
|
||||
info() { echo -e "\033[1;34m[INFO]\033[0m $*"; }
|
||||
warn() { echo -e "\033[1;33m[AVERT]\033[0m $*"; }
|
||||
error() { echo -e "\033[1;31m[ERREUR]\033[0m $*" >&2; }
|
||||
success() { echo -e "\033[1;32m[SUCCÈS]\033[0m $*"; }
|
||||
|
||||
cleanup() {
|
||||
set +e
|
||||
[[ -d "$TEMP_DIR" ]] && rm -rf "$TEMP_DIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
is_windows_shell() {
|
||||
# Git Bash / MSYS / CYGWIN ou variable OS=Windows_NT
|
||||
if [[ "${OS:-}" == "Windows_NT" ]] || uname -s | grep -qiE 'mingw|msys|cygwin'; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
require_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || { error "Commande requise manquante: $1"; exit 1; }
|
||||
}
|
||||
|
||||
#####################################
|
||||
# PRÉ-VÉRIFICATIONS #
|
||||
#####################################
|
||||
require_cmd docker
|
||||
require_cmd curl
|
||||
require_cmd sed
|
||||
require_cmd grep
|
||||
require_cmd awk
|
||||
require_cmd sort
|
||||
|
||||
# Vérifier l'image locale
|
||||
info "Vérification de l'image locale '${LOCAL_IMAGE}'…"
|
||||
if ! docker image inspect "${LOCAL_IMAGE}" >/dev/null 2>&1; then
|
||||
error "L'image locale ${LOCAL_IMAGE} n'existe pas. Construis-la d'abord (docker build …)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Vérifier config daemon: insecure-registries
|
||||
info "Vérification de la config du daemon Docker (insecure-registries)…"
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
error "Impossible de contacter le daemon Docker. Est-il démarré ?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! docker info 2>/dev/null \
|
||||
| tr -d '\r' \
|
||||
| awk '/Insecure Registries:/,/^$/ {print}' \
|
||||
| grep -q -E "(^|[[:space:]])${REGISTRY_HOST}:${REGISTRY_PORT}([[:space:]]|$)"; then
|
||||
error "Le daemon Docker n'a PAS '${REGISTRY}' dans insecure-registries."
|
||||
if is_windows_shell; then
|
||||
info "Sous Windows (Docker Desktop) : Settings → Docker Engine, ajoute dans le JSON :"
|
||||
printf '%s\n' ' "insecure-registries": ["'"${REGISTRY}"'"]'
|
||||
info "Puis clique 'Apply & Restart' et relance ce script."
|
||||
else
|
||||
info "Sous Linux : édite /etc/docker/daemon.json et ajoute par ex. :"
|
||||
printf '%s\n' '{ "insecure-registries": ["'"${REGISTRY}"'"] }'
|
||||
info "Puis : sudo systemctl restart docker"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ping HTTP direct du registre (API v2)
|
||||
info "Vérification HTTP directe du registre (http://${REGISTRY}/v2/)…"
|
||||
if ! ${CURL} "http://${REGISTRY}/v2/" >/dev/null 2>&1; then
|
||||
error "Impossible de joindre http://${REGISTRY}/v2/. Le registre écoute-t-il bien en HTTP sur :${REGISTRY_PORT} ?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Auth facultative via env (DOCKER_USERNAME / DOCKER_PASSWORD)
|
||||
if [[ -n "${DOCKER_USERNAME:-}" && -n "${DOCKER_PASSWORD:-}" ]]; then
|
||||
info "Authentification au registre (docker login)…"
|
||||
# NB: docker login respecte le mode HTTP si daemon configuré en insecure-registries
|
||||
echo "${DOCKER_PASSWORD}" | docker login "${REGISTRY}" --username "${DOCKER_USERNAME}" --password-stdin >/dev/null
|
||||
else
|
||||
info "Aucun identifiant Docker fourni (DOCKER_USERNAME/DOCKER_PASSWORD). Tentative sans authentification."
|
||||
fi
|
||||
|
||||
mkdir -p "${TEMP_DIR}"
|
||||
|
||||
#####################################
|
||||
# RÉCUPÉRATION DES TAGS #
|
||||
#####################################
|
||||
get_all_tags() {
|
||||
# Renvoie la liste des tags (un par ligne) ou rien si vide/erreur
|
||||
# Utilise jq si dispo, sinon un parseur simple.
|
||||
local tags_json
|
||||
if ! tags_json="$(${CURL} "http://${REGISTRY}/v2/${IMAGE_NAME}/tags/list" 2>/dev/null)"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command -v "${JQ_BIN}" >/dev/null 2>&1; then
|
||||
echo "${tags_json}" | ${JQ_BIN} -r '.tags[]?' 2>/dev/null || true
|
||||
else
|
||||
# fallback très simple (non robuste à tous les cas, mais suffisant ici)
|
||||
echo "${tags_json}" \
|
||||
| tr -d '\n' \
|
||||
| sed -n 's/.*"tags":[[]\([^]]*\)[]].*/\1/p' \
|
||||
| tr -d '"' \
|
||||
| tr ',' '\n' \
|
||||
| sed 's/^[[:space:]]*//; s/[[:space:]]*$//'
|
||||
fi
|
||||
}
|
||||
|
||||
filter_semver() {
|
||||
# Garde uniquement X.Y.Z (numériques)
|
||||
grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' || true
|
||||
}
|
||||
|
||||
increment_patch() {
|
||||
# Lit un tag semver X.Y.Z et augmente Z
|
||||
local tag="$1"
|
||||
local major minor patch
|
||||
IFS='.' read -r major minor patch <<< "${tag}"
|
||||
echo "${major}.${minor}.$((patch+1))"
|
||||
}
|
||||
|
||||
info "Récupération des tags existants…"
|
||||
ALL_TAGS="$(get_all_tags || true)"
|
||||
SEMVER_TAGS="$(printf '%s\n' "${ALL_TAGS}" | filter_semver | sort -V || true)"
|
||||
|
||||
if [[ -z "${SEMVER_TAGS}" ]]; then
|
||||
NEW_TAG="1.0.0"
|
||||
else
|
||||
LATEST_TAG="$(printf '%s\n' "${SEMVER_TAGS}" | tail -n1)"
|
||||
NEW_TAG="$(increment_patch "${LATEST_TAG}")"
|
||||
fi
|
||||
info "Tag retenu pour cette release : ${NEW_TAG}"
|
||||
|
||||
#####################################
|
||||
# TAG + PUSH (HTTP via daemon)
|
||||
#####################################
|
||||
info "Taggage local → ${REMOTE_REPO}:${NEW_TAG}"
|
||||
docker tag "${LOCAL_IMAGE}" "${REMOTE_REPO}:${NEW_TAG}"
|
||||
|
||||
if [[ "${PUSH_LATEST}" == "yes" ]]; then
|
||||
info "Taggage local → ${REMOTE_REPO}:latest"
|
||||
docker tag "${LOCAL_IMAGE}" "${REMOTE_REPO}:latest"
|
||||
fi
|
||||
|
||||
info "Push de ${REMOTE_REPO}:${NEW_TAG} (HTTP via insecure-registries)…"
|
||||
docker push --disable-content-trust "${REMOTE_REPO}:${NEW_TAG}"
|
||||
|
||||
if [[ "${PUSH_LATEST}" == "yes" ]]; then
|
||||
info "Push de ${REMOTE_REPO}:latest…"
|
||||
docker push --disable-content-trust "${REMOTE_REPO}:latest"
|
||||
fi
|
||||
|
||||
#####################################
|
||||
# RÉTENTION: SUPPRIMER ANCIENS #
|
||||
#####################################
|
||||
delete_by_tag() {
|
||||
# Supprime un manifest par son tag en récupérant le digest via HEAD
|
||||
local tag="$1"
|
||||
local digest
|
||||
# On demande le digest via HEAD + Accept manifest v2
|
||||
digest="$(curl -fsSI -H "Accept: ${ACCEPT_MANIFEST}" "http://${REGISTRY}/v2/${IMAGE_NAME}/manifests/${tag}" \
|
||||
| tr -d '\r' \
|
||||
| awk -F': ' 'tolower($1)=="docker-content-digest"{print $2}' \
|
||||
| tail -n1)"
|
||||
if [[ -z "${digest}" ]]; then
|
||||
warn "Digest introuvable pour ${tag} (manifest v2 absent ?). Skip."
|
||||
return 0
|
||||
fi
|
||||
|
||||
info "Suppression manifest ${tag} (digest: ${digest})…"
|
||||
# La delete API ne renvoie rien en cas de succès (204)
|
||||
if ! curl -fsS -X DELETE "http://${REGISTRY}/v2/${IMAGE_NAME}/manifests/${digest}" >/dev/null; then
|
||||
warn "Échec suppression manifest pour ${tag} (digest: ${digest})."
|
||||
fi
|
||||
}
|
||||
|
||||
# Mettre à jour la liste après push
|
||||
ALL_TAGS="$(get_all_tags || true)"
|
||||
SEMVER_TAGS="$(printf '%s\n' "${ALL_TAGS}" | filter_semver | sort -V || true)"
|
||||
|
||||
if [[ -n "${SEMVER_TAGS}" ]]; then
|
||||
COUNT="$(printf '%s\n' "${SEMVER_TAGS}" | wc -l | awk '{print $1}')"
|
||||
if (( COUNT > MAX_VERSIONS )); then
|
||||
TO_DELETE_COUNT=$(( COUNT - MAX_VERSIONS ))
|
||||
# On supprime les plus anciennes
|
||||
OLDEST="$(printf '%s\n' "${SEMVER_TAGS}" | head -n "${TO_DELETE_COUNT}")"
|
||||
while IFS= read -r old_tag; do
|
||||
[[ -z "${old_tag}" ]] && continue
|
||||
# Ne jamais supprimer le tag que l'on vient de pousser (sécurité)
|
||||
if [[ "${old_tag}" == "${NEW_TAG}" ]]; then
|
||||
continue
|
||||
fi
|
||||
delete_by_tag "${old_tag}"
|
||||
done <<< "${OLDEST}"
|
||||
fi
|
||||
fi
|
||||
|
||||
#####################################
|
||||
# NETTOYAGE LOCAL OPTIONNEL #
|
||||
#####################################
|
||||
info "Nettoyage des tags locaux temporaires…"
|
||||
set +e
|
||||
docker rmi "${REMOTE_REPO}:${NEW_TAG}" >/dev/null 2>&1
|
||||
[[ "${PUSH_LATEST}" == "yes" ]] && docker rmi "${REMOTE_REPO}:latest" >/dev/null 2>&1
|
||||
set -e
|
||||
|
||||
success "Déploiement terminé. Version publiée : ${NEW_TAG}"
|
||||
exit 0
|
||||
@@ -0,0 +1,78 @@
|
||||
---
|
||||
services:
|
||||
homelab-dashboard:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile
|
||||
container_name: homelab-automation-dashboard
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8008:8000"
|
||||
environment:
|
||||
# zone horaire
|
||||
- TZ=${TZ:-America/Montreal}
|
||||
# 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
|
||||
# Homelab Data folder (monté sur /app/data)
|
||||
- HOMELAB_DATA_DIR=${HOMELAB_DATA_DIR:-./data}
|
||||
# SQLite DB path et URL (doivent correspondre à app/models/database.py)
|
||||
- DB_PATH=/app/data/homelab.db
|
||||
- DATABASE_URL=sqlite+aiosqlite:////app/data/homelab.db
|
||||
# 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
|
||||
# Notifications ntfy (peuvent aussi être définies dans .env)
|
||||
- NTFY_BASE_URL=${NTFY_BASE_URL:-http://localhost:8150}
|
||||
- NTFY_DEFAULT_TOPIC=${NTFY_DEFAULT_TOPIC:-homelab-events}
|
||||
- NTFY_ENABLED=${NTFY_ENABLED:-true}
|
||||
- NTFY_TIMEOUT=${NTFY_TIMEOUT:-5}
|
||||
- NTFY_USERNAME=${NTFY_USERNAME:-}
|
||||
- NTFY_PASSWORD=${NTFY_PASSWORD:-}
|
||||
- NTFY_TOKEN=${NTFY_TOKEN:-}
|
||||
- NTFY_MSG_TYPE=${NTFY_MSG_TYPE:-ALL}
|
||||
volumes:
|
||||
# Volume Docker natif pour la base de données SQLite (évite les problèmes I/O sur Windows)
|
||||
- homelab_data:/app/data
|
||||
# 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_data:
|
||||
driver: local
|
||||
homelab_logs:
|
||||
driver: local
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
# init.sh - Script d'initialisation de l'environnement pour Homelab Automation
|
||||
# Ce script prépare le fichier .env et les répertoires nécessaires.
|
||||
|
||||
set -e
|
||||
|
||||
# Se placer dans le dossier du script
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
echo "=== Initialisation de l'environnement Docker ==="
|
||||
|
||||
# 1. Configuration du fichier .env
|
||||
if [ ! -f .env ]; then
|
||||
echo "Creation du fichier .env a partir de .env.example..."
|
||||
cp .env.example .env
|
||||
|
||||
# Génération d'une clé API aléatoire
|
||||
API_KEY=$(openssl rand -hex 16 2>/dev/null || echo "change-me-please-123")
|
||||
|
||||
# Remplacement de la clé API par défaut (si sed disponible)
|
||||
if command -v sed >/dev/null 2>&1; then
|
||||
# Compatible Linux/Mac
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -i '' "s/API_KEY=dev-key-12345/API_KEY=${API_KEY}/" .env
|
||||
else
|
||||
sed -i "s/API_KEY=dev-key-12345/API_KEY=${API_KEY}/" .env
|
||||
fi
|
||||
echo "Clé API générée aléatoirement."
|
||||
fi
|
||||
|
||||
echo "--> Fichier .env créé. Pensez à l'éditer pour configurer vos accès SSH et notifications."
|
||||
else
|
||||
echo "--> Le fichier .env existe déjà."
|
||||
fi
|
||||
|
||||
# 2. Création des répertoires de données
|
||||
echo "Vérification des répertoires de données..."
|
||||
mkdir -p ../data
|
||||
mkdir -p ../tasks_logs
|
||||
|
||||
# 3. Vérification des permissions
|
||||
echo "Ajustement des permissions..."
|
||||
chmod +x deploy-img.sh maj.sh init.sh 2>/dev/null || true
|
||||
|
||||
echo "=== Initialisation terminée ==="
|
||||
echo "Pour démarrer l'application :"
|
||||
echo " docker compose up -d --build"
|
||||
echo ""
|
||||
echo "Pour construire l'image :"
|
||||
echo " ./build-img.ps1 (Windows/WSL)"
|
||||
echo " docker build -f Dockerfile -t homelab-automation-api:latest .. (Linux)"
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Always execute relative to this script directory
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Charger les variables depuis .env s'il existe
|
||||
if [[ -f ".env" ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source .env
|
||||
fi
|
||||
|
||||
REGISTRY_HOST="${REGISTRY_HOST:-docker-registry.dev.home}"
|
||||
REGISTRY_PORT="${REGISTRY_PORT:-5000}"
|
||||
IMAGE_NAME="${IMAGE_NAME:-homelab-automation-api}"
|
||||
|
||||
REGISTRY="${REGISTRY_HOST}:${REGISTRY_PORT}"
|
||||
IMAGE="${IMAGE_NAME}:latest"
|
||||
|
||||
# Pull latest image from private registry
|
||||
docker image pull "${REGISTRY}/${IMAGE}"
|
||||
|
||||
# Restart stack with the current compose file
|
||||
docker compose down
|
||||
docker compose up -d
|
||||
|
||||
echo "Homelab Automation API updated and running."
|
||||
Reference in New Issue
Block a user