-
-
Notifications
You must be signed in to change notification settings - Fork 0
feat(cli): backup management commands #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
d4c8625
feat(cli): added `mbm backup list` command
Nonolanlan1007 88f543f
feat(config): added backup identifier to Backup structure
Nonolanlan1007 f285899
feat(datastores): added .list_backups() and .check_backup_integrity()…
Nonolanlan1007 58637f6
feat(cli): added `mbm backup inspect` command
Nonolanlan1007 1442e06
refactor: fixed clippy errors
Nonolanlan1007 6097646
refactor(cli): fixed imports
Nonolanlan1007 494c77f
refactor!: moved backup related functions to BackupJob struct and mer…
Nonolanlan1007 177fae5
refactor: fixed clippy errors
Nonolanlan1007 f96b090
fix(backups): fixed finalize_backup() method in backupJob
Nonolanlan1007 0cb5ffc
fix(datastore): added open_read_stream() method
Nonolanlan1007 e55a569
fix(backup): added restore_backup method
Nonolanlan1007 54c634b
refactor(backup): fixed imports
Nonolanlan1007 61319d2
feat(cli): added `mbm backup restore` command
Nonolanlan1007 55a7178
fix(config): fixed config_parse_config test
Nonolanlan1007 0b9cac4
refactor: fixed clippy errors
Nonolanlan1007 e4d32e3
fix(config): fixed config_parse_config test
Nonolanlan1007 84eb027
fix(config): brought back optional schedule
Nonolanlan1007 e5eb9a4
fix(config): fixed config_parse_config test
Nonolanlan1007 896b64b
refactor(datastore): added `.as_str()` method to `Datastore` trait
Nonolanlan1007 d676974
refactor(datastore): replaced `.unwrap_or_else(Vec::new())` by `.unwr…
Nonolanlan1007 ac35f7a
refactor(datastore): enhanced filesystem datastore
Nonolanlan1007 6f558ca
chore(crates): removed default features from `async-stream`
Nonolanlan1007 ae90990
refactor(logger): removed useless brackets
Nonolanlan1007 fff87b1
refactor(config): removed useless `.clone()`
Nonolanlan1007 5caa317
refactor: fixed clippy errors
Nonolanlan1007 ef997d8
refactor(cli): removed some unwraps from `mbm backup inspect` command
Nonolanlan1007 597a055
refactor(datastore): merged multiple `.filer_map()` in one
Nonolanlan1007 4500055
refactor(backups): merged `.map()` + `.unwrap_or()` into `.map_or()`
Nonolanlan1007 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| use std::process::exit; | ||
|
|
||
| use chrono::DateTime; | ||
|
|
||
| use crate::{ | ||
| datastores::{Datastore, DatastoreTrait}, | ||
| utils::{Config, Log}, | ||
| }; | ||
|
|
||
| pub fn inspect(name: String) { | ||
| let config = Config::new(); | ||
| let Some(backup_job) = config | ||
| .backups | ||
| .values() | ||
| .find(|backup_job| backup_job.identifier == name) | ||
| else { | ||
| Log::error("Backup not found"); | ||
| exit(1); | ||
| }; | ||
|
|
||
| let backup_dir_prefix = format!("backup_{name}_"); | ||
| let backups = match &backup_job.datastore { | ||
| Datastore::FileSystem(store) => store | ||
| .list_backups() | ||
| .unwrap_or_default() | ||
| .into_iter() | ||
| .filter_map(|store| { | ||
| let dir_name = store.base_path.file_name()?.to_str()?.to_string(); | ||
|
|
||
| if dir_name.starts_with(&backup_dir_prefix) { | ||
| Some((dir_name, Datastore::FileSystem(store))) | ||
| } else { | ||
| None | ||
| } | ||
| }) | ||
| .collect::<Vec<_>>(), | ||
|
|
||
| Datastore::S3(store) => store | ||
| .list_backups() | ||
| .unwrap_or_default() | ||
| .into_iter() | ||
| .filter_map(|store| { | ||
| let dir_name = store.base_path.file_name()?.to_str()?.to_string(); | ||
|
|
||
| if dir_name.starts_with(&backup_dir_prefix) { | ||
| Some((dir_name, Datastore::S3(store))) | ||
| } else { | ||
| None | ||
| } | ||
| }) | ||
| .collect::<Vec<_>>(), | ||
| }; | ||
|
|
||
| let datastore_type = backup_job.datastore.as_str(); | ||
| let datastore_base_path = match &backup_job.datastore { | ||
| Datastore::FileSystem(store) => store.base_path.display().to_string(), | ||
| Datastore::S3(store) => store.base_path.display().to_string(), | ||
| }; | ||
|
|
||
| println!("-- {} --", backup_job.display_name); | ||
| println!("Datastore:"); | ||
| println!("\tType: {}", datastore_type); | ||
| println!("\tPath: {}", datastore_base_path); | ||
| println!( | ||
| "Schedule: {:?}", | ||
| if let Some(schedule) = backup_job.clone().raw_schedule { | ||
| schedule | ||
| } else { | ||
| "disabled".to_string() | ||
| } | ||
| ); | ||
| if let Some(next) = backup_job.get_next_run() { | ||
| println!("Next run: {:?}", next); | ||
| } | ||
| println!( | ||
| "Encryption: {}", | ||
| if backup_job.is_encryption_enabled() { | ||
| "enabled" | ||
| } else { | ||
| "disabled" | ||
| } | ||
| ); | ||
| println!("Available backups:"); | ||
| for (dir_name, datastore) in backups { | ||
| let health_state = datastore.check_backup_integrity().is_ok_and(|res| res); | ||
| let timestamp = dir_name | ||
| .rsplit("_") | ||
| .next() | ||
| .and_then(|s| s.parse::<i64>().ok()) | ||
| .unwrap_or(0); | ||
| let date = match DateTime::from_timestamp_secs(timestamp) { | ||
| Some(value) => value.to_rfc3339(), | ||
| None => "Unknown date".to_string(), | ||
| }; | ||
| println!( | ||
| "\t{} - {} - {}", | ||
| dir_name, | ||
| date, | ||
| if health_state { "Healthy" } else { "Unhealthy" } | ||
| ) | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| use crate::utils::Config; | ||
| use crate::utils::backup_manager::BackupJob; | ||
|
|
||
| pub fn list() { | ||
| let config = Config::new(); | ||
|
|
||
| if config.backups.is_empty() { | ||
| println!("No backup jobs found") | ||
| } | ||
|
|
||
| let mut backup_jobs: Vec<&BackupJob> = config.backups.values().collect(); | ||
| backup_jobs.sort_by_key(|a| a.get_next_run()); | ||
|
|
||
| for backup_job in backup_jobs { | ||
| println!( | ||
| "- {} - Next run: {:?}", | ||
| backup_job.identifier, | ||
| backup_job.get_next_run() | ||
| ); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,9 @@ | ||
| mod inspect; | ||
| mod list; | ||
| mod restore; | ||
| mod start; | ||
|
|
||
| pub use inspect::inspect; | ||
| pub use list::list; | ||
| pub use restore::restore; | ||
| pub use start::start; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| use std::process::exit; | ||
|
|
||
| use futures::StreamExt; | ||
|
|
||
| use crate::utils::{Config, Log, logger::StreamEvent}; | ||
|
|
||
| pub async fn restore(name: String, target: Option<String>) { | ||
| let config = Config::new(); | ||
| let Some(backup_job) = config | ||
| .backups | ||
| .values() | ||
| .find(|backup_job| name.starts_with(&format!("backup_{}", &backup_job.identifier))) | ||
| else { | ||
| Log::error("Backup not found"); | ||
| exit(1); | ||
| }; | ||
|
|
||
| let mut events = Box::pin(backup_job.restore_backup_to_database(name, target)); | ||
|
|
||
| let mut has_errors = false; | ||
| while let Some(event) = events.next().await { | ||
| if matches!(event, StreamEvent::Error(_)) && !has_errors { | ||
| has_errors = true; | ||
| } | ||
| Log::from_stream_event(event); | ||
| } | ||
|
|
||
| if !has_errors { | ||
| Log::highlight( | ||
| format!( | ||
| "Backup job {} successfully executed", | ||
| backup_job.display_name | ||
| ) | ||
| .as_str(), | ||
| ) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,30 +1,39 @@ | ||
| use std::process::exit; | ||
|
|
||
| use crate::{ | ||
| Daemon, | ||
| utils::{config::Config, logger::Logger}, | ||
| }; | ||
| use futures::StreamExt; | ||
|
|
||
| use crate::utils::{Config, Log, logger::StreamEvent}; | ||
|
|
||
| pub async fn start(name: String) { | ||
| let config = Config::new(); | ||
| let Some((_, backup_config)) = config | ||
| let Some(backup_job) = config | ||
| .backups | ||
| .iter() | ||
| .find(|(backup_name, _)| **backup_name == format!("backup.{name}")) | ||
| .values() | ||
| .find(|backup_job| backup_job.identifier == name) | ||
| else { | ||
| Logger::error("Backup not found"); | ||
| Log::error("Backup not found"); | ||
| exit(1); | ||
| }; | ||
|
|
||
| Logger::info(format!("Starting backup job {}...", backup_config.display_name).as_str()); | ||
| match Daemon::start_backup_job(backup_config).await { | ||
| Ok(_) => Logger::highlight( | ||
| Log::info(format!("Starting backup job {}...", backup_job.display_name).as_str()); | ||
|
|
||
| let mut events = Box::pin(backup_job.execute()); | ||
|
|
||
| let mut has_errors = false; | ||
| while let Some(event) = events.next().await { | ||
| if matches!(event, StreamEvent::Error(_)) && !has_errors { | ||
| has_errors = true; | ||
| } | ||
| Log::from_stream_event(event); | ||
| } | ||
|
|
||
| if !has_errors { | ||
| Log::highlight( | ||
| format!( | ||
| "Backup job {} successfully executed", | ||
| backup_config.display_name | ||
| backup_job.display_name | ||
| ) | ||
| .as_str(), | ||
| ), | ||
| Err(err) => Logger::error(err.as_str()), | ||
| }; | ||
| ) | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.