WIP many change in logic for simplify

This commit is contained in:
Nicolas Duhamel 2025-06-26 17:54:08 +02:00
parent b0b9712b52
commit de21cbd4d2
7 changed files with 237 additions and 188 deletions

118
README.md
View File

@ -1,118 +0,0 @@
# Citadel Backup System
Système de sauvegarde automatisé basé sur Restic avec intégration systemd pour services containerisés.
## Structure du Projet
```
citadel/
├── backup.env # Configuration centralisée
├── manage # Interface principale de gestion
├── install # Script d'installation et configuration
├── config/
│ └── restic.conf # Configuration Restic (générée)
└── backup/
├── install-service # Installation timers systemd
├── list-snapshots # Liste des snapshots
├── restore # Restauration
├── service-backup@.service # Template service systemd
└── service-backup@.timer # Template timer systemd
```
## Installation
1. **Configuration initiale**
```bash
# Copier et adapter la configuration
cp backup.env.sample backup.env
# Éditer backup.env selon votre environnement
```
2. **Installation complète**
```bash
# Installation automatique (configuration + repository)
./install
# Ou étape par étape
./install config # Génération configuration Restic
./install repo # Initialisation repository
```
3. **Installation d'un service**
```bash
sudo ./manage install <nom_service>
```
## Configuration
### Variables principales (backup.env)
- `BACKUP_USER` : Utilisateur système (défaut: citadel)
- `PROJECT_ROOT` : Racine du projet
- `SERVICES_BASE_DIR` : Répertoire des services à sauvegarder
- `BACKUP_REPOSITORY` : Chemin du repository Restic
- `DEFAULT_BACKUP_SCHEDULE` : Planning par défaut (défaut: *-*-* 03:00:00)
### Personnalisation
```bash
# Exemple pour un autre utilisateur
export BACKUP_USER="myuser"
export BACKUP_HOME="/home/myuser"
source backup.env
# Puis utiliser normalement
./manage list
```
## Utilisation
### Gestion des sauvegardes
```bash
# Lister les timers (configuration auto-sourcée)
./manage list
# Statut d'un service
./manage status paperless
# Lancer une sauvegarde manuelle
./manage run paperless
# Voir les logs
./manage logs paperless
# Services disponibles
./manage available
```
### Restauration
```bash
# Lister les snapshots
./manage snapshots paperless
# Restaurer en mode test
./manage restore paperless
# Restaurer en production
./manage restore-prod paperless
```
## Architecture
### Principes de conception
- **Interface unifiée** : Toutes les opérations via `./manage` et `./install`
- **Configuration auto-sourcée** : Plus besoin de sourcer manuellement
- **Scripts protégés** : Scripts dans `backup/` non exécutables directement
- **Sécurité** : Mots de passe générés automatiquement, permissions restreintes
### Composants
- **`./manage`** : Interface principale pour toutes les opérations de sauvegarde
- **`./install`** : Script d'installation consolidé (config + repository)
- **`backup.env`** : Configuration centralisée avec variables d'environnement
- **`backup/`** : Scripts internes appelés via `./manage` uniquement
### Développement
Les scripts dans `backup/` utilisent la variable `CALLED_FROM_MANAGE` pour empêcher l'exécution directe et garantir l'utilisation de l'interface unifiée.

View File

@ -4,36 +4,26 @@
# This template provides standardized configuration for all service scripts # This template provides standardized configuration for all service scripts
# Usage: Source this template at the beginning of service backup/restore scripts # Usage: Source this template at the beginning of service backup/restore scripts
# Auto-configure via backup.env # Auto-configure via backup.env from standard location
# Calculate PROJECT_ROOT based on where template is sourced from CONFIG_DIR="$HOME/.config/citadel"
# Template is in backup/, so from services/service_name/ we need to go ../../ CONFIG_FILE="$CONFIG_DIR/backup.env"
if [[ "${BASH_SOURCE[1]}" == */services/* ]]; then
# Sourced from a service script
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[1]}")/../.." && pwd)"
else
# Sourced from backup/ directory or elsewhere
SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_ROOT/.." && pwd)"
fi
# Source centralized configuration if [ -f "$CONFIG_FILE" ]; then
if [ -f "$PROJECT_ROOT/backup.env" ]; then source "$CONFIG_FILE"
source "$PROJECT_ROOT/backup.env"
else else
echo "ERROR: Configuration file backup.env not found in $PROJECT_ROOT" >&2 echo "ERROR: Configuration not found at $CONFIG_FILE" >&2
echo "Please ensure backup.env exists in project root directory" >&2 echo "Please run './install setup' to initialize configuration" >&2
exit 1 exit 1
fi fi
# Variables universelles pour tout service (auto-dérivées) # Variables universelles pour tout service (auto-dérivées)
# Detect service name from the script that sources this template # Use service name if set explicitly, otherwise detect from calling script
if [[ "${BASH_SOURCE[1]}" == */services/* ]]; then if [ -z "$SERVICE_NAME" ]; then
# BASH_SOURCE[1] is the script that sourced this template
SERVICE_NAME="$(basename "$(dirname "${BASH_SOURCE[1]}")")" SERVICE_NAME="$(basename "$(dirname "${BASH_SOURCE[1]}")")"
else
SERVICE_NAME="$(basename "$(dirname "$0")")"
fi fi
SERVICE_DIR="$SERVICES_BASE_DIR/$SERVICE_NAME" SERVICE_DIR="$SERVICES_BASE_DIR/$SERVICE_NAME"
CONFIG_FILE="$RESTIC_CONFIG_FILE" RESTIC_CONFIG_FILE="$CONFIG_DIR/restic.conf"
LOG_FILE="$LOG_DIR/$SERVICE_NAME-backup.log" LOG_FILE="$LOG_DIR/$SERVICE_NAME-backup.log"
DATA_DIR="${DATA_DIR:-$(dirname "$SERVICES_BASE_DIR")/data/$SERVICE_NAME}" DATA_DIR="${DATA_DIR:-$(dirname "$SERVICES_BASE_DIR")/data/$SERVICE_NAME}"
TEMP_BACKUP_DIR="$TEMP_DIR/$SERVICE_NAME-backup" TEMP_BACKUP_DIR="$TEMP_DIR/$SERVICE_NAME-backup"
@ -96,7 +86,7 @@ cleanup_on_exit() {
# Export commonly used variables # Export commonly used variables
export SERVICE_NAME export SERVICE_NAME
export SERVICE_DIR export SERVICE_DIR
export CONFIG_FILE export RESTIC_CONFIG_FILE
export LOG_FILE export LOG_FILE
export DATA_DIR export DATA_DIR
export TEMP_BACKUP_DIR export TEMP_BACKUP_DIR

View File

@ -1,12 +1,35 @@
#My name is Nicolas # Claude Code Guidance - Citadel Project
This file provides guidance to Claude Code when working with this repository. **Maintainer:** Nicolas
This is a pack of script named citadel for manage a self hosted server, for personnal usage. ## Project Overview
IMPORTANT Keep things simple. Ne rajoute pas de fonctionnalitée non spécifiquement souhaité. Si tu penses qu'une nouvelle fonctionnalitée est fortement souhaitable demande moi avant.
Use shell script.
Ne prévoit pas de script ou documentation de migration sauf si demandé explicitement.
I interact with you in french, you can anwser in french Citadel is a collection of shell scripts for managing a self-hosted server for personal usage. It provides automated backup management using Restic with systemd integration for containerized services.
IMPORTANT all code comment and documentation must be write in english
IMPORTANT do not analyse file mentioned in .gitignore ## Deployment Structure
- **Development:** `/home/nicolas/dev/citadel`
- **Production:** `$HOME/citadel` (default user: "citadel")
- **Configuration:** `$HOME/.config/citadel`
## Development Guidelines
### Core Principles
- **Simplicity first:** Keep solutions minimal and focused
- **No unsolicited features:** Only implement specifically requested functionality
- **Ask before enhancing:** If a feature seems beneficial, ask before implementing
- **Shell scripts only:** Use bash/shell scripting as the primary technology
- **No migration scripts:** Unless explicitly requested
### Code Standards
- **Comments & Documentation:** English only
- **Error handling:** Use consistent patterns across scripts
- **Security:** Follow secure coding practices, especially for password/secret handling
- **Integration:** Prefer using the centralized template system for new services
### File Exclusions
- **Do not analyze:** Files listed in `.gitignore`
## Communication
- **Interaction language:** French (Nicolas preference)
- **Code language:** English (comments, documentation, variable names)

87
install
View File

@ -8,13 +8,15 @@ set -e
# Get the directory where this script is located (project root) # Get the directory where this script is located (project root)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Auto-source configuration # Auto-source configuration from standard location
if [ -f "$SCRIPT_DIR/backup.env" ]; then CONFIG_DIR="$HOME/.config/citadel"
source "$SCRIPT_DIR/backup.env" CONFIG_FILE="$CONFIG_DIR/backup.env"
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE"
else else
echo "ERROR: Configuration file backup.env not found in $SCRIPT_DIR" echo "Configuration not found at $CONFIG_FILE"
echo "Please ensure backup.env exists in project root directory" echo "Will create configuration during setup..."
exit 1
fi fi
show_help() { show_help() {
@ -33,14 +35,34 @@ show_help() {
} }
generate_config() { generate_config() {
local CONFIG_FILE="$RESTIC_CONFIG_FILE" local RESTIC_CONFIG_FILE="$CONFIG_DIR/restic.conf"
local BACKUP_ENV_FILE="$CONFIG_DIR/backup.env"
echo "=== Generating Citadel Configuration ==="
# Create config directory
mkdir -p "$CONFIG_DIR"
# Copy backup.env.sample if backup.env doesn't exist
if [ ! -f "$BACKUP_ENV_FILE" ]; then
if [ -f "$SCRIPT_DIR/backup.env.sample" ]; then
echo "Creating configuration from sample..."
cp "$SCRIPT_DIR/backup.env.sample" "$BACKUP_ENV_FILE"
echo "✅ Configuration created at $BACKUP_ENV_FILE"
echo "Please edit this file to match your environment"
else
echo "ERROR: backup.env.sample not found in $SCRIPT_DIR"
return 1
fi
fi
# Source the configuration to get variables
source "$BACKUP_ENV_FILE"
local REPO_PATH="$BACKUP_REPOSITORY" local REPO_PATH="$BACKUP_REPOSITORY"
echo "=== Generating Restic Configuration ===" # Check if restic config already exists
if [ -f "$RESTIC_CONFIG_FILE" ]; then
# Check if config already exists echo "Restic configuration already exists at $RESTIC_CONFIG_FILE"
if [ -f "$CONFIG_FILE" ]; then
echo "Configuration file already exists at $CONFIG_FILE"
read -p "Do you want to overwrite it? (y/N): " -n 1 -r read -p "Do you want to overwrite it? (y/N): " -n 1 -r
echo echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then if [[ ! $REPLY =~ ^[Yy]$ ]]; then
@ -49,16 +71,13 @@ generate_config() {
fi fi
fi fi
# Ensure config directory exists
mkdir -p "$(dirname "$CONFIG_FILE")"
# Generate secure password (32 characters) # Generate secure password (32 characters)
echo "Generating secure password..." echo "Generating secure password..."
local RESTIC_PASSWORD=$(openssl rand -base64 32) local RESTIC_PASSWORD=$(openssl rand -base64 32)
# Create configuration file # Create restic configuration file
echo "Creating configuration file..." echo "Creating restic configuration file..."
cat > "$CONFIG_FILE" << EOF cat > "$RESTIC_CONFIG_FILE" << EOF
# Restic configuration for citadel backups # Restic configuration for citadel backups
# Generated on $(date) # Generated on $(date)
@ -73,24 +92,34 @@ export RESTIC_CACHE_DIR="$RESTIC_CACHE_DIR"
EOF EOF
# Set secure permissions # Set secure permissions
chmod 600 "$CONFIG_FILE" chmod 600 "$RESTIC_CONFIG_FILE"
echo "✅ Configuration file created at $CONFIG_FILE" echo "✅ Restic configuration file created at $RESTIC_CONFIG_FILE"
echo "🔒 Password generated and saved securely" echo "🔒 Password generated and saved securely"
echo "" echo ""
echo "⚠️ IMPORTANT: Save this password somewhere safe!" echo "⚠️ IMPORTANT: Save this password somewhere safe!"
echo " If you lose it, you won't be able to restore your backups!" echo " If you lose it, you won't be able to restore your backups!"
echo "" echo ""
echo "📁 Password saved in: $CONFIG_FILE" echo "📁 Password saved in: $RESTIC_CONFIG_FILE"
echo " Use 'cat $CONFIG_FILE' to view the password if needed" echo " Use 'cat $RESTIC_CONFIG_FILE' to view the password if needed"
echo "" echo ""
return 0 return 0
} }
initialize_repository() { initialize_repository() {
local RESTIC_CONFIG_FILE="$CONFIG_DIR/restic.conf"
# Source backup.env to get repository path
if [ -f "$CONFIG_DIR/backup.env" ]; then
source "$CONFIG_DIR/backup.env"
else
echo "Error: backup.env not found at $CONFIG_DIR/backup.env"
echo "Please run '$0 config' first to create the configuration."
return 1
fi
local REPO_PATH="$BACKUP_REPOSITORY" local REPO_PATH="$BACKUP_REPOSITORY"
local CONFIG_FILE="$RESTIC_CONFIG_FILE"
echo "=== Initializing Restic Repository ===" echo "=== Initializing Restic Repository ==="
@ -101,15 +130,15 @@ initialize_repository() {
sudo chown $(whoami):$(whoami) "$(dirname "$REPO_PATH")" sudo chown $(whoami):$(whoami) "$(dirname "$REPO_PATH")"
fi fi
# Check if config file exists # Check if restic config file exists
if [ ! -f "$CONFIG_FILE" ]; then if [ ! -f "$RESTIC_CONFIG_FILE" ]; then
echo "Error: Configuration file $CONFIG_FILE not found!" echo "Error: Restic configuration file $RESTIC_CONFIG_FILE not found!"
echo "Please run '$0 config' first to create the configuration." echo "Please run '$0 config' first to create the configuration."
return 1 return 1
fi fi
# Source the configuration # Source the restic configuration
source "$CONFIG_FILE" source "$RESTIC_CONFIG_FILE"
# Check if repository is already initialized # Check if repository is already initialized
if restic -r "$REPO_PATH" cat config &>/dev/null; then if restic -r "$REPO_PATH" cat config &>/dev/null; then
@ -125,7 +154,7 @@ initialize_repository() {
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo "✅ Repository successfully initialized!" echo "✅ Repository successfully initialized!"
echo "Repository path: $REPO_PATH" echo "Repository path: $REPO_PATH"
echo "Configuration: $CONFIG_FILE" echo "Configuration: $RESTIC_CONFIG_FILE"
echo "" echo ""
echo "=== Repository Information ===" echo "=== Repository Information ==="
restic -r "$REPO_PATH" stats restic -r "$REPO_PATH" stats

13
manage
View File

@ -8,12 +8,15 @@ set -e
# Get the directory where this script is located (project root) # Get the directory where this script is located (project root)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Auto-source configuration # Auto-source configuration from standard location
if [ -f "$SCRIPT_DIR/backup.env" ]; then CONFIG_DIR="$HOME/.config/citadel"
source "$SCRIPT_DIR/backup.env" CONFIG_FILE="$CONFIG_DIR/backup.env"
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE"
else else
echo "ERROR: Configuration file backup.env not found in $SCRIPT_DIR" echo "ERROR: Configuration not found at $CONFIG_FILE"
echo "Please ensure backup.env exists in project root directory" echo "Please run './install setup' to initialize configuration"
exit 1 exit 1
fi fi

View File

@ -6,7 +6,12 @@
set -e set -e
# Load template configuration # Load template configuration
source "$(dirname "$(dirname "$(dirname "$0")")")/backup/service-script-template.sh" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Set service name explicitly for template
export SERVICE_NAME="paperless"
source "$PROJECT_ROOT/backup/service-script-template.sh"
# Setup logging and cleanup # Setup logging and cleanup
setup_logging setup_logging
@ -17,14 +22,14 @@ COMPOSE_FILE="$SERVICE_DIR/docker-compose.yml"
log "=== Starting $SERVICE_NAME Backup ===" log "=== Starting $SERVICE_NAME Backup ==="
# Check if configuration exists # Check if restic configuration exists
if [ ! -f "$CONFIG_FILE" ]; then if [ ! -f "$RESTIC_CONFIG_FILE" ]; then
error "Configuration file $CONFIG_FILE not found!" error "Restic configuration file $RESTIC_CONFIG_FILE not found!"
exit 1 exit 1
fi fi
# Source Restic configuration # Source Restic configuration
source "$CONFIG_FILE" source "$RESTIC_CONFIG_FILE"
# Create temporary backup directory # Create temporary backup directory
log "Creating temporary backup directory: $TEMP_BACKUP_DIR" log "Creating temporary backup directory: $TEMP_BACKUP_DIR"

117
todo.md Normal file
View File

@ -0,0 +1,117 @@
# Plan de Migration vers $HOME/.config/citadel
## Objectif
Migrer la configuration du projet vers `$HOME/.config/citadel` pour respecter les standards de configuration système et séparer clairement le code de la configuration en production.
## Architecture Cible
### Structure de configuration
```
$HOME/.config/citadel/
├── backup.env # Configuration principale (était à la racine)
├── restic.conf # Configuration Restic générée (était dans config/)
└── services/ # Configurations spécifiques par service (futures extensions)
```
### Fichiers sample conservés dans le projet
```
backup.env.sample # Guide d'installation (reste à la racine)
config/restic.conf # Devient un exemple/template
```
## Plan d'action détaillé
### Phase 1 : Modification du système de sourcing
#### 1.1 Modifier `manage`
- **Fichier** : `manage` (lignes 12-18)
- **Action** : Remplacer le sourcing conditionnel par un chemin fixe
- **Nouveau code** :
```bash
CONFIG_DIR="$HOME/.config/citadel"
CONFIG_FILE="$CONFIG_DIR/backup.env"
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE"
else
echo "ERROR: Configuration not found at $CONFIG_FILE"
echo "Please run './install setup' to initialize configuration"
exit 1
fi
```
#### 1.2 Modifier `install`
- **Fichier** : `install` (lignes 12-18)
- **Action** : Même modification que `manage` + création du répertoire config
- **Ajout** : Fonction de création/migration de la configuration
- **Nouveau comportement** :
- Créer `$HOME/.config/citadel/` si inexistant
- Copier `backup.env.sample` vers `$HOME/.config/citadel/backup.env` si absent
- Générer `restic.conf` dans le nouveau répertoire
#### 1.3 Modifier `service-script-template.sh`
- **Fichier** : `backup/service-script-template.sh` (lignes 8-26)
- **Action** : Supprimer la détection automatique de PROJECT_ROOT
- **Nouveau code** :
```bash
CONFIG_DIR="$HOME/.config/citadel"
CONFIG_FILE="$CONFIG_DIR/backup.env"
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE"
else
echo "ERROR: Configuration not found at $CONFIG_FILE" >&2
exit 1
fi
```
### Phase 2 : Adaptation des variables de configuration
#### 2.1 Modifier `backup.env.sample`
- **Action** : Mettre à jour les chemins par défaut
- **Variables à modifier** :
```bash
# Nouveau chemin de configuration
RESTIC_CONFIG_FILE="${RESTIC_CONFIG_FILE:-$HOME/.config/citadel/restic.conf}"
# PROJECT_ROOT devient optionnel (pour les templates systemd seulement)
PROJECT_ROOT="${PROJECT_ROOT:-/home/nicolas/dev/citadel}"
```
#### 2.2 Modifier la génération de `restic.conf`
- **Fichier** : `install` (fonction `generate_config`)
- **Action** : Générer le fichier dans `$HOME/.config/citadel/restic.conf`
- **Chemin cible** : `$CONFIG_DIR/restic.conf`
### Phase 3 : Tests et validation
#### 3.1 Tests de non-régression
- `./manage list` fonctionne
- `./manage install <service>` fonctionne
- Scripts de backup sourcent correctement la configuration
- Installation initiale crée la structure correcte
### Phase 4 : Documentation
#### 4.1 Mettre à jour README.md
- Documenter le nouveau chemin de configuration
- Ajouter la procédure de setup initial
#### 4.2 Messages d'erreur informatifs
- Guider l'utilisateur vers la bonne commande d'installation
- Indiquer clairement les chemins de configuration
## Avantages de cette migration
1. **Standard système** : Respect de la convention `$HOME/.config/`
2. **Séparation claire** : Code et configuration indépendants
3. **Sécurité** : Configuration hors du répertoire de développement
4. **Simplicité** : Plus de détection automatique hasardeuse
5. **Maintenance** : Configuration centralisée et prévisible
## Risques identifiés et mitigations
- **Risque** : Scripts cassés après migration
- **Mitigation** : Tests de non-régression complets
- **Risque** : Confusion utilisateur
- **Mitigation** : Messages d'erreur explicites et documentation claire