Refactor: Unify interface with manage and install scripts at root

- Move backup/manage to root with auto-sourcing configuration
- Create consolidated ./install script (replaces gen-conf.sh + init-restic.sh)
- Add protection against direct execution of backup/ scripts
- Update documentation (README.md, CLAUDE.md) for new architecture
- Remove obsolete gen-conf.sh and init-restic.sh

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Nicolas Duhamel 2025-06-23 21:41:09 +02:00
parent f82a913bdd
commit 17414fee4a
9 changed files with 318 additions and 208 deletions

View File

@ -4,19 +4,23 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Critical Convention ## Critical Convention
**ALL scripts must be executed in an environment that has sourced the configuration:** **Use the unified interface scripts that auto-source configuration:**
```bash ```bash
# Always start by sourcing configuration # Installation and setup
source backup.env ./install # Complete setup (config + repository)
./install config # Generate configuration only
./install repo # Initialize repository only
# Then execute any script # All backup operations via manage
./backup/manage list ./manage list # List backup timers
./backup/gen-conf.sh ./manage install <service> # Install service timer
sudo ./backup/install-service paperless ./manage run <service> # Manual backup
./manage restore <service> # Restore (test mode)
./manage restore-prod <service> # Restore (production)
``` ```
This is the core architectural pattern of this codebase. Scripts do NOT auto-source configuration files. **NEVER call scripts in backup/ directly** - they are protected and will error. Always use `./manage` or `./install`.
## Common Commands ## Common Commands
@ -24,31 +28,29 @@ This is the core architectural pattern of this codebase. Scripts do NOT auto-sou
```bash ```bash
cp backup.env.sample backup.env # Copy configuration template cp backup.env.sample backup.env # Copy configuration template
# Edit backup.env to match environment # Edit backup.env to match environment
source backup.env ./install # Complete installation (config + repository)
./backup/gen-conf.sh # Generate secure Restic configuration
./backup/init-restic.sh # Initialize Restic repository
``` ```
### Service Management ### Service Management
```bash ```bash
source backup.env ./manage list # List all backup timers
./backup/manage list # List all backup timers ./manage status <service> # Service backup status
./backup/manage status <service> # Service backup status ./manage run <service> # Manual backup execution
./backup/manage run <service> # Manual backup execution ./manage logs <service> # View backup logs
./backup/manage logs <service> # View backup logs ./manage available # List services with backup.sh
sudo ./backup/install-service <service> # Install systemd timer sudo ./manage install <service> # Install systemd timer
``` ```
### Backup Operations ### Backup Operations
```bash ```bash
source backup.env ./manage snapshots [service] # List available snapshots
./backup/list-snapshots [service] # List available snapshots ./manage restore <service> # Test restoration
./backup/restore <service> --test # Test restoration ./manage restore-prod <service> # Production restoration
./backup/restore <service> --production # Production restoration
``` ```
### Configuration Testing ### Configuration Testing
```bash ```bash
# Source configuration manually for utility functions
source backup.env source backup.env
show_config # Display current configuration show_config # Display current configuration
validate_paths # Check directory existence validate_paths # Check directory existence
@ -62,9 +64,10 @@ validate_paths # Check directory existence
- **Variable substitution**: systemd templates use `${VAR}` placeholders replaced during installation - **Variable substitution**: systemd templates use `${VAR}` placeholders replaced during installation
### Core Components ### Core Components
- **`backup/manage`**: Primary interface for all backup operations and service management - **`./manage`**: Primary interface for all backup operations and service management (auto-sources config)
- **`backup/install-service`**: Systemd timer installer that performs variable substitution in templates - **`./install`**: Installation script consolidating configuration generation and repository initialization
- **`backup/restore`**: Advanced restoration tool with test/production modes and safety checks - **`backup/install-service`**: Systemd timer installer (called via `./manage install`)
- **`backup/restore`**: Advanced restoration tool (called via `./manage restore/restore-prod`)
- **Templates**: `service-backup@.service` and `service-backup@.timer` are systemd unit templates - **Templates**: `service-backup@.service` and `service-backup@.timer` are systemd unit templates
### Variable Override Pattern ### Variable Override Pattern
@ -94,25 +97,36 @@ Users can customize by setting environment variables before sourcing `backup.env
- `config/restic.conf`: Generated Restic authentication and repository settings - `config/restic.conf`: Generated Restic authentication and repository settings
### Operational Scripts ### Operational Scripts
- `backup/manage`: Main interface (list, status, run, logs commands) - `./manage`: Main interface (list, status, run, logs commands) - auto-sources configuration
- `backup/gen-conf.sh`: Secure configuration generator - `./install`: Consolidated installation script (config + repository)
- `backup/init-restic.sh`: Repository initialization
- `backup/install-service`: Systemd timer installation with template substitution - `backup/install-service`: Systemd timer installation with template substitution
- `backup/list-snapshots`: Snapshot browsing utility
- `backup/restore`: Production-grade restoration tool
### Templates and Restoration ### Templates and Restoration
- `backup/service-backup@.{service,timer}`: Systemd unit templates with variable placeholders - `backup/service-backup@.{service,timer}`: Systemd unit templates with variable placeholders
- `backup/restore`: Production-grade restoration with test mode and extensive validation
- `backup/list-snapshots`: Snapshot browsing utility
## Development Guidelines ## Development Guidelines
When adding new scripts: ### Script Protection
1. Add comment: `# Configuration should be sourced before running: source backup.env` All scripts in `backup/` are protected against direct execution:
2. Use variables from `backup.env` directly (do not auto-source) - Use `CALLED_FROM_MANAGE` environment variable check
3. Follow the pattern of existing scripts for error handling and logging - Scripts error with helpful message if called directly
4. For systemd integration, use template substitution pattern from `install-service` - Always route through `./manage` interface
When modifying configuration: ### Adding New Scripts
1. If adding scripts to `backup/`, include protection check:
```bash
if [ "${CALLED_FROM_MANAGE:-}" != "true" ]; then
echo "ERROR: Use ./manage <command> instead"
exit 1
fi
```
2. Add corresponding command to `./manage` with `CALLED_FROM_MANAGE=true`
3. Follow existing error handling and logging patterns
### Configuration Changes
- All path variables should have environment override capability - All path variables should have environment override capability
- Maintain backward compatibility with default values - Maintain backward compatibility with default values
- Update both `backup.env` and this documentation if adding new variables - Update both `backup.env` and this documentation if adding new variables
- Test with both `./manage` and `./install` interfaces

View File

@ -7,12 +7,11 @@ Système de sauvegarde automatisé basé sur Restic avec intégration systemd po
``` ```
quantumrick/ quantumrick/
├── backup.env # Configuration centralisée ├── backup.env # Configuration centralisée
├── manage # Interface principale de gestion
├── install # Script d'installation et configuration
├── config/ ├── config/
│ └── restic.conf # Configuration Restic (générée) │ └── restic.conf # Configuration Restic (générée)
└── backup/ └── backup/
├── manage # Interface principale de gestion
├── gen-conf.sh # Génération de configuration Restic
├── init-restic.sh # Initialisation repository
├── install-service # Installation timers systemd ├── install-service # Installation timers systemd
├── list-snapshots # Liste des snapshots ├── list-snapshots # Liste des snapshots
├── restore # Restauration ├── restore # Restauration
@ -20,20 +19,6 @@ quantumrick/
└── service-backup@.timer # Template timer systemd └── service-backup@.timer # Template timer systemd
``` ```
## Prérequis
**IMPORTANT:** Tous les scripts doivent être exécutés dans un environnement ayant sourcé la configuration :
```bash
# Toujours commencer par sourcer la configuration
source backup.env
# Puis exécuter les scripts
./backup/manage list
./backup/gen-conf.sh
./backup/init-restic.sh
```
## Installation ## Installation
1. **Configuration initiale** 1. **Configuration initiale**
@ -41,22 +26,21 @@ source backup.env
# Copier et adapter la configuration # Copier et adapter la configuration
cp backup.env.sample backup.env cp backup.env.sample backup.env
# Éditer backup.env selon votre environnement # Éditer backup.env selon votre environnement
# Puis générer la configuration Restic
source backup.env
./backup/gen-conf.sh
``` ```
2. **Initialisation du repository** 2. **Installation complète**
```bash ```bash
source backup.env # Installation automatique (configuration + repository)
./backup/init-restic.sh ./install
# Ou étape par étape
./install config # Génération configuration Restic
./install repo # Initialisation repository
``` ```
3. **Installation d'un service** 3. **Installation d'un service**
```bash ```bash
source backup.env sudo ./manage install <nom_service>
sudo ./backup/install-service <nom_service>
``` ```
## Configuration ## Configuration
@ -78,55 +62,57 @@ export BACKUP_HOME="/home/myuser"
source backup.env source backup.env
# Puis utiliser normalement # Puis utiliser normalement
./backup/manage list ./manage list
``` ```
## Utilisation ## Utilisation
### Gestion des sauvegardes ### Gestion des sauvegardes
```bash ```bash
source backup.env # Lister les timers (configuration auto-sourcée)
./manage list
# Lister les timers
./backup/manage list
# Statut d'un service # Statut d'un service
./backup/manage status paperless ./manage status paperless
# Lancer une sauvegarde manuelle # Lancer une sauvegarde manuelle
./backup/manage run paperless ./manage run paperless
# Voir les logs # Voir les logs
./backup/manage logs paperless ./manage logs paperless
# Services disponibles
./manage available
``` ```
### Restauration ### Restauration
```bash ```bash
source backup.env
# Lister les snapshots # Lister les snapshots
./backup/list-snapshots paperless ./manage snapshots paperless
# Restaurer en mode test # Restaurer en mode test
./backup/restore paperless --test ./manage restore paperless
# Restaurer en production # Restaurer en production
./backup/restore paperless --production ./manage restore-prod paperless
```
## Développement
Pour contribuer au projet, respectez la convention de sourcer `backup.env` dans tous vos scripts :
```bash
#!/bin/bash
# Source configuration (scripts doivent être dans backup/)
source "$(dirname "$(dirname "$0")")/backup.env"
``` ```
## Architecture ## Architecture
- **Configuration centralisée** : `backup.env` contient toutes les variables ### Principes de conception
- **Scripts modulaires** : Chaque script a une responsabilité spécifique
- **Templates systemd** : Variables substituées à l'installation - **Interface unifiée** : Toutes les opérations via `./manage` et `./install`
- **Sécurité** : Mots de passe générés automatiquement - **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

@ -1,56 +0,0 @@
#!/bin/bash
# Script to generate Restic configuration with secure password
set -e
# Configuration should be sourced before running: source backup.env
CONFIG_FILE="$RESTIC_CONFIG_FILE"
REPO_PATH="$BACKUP_REPOSITORY"
echo "=== Generating Restic Configuration ==="
# Check if config already exists
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
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted."
exit 1
fi
fi
# Generate secure password (32 characters)
echo "Generating secure password..."
RESTIC_PASSWORD=$(openssl rand -base64 32)
# Create configuration file
echo "Creating configuration file..."
cat > "$CONFIG_FILE" << EOF
# Restic configuration for quantumrick backups
# Generated on $(date)
# Repository path
export RESTIC_REPOSITORY="$REPO_PATH"
# Repository password
export RESTIC_PASSWORD="$RESTIC_PASSWORD"
# Cache directory (optional)
export RESTIC_CACHE_DIR="$RESTIC_CACHE_DIR"
EOF
# Set secure permissions
chmod 600 "$CONFIG_FILE"
echo "✅ Configuration file created at $CONFIG_FILE"
echo "🔒 Password generated and saved securely"
echo ""
echo "⚠️ IMPORTANT: Save this password somewhere safe!"
echo " If you lose it, you won't be able to restore your backups!"
echo ""
echo "📁 Password saved in: $CONFIG_FILE"
echo " Use 'cat $CONFIG_FILE' to view the password if needed"
echo ""

View File

@ -1,52 +0,0 @@
#!/bin/bash
# Script to initialize Restic repository for quantumrick backups
set -e
# Configuration should be sourced before running: source backup.env
REPO_PATH="$BACKUP_REPOSITORY"
CONFIG_FILE="$RESTIC_CONFIG_FILE"
echo "=== Initializing Restic Repository ==="
# Check if repository directory exists
if [ ! -d "$(dirname "$REPO_PATH")" ]; then
echo "Creating backup directory..."
sudo mkdir -p "$(dirname "$REPO_PATH")"
sudo chown $(whoami):$(whoami) "$(dirname "$REPO_PATH")"
fi
# Check if config file exists
if [ ! -f "$CONFIG_FILE" ]; then
echo "Error: Configuration file $CONFIG_FILE not found!"
echo "Please run generate-restic-config.sh first to create the configuration."
exit 1
fi
# Source the configuration
source "$CONFIG_FILE"
# Check if repository is already initialized
if restic -r "$REPO_PATH" cat config &>/dev/null; then
echo "Repository already initialized at $REPO_PATH"
exit 0
fi
echo "Initializing new Restic repository at $REPO_PATH"
# Initialize the repository
restic init -r "$REPO_PATH"
if [ $? -eq 0 ]; then
echo "✅ Repository successfully initialized!"
echo "Repository path: $REPO_PATH"
echo "Configuration: $CONFIG_FILE"
else
echo "❌ Failed to initialize repository"
exit 1
fi
echo "=== Repository Information ==="
restic -r "$REPO_PATH" stats

View File

@ -1,10 +1,17 @@
#!/bin/bash #!/bin/bash
# Generic script to install systemd timer for any service backup # Generic script to install systemd timer for any service backup
# Usage: sudo ./install-service.sh <service_name> [schedule] # This script should only be called via ./manage install <service>
set -e set -e
# Check if called via manage script
if [ "${CALLED_FROM_MANAGE:-}" != "true" ]; then
echo "ERROR: This script should not be called directly."
echo "Use: ./manage install <service_name>"
exit 1
fi
# Configuration should be sourced before running: source backup.env # Configuration should be sourced before running: source backup.env
# Check arguments # Check arguments

View File

@ -1,10 +1,17 @@
#!/bin/bash #!/bin/bash
# Script to list available snapshots from Restic repository # Script to list available snapshots from Restic repository
# Usage: ./list-snapshots [service_name] # This script should only be called via ./manage snapshots [service]
set -e set -e
# Check if called via manage script
if [ "${CALLED_FROM_MANAGE:-}" != "true" ]; then
echo "ERROR: This script should not be called directly."
echo "Use: ./manage snapshots [service_name]"
exit 1
fi
# Configuration should be sourced before running: source backup.env # Configuration should be sourced before running: source backup.env
# Configuration # Configuration

View File

@ -1,10 +1,17 @@
#!/bin/bash #!/bin/bash
# Restic backup restore script # Restic backup restore script
# Usage: ./restore <service_name> [--test|--production] # This script should only be called via ./manage restore/restore-prod <service>
set -euo pipefail # Strict mode: exit on error, undefined vars, pipe failures set -euo pipefail # Strict mode: exit on error, undefined vars, pipe failures
# Check if called via manage script
if [ "${CALLED_FROM_MANAGE:-}" != "true" ]; then
echo "ERROR: This script should not be called directly."
echo "Use: ./manage restore <service_name> or ./manage restore-prod <service_name>"
exit 1
fi
# Configuration should be sourced before running: source backup.env # Configuration should be sourced before running: source backup.env
# Configuration # Configuration

186
install Executable file
View File

@ -0,0 +1,186 @@
#!/bin/bash
# QuantumRick Installation Script
# Consolidates configuration generation and repository initialization
set -e
# Get the directory where this script is located (project root)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Auto-source configuration
if [ -f "$SCRIPT_DIR/backup.env" ]; then
source "$SCRIPT_DIR/backup.env"
else
echo "ERROR: Configuration file backup.env not found in $SCRIPT_DIR"
echo "Please ensure backup.env exists in project root directory"
exit 1
fi
show_help() {
echo "Usage: $0 [command]"
echo ""
echo "Commands:"
echo " config Generate Restic configuration with secure password"
echo " repo Initialize Restic repository"
echo " setup Complete setup (config + repo)"
echo " help Show this help message"
echo ""
echo "Examples:"
echo " $0 setup # Full installation (recommended)"
echo " $0 config # Generate configuration only"
echo " $0 repo # Initialize repository only"
}
generate_config() {
local CONFIG_FILE="$RESTIC_CONFIG_FILE"
local REPO_PATH="$BACKUP_REPOSITORY"
echo "=== Generating Restic Configuration ==="
# Check if config already exists
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
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted."
return 1
fi
fi
# Ensure config directory exists
mkdir -p "$(dirname "$CONFIG_FILE")"
# Generate secure password (32 characters)
echo "Generating secure password..."
local RESTIC_PASSWORD=$(openssl rand -base64 32)
# Create configuration file
echo "Creating configuration file..."
cat > "$CONFIG_FILE" << EOF
# Restic configuration for quantumrick backups
# Generated on $(date)
# Repository path
export RESTIC_REPOSITORY="$REPO_PATH"
# Repository password
export RESTIC_PASSWORD="$RESTIC_PASSWORD"
# Cache directory (optional)
export RESTIC_CACHE_DIR="$RESTIC_CACHE_DIR"
EOF
# Set secure permissions
chmod 600 "$CONFIG_FILE"
echo "✅ Configuration file created at $CONFIG_FILE"
echo "🔒 Password generated and saved securely"
echo ""
echo "⚠️ IMPORTANT: Save this password somewhere safe!"
echo " If you lose it, you won't be able to restore your backups!"
echo ""
echo "📁 Password saved in: $CONFIG_FILE"
echo " Use 'cat $CONFIG_FILE' to view the password if needed"
echo ""
return 0
}
initialize_repository() {
local REPO_PATH="$BACKUP_REPOSITORY"
local CONFIG_FILE="$RESTIC_CONFIG_FILE"
echo "=== Initializing Restic Repository ==="
# Check if repository directory exists
if [ ! -d "$(dirname "$REPO_PATH")" ]; then
echo "Creating backup directory..."
sudo mkdir -p "$(dirname "$REPO_PATH")"
sudo chown $(whoami):$(whoami) "$(dirname "$REPO_PATH")"
fi
# Check if config file exists
if [ ! -f "$CONFIG_FILE" ]; then
echo "Error: Configuration file $CONFIG_FILE not found!"
echo "Please run '$0 config' first to create the configuration."
return 1
fi
# Source the configuration
source "$CONFIG_FILE"
# Check if repository is already initialized
if restic -r "$REPO_PATH" cat config &>/dev/null; then
echo "Repository already initialized at $REPO_PATH"
return 0
fi
echo "Initializing new Restic repository at $REPO_PATH"
# Initialize the repository
restic init -r "$REPO_PATH"
if [ $? -eq 0 ]; then
echo "✅ Repository successfully initialized!"
echo "Repository path: $REPO_PATH"
echo "Configuration: $CONFIG_FILE"
echo ""
echo "=== Repository Information ==="
restic -r "$REPO_PATH" stats
return 0
else
echo "❌ Failed to initialize repository"
return 1
fi
}
complete_setup() {
echo "=== QuantumRick Complete Setup ==="
echo ""
# Step 1: Generate configuration
if ! generate_config; then
echo "❌ Configuration generation failed"
return 1
fi
echo ""
# Step 2: Initialize repository
if ! initialize_repository; then
echo "❌ Repository initialization failed"
return 1
fi
echo ""
echo "🎉 QuantumRick setup completed successfully!"
echo ""
echo "Next steps:"
echo "1. Install a service timer: ./manage install <service_name>"
echo "2. Check available services: ./manage available"
echo "3. View backup status: ./manage list"
}
# Main script logic
case "${1:-setup}" in
config)
generate_config
;;
repo)
initialize_repository
;;
setup)
complete_setup
;;
help|--help|-h)
show_help
;;
*)
echo "ERROR: Unknown command '${1:-}'"
echo ""
show_help
exit 1
;;
esac

View File

@ -1,10 +1,21 @@
#!/bin/bash #!/bin/bash
# Script to manage backup timers for all services # QuantumRick Backup Management Interface
# Automatically sources configuration from project root
set -e set -e
# Configuration should be sourced before running: source backup.env # Get the directory where this script is located (project root)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Auto-source configuration
if [ -f "$SCRIPT_DIR/backup.env" ]; then
source "$SCRIPT_DIR/backup.env"
else
echo "ERROR: Configuration file backup.env not found in $SCRIPT_DIR"
echo "Please ensure backup.env exists in project root directory"
exit 1
fi
BACKUP_DIR="$BACKUP_BASE_DIR" BACKUP_DIR="$BACKUP_BASE_DIR"
SERVICES_DIR="$SERVICES_BASE_DIR" SERVICES_DIR="$SERVICES_BASE_DIR"
@ -168,7 +179,7 @@ install_timer() {
exit 1 exit 1
fi fi
"$BACKUP_DIR/install" "$service" CALLED_FROM_MANAGE=true "$SCRIPT_DIR/backup/install-service" "$service"
} }
list_available() { list_available() {
@ -220,16 +231,16 @@ case "${1:-}" in
list_available list_available
;; ;;
snapshots) snapshots)
"$BACKUP_DIR/list-snapshots" "$2" CALLED_FROM_MANAGE=true "$SCRIPT_DIR/backup/list-snapshots" "$2"
;; ;;
restore) restore)
"$BACKUP_DIR/restore" "$2" --test CALLED_FROM_MANAGE=true "$SCRIPT_DIR/backup/restore" "$2" --test
;; ;;
restore-prod) restore-prod)
"$BACKUP_DIR/restore" "$2" --production CALLED_FROM_MANAGE=true "$SCRIPT_DIR/backup/restore" "$2" --production
;; ;;
cleanup-test) cleanup-test)
"$BACKUP_DIR/cleanup-test" "$2" CALLED_FROM_MANAGE=true "$SCRIPT_DIR/backup/cleanup-test" "$2"
;; ;;
help|--help|-h) help|--help|-h)
show_help show_help