mirror of
https://git.ahines.net/joeyahines/Albatross.git
synced 2026-11-08 09:13:57 +00:00
First pass on adding remote backups
+ Added remote_backup.rs to handle remote backup logic + Added `remote` section to the config for optional remote backup setup + Using ssh2 rust library for SFTP support + small tweaks
This commit is contained in:
6 files changed
+193
-21
No files matched your search
+36
-20
@@ -2,6 +2,7 @@ use crate::backup;
|
||||
use crate::config::{AlbatrossConfig, WorldConfig, WorldType};
|
||||
use crate::discord::send_webhook;
|
||||
use crate::region::Region;
|
||||
use crate::remote_backup::remote_backup;
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
use flate2::read::GzDecoder;
|
||||
use flate2::write::GzEncoder;
|
||||
@@ -321,8 +322,42 @@ pub fn do_backup(cfg: AlbatrossConfig, output: Option<PathBuf>) -> Result<(), st
|
||||
|
||||
create_dir_all(tmp_dir.clone()).unwrap();
|
||||
|
||||
send_webhook("**Albatross is swooping in to backup your worlds!**", &cfg);
|
||||
let timer = Instant::now();
|
||||
backup_worlds(&cfg, server_base_dir, worlds, &mut tmp_dir)?;
|
||||
|
||||
backup::compress_backup(&tmp_dir, &output_archive)?;
|
||||
|
||||
remove_dir_all(&tmp_dir)?;
|
||||
|
||||
let backups_removed = remove_old_backups(&cfg.backup.output_dir, cfg.backup.backups_to_keep)?;
|
||||
|
||||
if backups_removed > 0 {
|
||||
let msg = format!(
|
||||
"Albatross mistook **{}** of your old backups for some french fries and ate them!! SKRAWWWW",
|
||||
backups_removed
|
||||
);
|
||||
send_webhook(msg.as_str(), &cfg);
|
||||
}
|
||||
|
||||
if let Some(remote_backup_cfg) = &cfg.remote {
|
||||
remote_backup(output_archive, remote_backup_cfg);
|
||||
}
|
||||
|
||||
let secs = timer.elapsed().as_secs();
|
||||
send_webhook(
|
||||
format!("**Full backup completed in {}s**! *SKREEEEEEEEEE*", secs).as_str(),
|
||||
&cfg,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn backup_worlds(
|
||||
cfg: &AlbatrossConfig,
|
||||
server_base_dir: PathBuf,
|
||||
worlds: Vec<WorldConfig>,
|
||||
tmp_dir: &mut PathBuf,
|
||||
) -> Result<(), std::io::Error> {
|
||||
send_webhook("**Albatross is swooping in to backup your worlds!**", &cfg);
|
||||
for world in worlds {
|
||||
let mut world_dir = server_base_dir.clone();
|
||||
let world_name = world.world_name.clone();
|
||||
@@ -363,24 +398,5 @@ pub fn do_backup(cfg: AlbatrossConfig, output: Option<PathBuf>) -> Result<(), st
|
||||
}
|
||||
}
|
||||
|
||||
backup::compress_backup(&tmp_dir, &output_archive)?;
|
||||
|
||||
remove_dir_all(&tmp_dir)?;
|
||||
|
||||
let backups_removed = remove_old_backups(&cfg.backup.output_dir, cfg.backup.backups_to_keep)?;
|
||||
|
||||
if backups_removed > 0 {
|
||||
let msg = format!(
|
||||
"Albatross mistook **{}** of your old backups for some french fries and ate them!! SKRAWWWW",
|
||||
backups_removed
|
||||
);
|
||||
send_webhook(msg.as_str(), &cfg);
|
||||
}
|
||||
|
||||
let secs = timer.elapsed().as_secs();
|
||||
send_webhook(
|
||||
format!("**Full backup completed in {}s**! *SKREEEEEEEEEE*", secs).as_str(),
|
||||
&cfg,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
+21
-1
@@ -24,7 +24,7 @@ impl From<String> for WorldType {
|
||||
}
|
||||
}
|
||||
|
||||
/// Config for individual WorldConfig
|
||||
/// Config for individual world configuration
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct WorldConfig {
|
||||
pub world_name: String,
|
||||
@@ -41,11 +41,31 @@ pub struct BackupConfig {
|
||||
pub discord_webhook: Option<String>,
|
||||
}
|
||||
|
||||
/// Config for remote backups
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct RemoteBackupConfig {
|
||||
/// Remote server address
|
||||
pub sftp_server_addr: String,
|
||||
/// Remote output directory
|
||||
pub remote_dir: PathBuf,
|
||||
/// Remote server username
|
||||
pub username: String,
|
||||
/// Public key for key auth
|
||||
pub public_key: Option<PathBuf>,
|
||||
/// Private key for key auth
|
||||
pub private_key: Option<PathBuf>,
|
||||
/// Password if using password auth
|
||||
pub password: Option<String>,
|
||||
/// Remote backups to keep
|
||||
pub backups_to_keep: u64,
|
||||
}
|
||||
|
||||
/// Configs
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct AlbatrossConfig {
|
||||
pub backup: BackupConfig,
|
||||
pub world_config: Option<Vec<WorldConfig>>,
|
||||
pub remote: Option<RemoteBackupConfig>,
|
||||
}
|
||||
|
||||
impl AlbatrossConfig {
|
||||
|
||||
@@ -6,6 +6,7 @@ mod chunk_coordinate;
|
||||
mod config;
|
||||
mod discord;
|
||||
mod region;
|
||||
mod remote_backup;
|
||||
mod restore;
|
||||
|
||||
use crate::backup::{convert_backup_to_sp, do_backup};
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
use crate::config::RemoteBackupConfig;
|
||||
use ssh2::Session;
|
||||
use std::net::TcpStream;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn open_ssh_session(remote_config: &RemoteBackupConfig) -> Session {
|
||||
let tcp = TcpStream::connect(&remote_config.sftp_server_addr).unwrap();
|
||||
let mut sess = Session::new().unwrap();
|
||||
sess.set_tcp_stream(tcp);
|
||||
sess.handshake().unwrap();
|
||||
|
||||
if let Some(password) = &remote_config.password {
|
||||
sess.userauth_password(&remote_config.username, password)
|
||||
.unwrap();
|
||||
} else if let Some(key) = &remote_config.private_key {
|
||||
let public_key =
|
||||
remote_config
|
||||
.public_key
|
||||
.as_ref()
|
||||
.map(|pub_key| pub_key.as_path().clone());
|
||||
sess.userauth_pubkey_file(
|
||||
&remote_config.username,
|
||||
public_key,
|
||||
key,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
panic!("No key provided")
|
||||
}
|
||||
|
||||
sess
|
||||
}
|
||||
|
||||
pub fn remote_backup(file: PathBuf, remote_config: &RemoteBackupConfig) {
|
||||
let sess = open_ssh_session(remote_config);
|
||||
|
||||
let remote_path = remote_config.remote_dir.join(file.file_name().unwrap());
|
||||
|
||||
let mut local_file = std::fs::File::open(&file).unwrap();
|
||||
|
||||
let sftp = sess.sftp().unwrap();
|
||||
|
||||
let mut remote_file = sftp.create(&remote_path).unwrap();
|
||||
|
||||
std::io::copy(&mut local_file, &mut remote_file).unwrap();
|
||||
}
|
||||
Reference in new issue
Block a user