admin migrate-database
This commit is contained in:
@@ -3,18 +3,21 @@ use std::sync::Arc;
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use chrono::{Duration as ChronoDuration, Utc};
|
||||
use clap::{Parser, Subcommand, ValueEnum};
|
||||
use diesel::{dsl::exists, prelude::*, select};
|
||||
use diesel::{dsl::exists, pg::PgConnection, prelude::*, select};
|
||||
use diesel_migrations::MigrationHarness;
|
||||
use rand::{rngs::OsRng, TryRngCore};
|
||||
use reqwest::{Client, Method, StatusCode};
|
||||
use sha2::{Digest, Sha256};
|
||||
use tokio::task;
|
||||
use uuid::Uuid;
|
||||
|
||||
use papercrate::{
|
||||
auth::capability_sets::{ensure_capability_set, owner_capabilities},
|
||||
config::AppConfig,
|
||||
config::{redact_database_url, AppConfig},
|
||||
db::{self, PgPool},
|
||||
documents::search::ensure_quickwit_index,
|
||||
jobs::{enqueue_job, JOB_ANALYZE_DOCUMENT, JOB_DELETE_TENANT},
|
||||
migrations::MIGRATIONS,
|
||||
models::{
|
||||
DocumentAsset, DocumentAssetObject, MagicToken, MagicTokenKind, NewUser, NewUserMembership,
|
||||
Tenant, TenantStatus, User,
|
||||
@@ -112,6 +115,14 @@ enum Command {
|
||||
#[arg(long = "kind", value_enum, default_value_t = MagicTokenKindArg::EmailLogin)]
|
||||
kind: MagicTokenKindArg,
|
||||
},
|
||||
MigrateDatabase {
|
||||
#[arg(
|
||||
long = "database-url",
|
||||
value_name = "URL",
|
||||
help = "Override the migrations database URL (defaults to MIGRATIONS_DATABASE_URL or DATABASE_URL)"
|
||||
)]
|
||||
database_url: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, ValueEnum)]
|
||||
@@ -211,11 +222,34 @@ async fn main() -> Result<()> {
|
||||
} => {
|
||||
create_magic_token(&pool, &username, ttl_minutes, max_uses, kind.into())?;
|
||||
}
|
||||
Command::MigrateDatabase { database_url } => {
|
||||
let url = database_url.unwrap_or_else(|| config.migrations_database_url().to_string());
|
||||
migrate_database(url).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn migrate_database(database_url: String) -> Result<()> {
|
||||
let redacted = redact_database_url(&database_url);
|
||||
tracing::info!(database_url = %redacted, "running pending migrations");
|
||||
|
||||
let result = task::spawn_blocking(move || -> Result<()> {
|
||||
let mut conn =
|
||||
PgConnection::establish(&database_url).context("failed to connect to database")?;
|
||||
conn.run_pending_migrations(MIGRATIONS)
|
||||
.map_err(|err| anyhow!("failed to run migrations: {err}"))?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.context("migration task panicked")?;
|
||||
|
||||
result?;
|
||||
tracing::info!(database_url = %redacted, "migrations completed");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_user(pool: &PgPool, username: &str) -> Result<()> {
|
||||
let username = normalize_identifier(
|
||||
username,
|
||||
|
||||
Reference in New Issue
Block a user