Browse Source

Merge 011767057c into a2ad1dc7c3

pull/6349/merge
Lukas Pieper 1 day ago
committed by GitHub
parent
commit
f8ec13e697
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      src/api/admin.rs
  2. 17
      src/db/mod.rs
  3. 12
      src/main.rs

2
src/api/admin.rs

@ -793,7 +793,7 @@ async fn delete_config(_token: AdminToken) -> EmptyResult {
#[post("/config/backup_db", format = "application/json")]
async fn backup_db(_token: AdminToken, mut conn: DbConn) -> ApiResult<String> {
if *CAN_BACKUP {
match backup_database(&mut conn).await {
match backup_database(&mut conn, None).await {
Ok(f) => Ok(format!("Backup to '{f}' was successful")),
Err(e) => err!(format!("Backup was unsuccessful {e}")),
}

17
src/db/mod.rs

@ -368,7 +368,7 @@ pub mod models;
/// Creates a back-up of the sqlite database
/// MySQL/MariaDB and PostgreSQL are not supported.
pub async fn backup_database(conn: &mut DbConn) -> Result<String, Error> {
pub async fn backup_database(conn: &mut DbConn, output_dir: Option<String>) -> Result<String, Error> {
db_run! {@raw conn:
postgresql, mysql {
let _ = conn;
@ -376,8 +376,19 @@ pub async fn backup_database(conn: &mut DbConn) -> Result<String, Error> {
}
sqlite {
let db_url = CONFIG.database_url();
let db_path = std::path::Path::new(&db_url).parent().unwrap();
let backup_file = db_path
let backup_dir = match &output_dir {
Some(dir) => {
let output_path = std::path::Path::new(dir);
if !output_path.exists() || !output_path.is_dir() {
err!(format!("Backup directory does not exist or is not a directory: {}", dir));
}
output_path
}
None => std::path::Path::new(&db_url).parent().unwrap(),
};
let backup_file = backup_dir
.join(format!("db_{}.sqlite3", chrono::Utc::now().format("%Y%m%d_%H%M%S")))
.to_string_lossy()
.into_owned();

12
src/main.rs

@ -106,7 +106,7 @@ FLAGS:
COMMAND:
hash [--preset {bitwarden|owasp}] Generate an Argon2id PHC ADMIN_TOKEN
backup Create a backup of the SQLite database
backup [--output <dir>] Create a backup of the SQLite database
You can also send the USR1 signal to trigger a backup
PRESETS: m= t= p=
@ -188,7 +188,9 @@ async fn parse_args() {
exit(1);
}
} else if command == "backup" {
match backup_sqlite().await {
let output_dir: Option<String> = pargs.opt_value_from_str(["-o", "--output"]).unwrap_or_default();
match backup_sqlite(output_dir).await {
Ok(f) => {
println!("Backup to '{f}' was successful");
exit(0);
@ -203,7 +205,7 @@ async fn parse_args() {
}
}
async fn backup_sqlite() -> Result<String, Error> {
async fn backup_sqlite(output_dir: Option<String>) -> Result<String, Error> {
use crate::db::{backup_database, DbConnType};
if DbConnType::from_url(&CONFIG.database_url()).map(|t| t == DbConnType::sqlite).unwrap_or(false) {
// Establish a connection to the sqlite database
@ -213,7 +215,7 @@ async fn backup_sqlite() -> Result<String, Error> {
.await
.expect("Unable to get SQLite db pool");
let backup_file = backup_database(&mut conn).await?;
let backup_file = backup_database(&mut conn, output_dir).await?;
Ok(backup_file)
} else {
err_silent!("The database type is not SQLite. Backups only works for SQLite databases")
@ -622,7 +624,7 @@ async fn launch_rocket(pool: db::DbPool, extra_debug: bool) -> Result<(), Error>
// If we need more signals to act upon, we might want to use select! here.
// With only one item to listen for this is enough.
let _ = signal_user1.recv().await;
match backup_sqlite().await {
match backup_sqlite(None).await {
Ok(f) => info!("Backup to '{f}' was successful"),
Err(e) => error!("Backup failed. {e:?}"),
}

Loading…
Cancel
Save