lmrc-postgres 0.3.16

PostgreSQL management library for the LMRC Stack - comprehensive library for managing PostgreSQL installations on remote servers via SSH
Documentation
//! User and Database Management Example
//!
//! This example demonstrates the comprehensive user and database management
//! capabilities of postgres-manager:
//!
//! - Listing users and databases
//! - Creating users with custom options
//! - Creating databases with custom options
//! - Managing permissions (GRANT/REVOKE)
//! - Role-based access control
//! - Password updates
//! - Cleanup (dropping users and databases)

use lmrc_postgres::{PostgresConfig, PostgresManager, Privilege};

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

    println!("\n=== PostgreSQL User & Database Management Example ===\n");

    // Build PostgreSQL configuration
    let config = PostgresConfig::builder()
        .version("15")
        .database_name("postgres") // Connect to default database initially
        .username("postgres")
        .password("postgres")
        .build()?;

    // Create manager
    let manager = PostgresManager::builder()
        .config(config)
        .server_ip("192.168.1.100")
        .ssh_user("root")
        .build()?;

    // ==================== List Existing Users and Databases ====================
    println!("1. Listing existing users and databases\n");

    println!("Current users:");
    let users = manager.list_users().await?;
    for user in &users {
        println!(
            "  - {} (superuser: {}, can_create_db: {}, can_create_role: {}, connection_limit: {})",
            user.name,
            user.is_superuser,
            user.can_create_db,
            user.can_create_role,
            user.connection_limit
        );
    }

    println!("\nCurrent databases:");
    let databases = manager.list_databases().await?;
    for db in &databases {
        let size_str = db.size.as_deref().unwrap_or("unknown");
        println!(
            "  - {} (owner: {}, encoding: {}, size: {})",
            db.name, db.owner, db.encoding, size_str
        );
    }

    // ==================== Create Application Database ====================
    println!("\n2. Creating application database with custom settings\n");

    let app_db = "myapp_db";

    if !manager.database_exists(app_db).await? {
        manager
            .create_database_with_options(app_db, Some("postgres"), Some("UTF8"), Some("template0"))
            .await?;
        println!("✓ Created database: {}", app_db);
    } else {
        println!("✓ Database already exists: {}", app_db);
    }

    // ==================== Create Users with Different Roles ====================
    println!("\n3. Creating users with different permission levels\n");

    // Admin user - can create databases and roles
    let admin_user = "app_admin";
    if !manager.user_exists(admin_user).await? {
        manager
            .create_user_with_options(
                admin_user,
                "admin_secure_password",
                false,    // not superuser
                true,     // can create databases
                true,     // can create roles
                Some(10), // connection limit
            )
            .await?;
        println!("✓ Created admin user: {}", admin_user);
    } else {
        println!("✓ User already exists: {}", admin_user);
    }

    // Application user - regular user with limited permissions
    let app_user = "app_user";
    if !manager.user_exists(app_user).await? {
        manager
            .create_user_with_options(
                app_user,
                "app_secure_password",
                false,    // not superuser
                false,    // cannot create databases
                false,    // cannot create roles
                Some(50), // higher connection limit for app
            )
            .await?;
        println!("✓ Created application user: {}", app_user);
    } else {
        println!("✓ User already exists: {}", app_user);
    }

    // Read-only user
    let readonly_user = "app_readonly";
    if !manager.user_exists(readonly_user).await? {
        manager
            .create_user_with_options(
                readonly_user,
                "readonly_password",
                false,
                false,
                false,
                Some(20),
            )
            .await?;
        println!("✓ Created read-only user: {}", readonly_user);
    } else {
        println!("✓ User already exists: {}", readonly_user);
    }

    // ==================== Grant Privileges ====================
    println!("\n4. Granting privileges to users\n");

    // Grant full privileges to admin user
    manager
        .grant_privileges(app_db, admin_user, &[Privilege::All])
        .await?;
    println!("✓ Granted ALL privileges on {} to {}", app_db, admin_user);

    // Grant read/write privileges to application user
    manager
        .grant_privileges(
            app_db,
            app_user,
            &[
                Privilege::Select,
                Privilege::Insert,
                Privilege::Update,
                Privilege::Delete,
            ],
        )
        .await?;
    println!(
        "✓ Granted SELECT, INSERT, UPDATE, DELETE on {} to {}",
        app_db, app_user
    );

    // Grant only SELECT to read-only user
    manager
        .grant_privileges(app_db, readonly_user, &[Privilege::Select])
        .await?;
    println!("✓ Granted SELECT only on {} to {}", app_db, readonly_user);

    // ==================== Role-Based Access Control ====================
    println!("\n5. Setting up role-based access control\n");

    // Create a role for analytics users
    let analytics_role = "analytics";
    manager.create_role(analytics_role, false, false).await?;
    println!("✓ Created role: {}", analytics_role);

    // Grant SELECT privilege to the role
    manager
        .grant_privileges(app_db, analytics_role, &[Privilege::Select])
        .await?;
    println!("✓ Granted SELECT to role: {}", analytics_role);

    // Grant the role to read-only user
    manager.grant_role(analytics_role, readonly_user).await?;
    println!(
        "✓ Granted role '{}' to user '{}'",
        analytics_role, readonly_user
    );

    // ==================== Password Management ====================
    println!("\n6. Updating user passwords\n");

    manager
        .update_user_password(app_user, "new_secure_password_2024")
        .await?;
    println!("✓ Updated password for user: {}", app_user);

    // ==================== Verify Setup ====================
    println!("\n7. Verifying the setup\n");

    println!("Final user list:");
    let users = manager.list_users().await?;
    for user in &users {
        if user.name.starts_with("app_") || user.name == "analytics" {
            println!("  - {} (superuser: {})", user.name, user.is_superuser);
        }
    }

    println!("\nFinal database list:");
    let databases = manager.list_databases().await?;
    for db in &databases {
        if db.name == app_db {
            println!("  - {} (owner: {})", db.name, db.owner);
        }
    }

    // ==================== Privilege Revocation Example ====================
    println!("\n8. Demonstrating privilege revocation\n");

    // Revoke DELETE privilege from app_user
    manager
        .revoke_privileges(app_db, app_user, &[Privilege::Delete])
        .await?;
    println!("✓ Revoked DELETE privilege from {} on {}", app_user, app_db);

    // ==================== Cleanup (Optional) ====================
    println!("\n9. Cleanup example (commented out for safety)\n");

    println!("To clean up, you would run:");
    println!(
        "  manager.revoke_role(\"{}\", \"{}\").await?;",
        analytics_role, readonly_user
    );
    println!("  manager.drop_user(\"{}\").await?;", readonly_user);
    println!("  manager.drop_user(\"{}\").await?;", app_user);
    println!("  manager.drop_user(\"{}\").await?;", admin_user);
    println!("  manager.drop_database(\"{}\").await?;", app_db);

    // Uncomment to actually perform cleanup:
    /*
    println!("\nPerforming cleanup...");

    // Revoke role before dropping user
    manager.revoke_role(analytics_role, readonly_user).await?;
    println!("✓ Revoked role '{}' from '{}'", analytics_role, readonly_user);

    // Drop users
    manager.drop_user(readonly_user).await?;
    println!("✓ Dropped user: {}", readonly_user);

    manager.drop_user(app_user).await?;
    println!("✓ Dropped user: {}", app_user);

    manager.drop_user(admin_user).await?;
    println!("✓ Dropped user: {}", admin_user);

    // Drop database
    manager.drop_database(app_db).await?;
    println!("✓ Dropped database: {}", app_db);

    println!("✓ Cleanup complete");
    */

    // ==================== Summary ====================
    println!("\n=== Summary ===\n");
    println!("This example demonstrated:");
    println!("  ✓ Listing users and databases");
    println!("  ✓ Creating databases with custom options (encoding, template, owner)");
    println!("  ✓ Creating users with specific capabilities and connection limits");
    println!("  ✓ Granting granular privileges (SELECT, INSERT, UPDATE, DELETE, ALL)");
    println!("  ✓ Role-based access control (create role, grant to users)");
    println!("  ✓ Password updates");
    println!("  ✓ Privilege revocation");
    println!("  ✓ Cleanup procedures (drop users and databases)");
    println!("\nAll user and database management operations completed successfully!");

    Ok(())
}