From 17414fee4a4cb9dcd3a3338ad51448ff5623fc08 Mon Sep 17 00:00:00 2001 From: Nicolas Duhamel Date: Mon, 23 Jun 2025 21:41:09 +0200 Subject: [PATCH] Refactor: Unify interface with manage and install scripts at root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- CLAUDE.md | 88 +++++++++++-------- README.md | 92 +++++++++----------- backup/gen-conf.sh | 56 ------------ backup/init-restic.sh | 52 ----------- backup/install-service | 9 +- backup/list-snapshots | 9 +- backup/restore | 9 +- install | 186 ++++++++++++++++++++++++++++++++++++++++ backup/manage => manage | 25 ++++-- 9 files changed, 318 insertions(+), 208 deletions(-) delete mode 100644 backup/gen-conf.sh delete mode 100644 backup/init-restic.sh create mode 100755 install rename backup/manage => manage (89%) diff --git a/CLAUDE.md b/CLAUDE.md index cde7816..0c1e552 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,19 +4,23 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## 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 -# Always start by sourcing configuration -source backup.env +# Installation and setup +./install # Complete setup (config + repository) +./install config # Generate configuration only +./install repo # Initialize repository only -# Then execute any script -./backup/manage list -./backup/gen-conf.sh -sudo ./backup/install-service paperless +# All backup operations via manage +./manage list # List backup timers +./manage install # Install service timer +./manage run # Manual backup +./manage restore # Restore (test mode) +./manage restore-prod # 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 @@ -24,31 +28,29 @@ This is the core architectural pattern of this codebase. Scripts do NOT auto-sou ```bash cp backup.env.sample backup.env # Copy configuration template # Edit backup.env to match environment -source backup.env -./backup/gen-conf.sh # Generate secure Restic configuration -./backup/init-restic.sh # Initialize Restic repository +./install # Complete installation (config + repository) ``` ### Service Management ```bash -source backup.env -./backup/manage list # List all backup timers -./backup/manage status # Service backup status -./backup/manage run # Manual backup execution -./backup/manage logs # View backup logs -sudo ./backup/install-service # Install systemd timer +./manage list # List all backup timers +./manage status # Service backup status +./manage run # Manual backup execution +./manage logs # View backup logs +./manage available # List services with backup.sh +sudo ./manage install # Install systemd timer ``` ### Backup Operations ```bash -source backup.env -./backup/list-snapshots [service] # List available snapshots -./backup/restore --test # Test restoration -./backup/restore --production # Production restoration +./manage snapshots [service] # List available snapshots +./manage restore # Test restoration +./manage restore-prod # Production restoration ``` ### Configuration Testing ```bash +# Source configuration manually for utility functions source backup.env show_config # Display current configuration validate_paths # Check directory existence @@ -62,9 +64,10 @@ validate_paths # Check directory existence - **Variable substitution**: systemd templates use `${VAR}` placeholders replaced during installation ### Core Components -- **`backup/manage`**: Primary interface for all backup operations and service management -- **`backup/install-service`**: Systemd timer installer that performs variable substitution in templates -- **`backup/restore`**: Advanced restoration tool with test/production modes and safety checks +- **`./manage`**: Primary interface for all backup operations and service management (auto-sources config) +- **`./install`**: Installation script consolidating configuration generation and repository initialization +- **`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 ### 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 ### Operational Scripts -- `backup/manage`: Main interface (list, status, run, logs commands) -- `backup/gen-conf.sh`: Secure configuration generator -- `backup/init-restic.sh`: Repository initialization +- `./manage`: Main interface (list, status, run, logs commands) - auto-sources configuration +- `./install`: Consolidated installation script (config + repository) - `backup/install-service`: Systemd timer installation with template substitution +- `backup/list-snapshots`: Snapshot browsing utility +- `backup/restore`: Production-grade restoration tool ### Templates and Restoration - `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 -When adding new scripts: -1. Add comment: `# Configuration should be sourced before running: source backup.env` -2. Use variables from `backup.env` directly (do not auto-source) -3. Follow the pattern of existing scripts for error handling and logging -4. For systemd integration, use template substitution pattern from `install-service` +### Script Protection +All scripts in `backup/` are protected against direct execution: +- Use `CALLED_FROM_MANAGE` environment variable check +- Scripts error with helpful message if called directly +- 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 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 -- Maintain backward compatibility with default values -- Update both `backup.env` and this documentation if adding new variables \ No newline at end of file +- Maintain backward compatibility with default values +- Update both `backup.env` and this documentation if adding new variables +- Test with both `./manage` and `./install` interfaces \ No newline at end of file diff --git a/README.md b/README.md index 9d2cb9d..19d5a4d 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,11 @@ SystĂšme de sauvegarde automatisĂ© basĂ© sur Restic avec intĂ©gration systemd po ``` quantumrick/ ├── 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/ - ├── manage # Interface principale de gestion - ├── gen-conf.sh # GĂ©nĂ©ration de configuration Restic - ├── init-restic.sh # Initialisation repository ├── install-service # Installation timers systemd ├── list-snapshots # Liste des snapshots ├── restore # Restauration @@ -20,20 +19,6 @@ quantumrick/ └── 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 1. **Configuration initiale** @@ -41,22 +26,21 @@ source backup.env # Copier et adapter la configuration cp backup.env.sample backup.env # É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 - source backup.env - ./backup/init-restic.sh + # 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 - source backup.env - sudo ./backup/install-service + sudo ./manage install ``` ## Configuration @@ -78,55 +62,57 @@ export BACKUP_HOME="/home/myuser" source backup.env # Puis utiliser normalement -./backup/manage list +./manage list ``` ## Utilisation ### Gestion des sauvegardes ```bash -source backup.env - -# Lister les timers -./backup/manage list +# Lister les timers (configuration auto-sourcĂ©e) +./manage list # Statut d'un service -./backup/manage status paperless +./manage status paperless # Lancer une sauvegarde manuelle -./backup/manage run paperless +./manage run paperless # Voir les logs -./backup/manage logs paperless +./manage logs paperless + +# Services disponibles +./manage available ``` ### Restauration ```bash -source backup.env - # Lister les snapshots -./backup/list-snapshots paperless +./manage snapshots paperless # Restaurer en mode test -./backup/restore paperless --test +./manage restore paperless # Restaurer en production -./backup/restore paperless --production -``` - -## 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" +./manage restore-prod paperless ``` ## Architecture -- **Configuration centralisĂ©e** : `backup.env` contient toutes les variables -- **Scripts modulaires** : Chaque script a une responsabilitĂ© spĂ©cifique -- **Templates systemd** : Variables substituĂ©es Ă  l'installation -- **SĂ©curitĂ©** : Mots de passe gĂ©nĂ©rĂ©s automatiquement \ No newline at end of file +### 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. \ No newline at end of file diff --git a/backup/gen-conf.sh b/backup/gen-conf.sh deleted file mode 100644 index d41a300..0000000 --- a/backup/gen-conf.sh +++ /dev/null @@ -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 "" diff --git a/backup/init-restic.sh b/backup/init-restic.sh deleted file mode 100644 index aa07914..0000000 --- a/backup/init-restic.sh +++ /dev/null @@ -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 diff --git a/backup/install-service b/backup/install-service index b55ea06..b50f9e4 100755 --- a/backup/install-service +++ b/backup/install-service @@ -1,10 +1,17 @@ #!/bin/bash # Generic script to install systemd timer for any service backup -# Usage: sudo ./install-service.sh [schedule] +# This script should only be called via ./manage install 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 " + exit 1 +fi + # Configuration should be sourced before running: source backup.env # Check arguments diff --git a/backup/list-snapshots b/backup/list-snapshots index c590b26..2b73949 100755 --- a/backup/list-snapshots +++ b/backup/list-snapshots @@ -1,10 +1,17 @@ #!/bin/bash # 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 +# 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 diff --git a/backup/restore b/backup/restore index 098dd48..31c760f 100755 --- a/backup/restore +++ b/backup/restore @@ -1,10 +1,17 @@ #!/bin/bash # Restic backup restore script -# Usage: ./restore [--test|--production] +# This script should only be called via ./manage restore/restore-prod 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 or ./manage restore-prod " + exit 1 +fi + # Configuration should be sourced before running: source backup.env # Configuration diff --git a/install b/install new file mode 100755 index 0000000..489a1d9 --- /dev/null +++ b/install @@ -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 " + 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 \ No newline at end of file diff --git a/backup/manage b/manage similarity index 89% rename from backup/manage rename to manage index cd92537..e0a2043 100755 --- a/backup/manage +++ b/manage @@ -1,10 +1,21 @@ #!/bin/bash -# Script to manage backup timers for all services +# QuantumRick Backup Management Interface +# Automatically sources configuration from project root 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" SERVICES_DIR="$SERVICES_BASE_DIR" @@ -168,7 +179,7 @@ install_timer() { exit 1 fi - "$BACKUP_DIR/install" "$service" + CALLED_FROM_MANAGE=true "$SCRIPT_DIR/backup/install-service" "$service" } list_available() { @@ -220,16 +231,16 @@ case "${1:-}" in list_available ;; snapshots) - "$BACKUP_DIR/list-snapshots" "$2" + CALLED_FROM_MANAGE=true "$SCRIPT_DIR/backup/list-snapshots" "$2" ;; restore) - "$BACKUP_DIR/restore" "$2" --test + CALLED_FROM_MANAGE=true "$SCRIPT_DIR/backup/restore" "$2" --test ;; restore-prod) - "$BACKUP_DIR/restore" "$2" --production + CALLED_FROM_MANAGE=true "$SCRIPT_DIR/backup/restore" "$2" --production ;; cleanup-test) - "$BACKUP_DIR/cleanup-test" "$2" + CALLED_FROM_MANAGE=true "$SCRIPT_DIR/backup/cleanup-test" "$2" ;; help|--help|-h) show_help