lmrc-postgres 0.3.16

PostgreSQL management library for the LMRC Stack - comprehensive library for managing PostgreSQL installations on remote servers via SSH
Documentation
//! Example: Configuration Backup, Rollback, and Dry-Run
//!
//! This example demonstrates:
//! 1. Dry-run mode (preview changes without applying)
//! 2. Configuration backup creation
//! 3. Safe configuration changes with automatic rollback
//! 4. Manual rollback to previous configuration
//! 5. pg_hba.conf reading and parsing
//! 6. Backup management (list, cleanup)
//!
//! Run with:
//! ```bash
//! cargo run --example backup_and_rollback
//! ```

use lmrc_postgres::{PostgresConfig, parse_pg_hba_rules};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize logging
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::INFO)
        .init();

    println!("=== PostgreSQL Configuration Backup & Rollback ===\n");

    // Note: This example shows the API usage. For actual execution,
    // you would need a real SSH connection to a server.

    // Build configuration
    let _config = PostgresConfig::builder()
        .version("15")
        .database_name("myapp")
        .username("appuser")
        .password("secure_password")
        .listen_addresses("0.0.0.0/0")
        .port(5432)
        .max_connections(100)
        .shared_buffers("256MB")
        .build()?;

    println!("Example 1: Dry-Run Mode");
    println!("------------------------");
    println!("Dry-run allows you to preview changes before applying them.\n");
    println!("Code:");
    println!("```rust");
    println!("// Preview what changes would be made");
    println!("let diff = manager.dry_run_configure().await?;");
    println!();
    println!("if diff.has_changes() {{");
    println!("    println!(\"Would make {{}} change(s):\", diff.len());");
    println!("    println!(\"{{}}\", diff);");
    println!("    ");
    println!("    // If changes look good, apply them");
    println!("    manager.apply_diff(&diff).await?;");
    println!("}}");
    println!("```\n");

    println!("Example 2: Safe Configuration Apply");
    println!("------------------------------------");
    println!("apply_diff_safe() automatically creates a backup and rolls back on failure.\n");
    println!("Code:");
    println!("```rust");
    println!("let diff = manager.diff().await?;");
    println!();
    println!("if diff.has_changes() {{");
    println!("    // This method:");
    println!("    // 1. Creates a backup");
    println!("    // 2. Applies changes");
    println!("    // 3. Rolls back automatically if anything fails");
    println!("    manager.apply_diff_safe(&diff).await?;");
    println!("}}");
    println!("```\n");

    println!("Example 3: Manual Backup & Restore");
    println!("-----------------------------------");
    println!("Code:");
    println!("```rust");
    println!("// Create a backup manually");
    println!("let backup = manager.backup_config().await?;");
    println!("println!(\"Backup created: {{}}\", backup.backup_dir);");
    println!();
    println!("// Make some changes...");
    println!("manager.configure().await?;");
    println!();
    println!("// If something went wrong, restore from backup");
    println!("manager.restore_backup(&backup).await?;");
    println!("```\n");

    println!("Example 4: Quick Rollback");
    println!("--------------------------");
    println!("Rollback to the most recent backup in one command.\n");
    println!("Code:");
    println!("```rust");
    println!("// Oops, the last change broke something!");
    println!("// Quickly roll back to the previous configuration");
    println!("manager.rollback_config().await?;");
    println!("println!(\"Rolled back to previous configuration\");");
    println!("```\n");

    println!("Example 5: Backup Management");
    println!("-----------------------------");
    println!("Code:");
    println!("```rust");
    println!("// List all available backups");
    println!("let backups = manager.list_backups().await?;");
    println!("for backup in &backups {{");
    println!("    println!(\"Backup: {{}} - {{}} files\", ");
    println!("        backup.timestamp, backup.files.len());");
    println!("}}");
    println!();
    println!("// Keep only the 5 most recent backups");
    println!("let deleted = manager.cleanup_old_backups(5).await?;");
    println!("println!(\"Deleted {{}} old backup(s)\", deleted);");
    println!("```\n");

    println!("Example 6: pg_hba.conf Inspection");
    println!("----------------------------------");
    println!("Read and parse pg_hba.conf authentication rules.\n");
    println!("Code:");
    println!("```rust");
    println!("// Read current pg_hba.conf");
    println!("let pg_hba_content = manager.read_pg_hba().await?;");
    println!();
    println!("// Parse rules");
    println!("let rules = parse_pg_hba_rules(&pg_hba_content);");
    println!("for rule in rules {{");
    println!("    println!(\"Rule: {{}} - {{}} - {{}}\",");
    println!("        rule.rule_type, rule.database, rule.method);");
    println!("}}");
    println!("```\n");

    println!("Example 7: Complete Workflow");
    println!("------------------------------");
    println!("A typical safe configuration change workflow:\n");
    println!("1. Check what would change (dry-run)");
    println!("2. Create explicit backup");
    println!("3. Apply changes");
    println!("4. Verify");
    println!("5. If issues, rollback\n");

    println!("Code:");
    println!("```rust");
    println!("// Step 1: Preview changes");
    println!("let diff = manager.dry_run_configure().await?;");
    println!("if !diff.has_changes() {{");
    println!("    println!(\"No changes needed\");");
    println!("    return Ok(());");
    println!("}}");
    println!();
    println!("// Step 2: Show changes to user");
    println!("println!(\"The following changes will be made:\");");
    println!("println!(\"{{}}\", diff);");
    println!();
    println!("// Step 3: Create backup before changes");
    println!("let backup = manager.backup_config().await?;");
    println!("println!(\"Created backup: {{}}\", backup.timestamp);");
    println!();
    println!("// Step 4: Apply changes");
    println!("match manager.apply_diff(&diff).await {{");
    println!("    Ok(_) => println!(\"✓ Changes applied successfully\"),");
    println!("    Err(e) => {{");
    println!("        eprintln!(\"✗ Error applying changes: {{}}\", e);");
    println!("        println!(\"Rolling back to backup...\");");
    println!("        manager.restore_backup(&backup).await?;");
    println!("        return Err(e.into());");
    println!("    }}");
    println!("}}");
    println!();
    println!("// Step 5: Verify changes");
    println!("manager.test_connection().await?;");
    println!("println!(\"✓ Configuration verified\");");
    println!("```\n");

    println!("Example 8: pg_hba.conf Diff Detection");
    println!("--------------------------------------");
    println!("Compare pg_hba.conf rules to detect changes.\n");

    let example_current = r#"
# PostgreSQL Client Authentication Configuration File
# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   all             postgres                                peer
host    all             all             127.0.0.1/32            md5
"#;

    let example_desired = r#"
# PostgreSQL Client Authentication Configuration File
# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   all             postgres                                trust
host    all             all             127.0.0.1/32            md5
host    all             all             0.0.0.0/0               md5
"#;

    println!("Current pg_hba.conf:");
    println!("{}", example_current);

    println!("Desired pg_hba.conf:");
    println!("{}", example_desired);

    let current_rules = parse_pg_hba_rules(example_current);
    let desired_rules = parse_pg_hba_rules(example_desired);

    println!("Parsed current rules: {}", current_rules.len());
    for (i, rule) in current_rules.iter().enumerate() {
        println!("  {}: {}", i + 1, rule);
    }

    println!("\nParsed desired rules: {}", desired_rules.len());
    for (i, rule) in desired_rules.iter().enumerate() {
        println!("  {}: {}", i + 1, rule);
    }

    // Detect differences
    use lmrc_postgres::diff_pg_hba_rules;
    let diffs = diff_pg_hba_rules(&current_rules, &desired_rules);

    if !diffs.is_empty() {
        println!(
            "\npg_hba.conf changes detected ({} difference(s)):",
            diffs.len()
        );
        for diff in diffs {
            println!("  {}", diff);
        }
    } else {
        println!("\nNo pg_hba.conf changes detected");
    }

    println!("\n=== Key Features Summary ===\n");
    println!("✓ Dry-run mode - Preview changes without applying");
    println!("✓ Automatic backups - Create backups before changes");
    println!("✓ Safe apply - Automatic rollback on failure");
    println!("✓ Manual rollback - Restore to any previous backup");
    println!("✓ Backup management - List and cleanup old backups");
    println!("✓ pg_hba.conf support - Read, parse, and diff authentication rules");
    println!("\n=== Complete ===");

    Ok(())
}