tape: implement backup using latest-only flag

This commit is contained in:
Dietmar Maurer 2021-02-24 13:37:33 +01:00
parent a941bbd0c9
commit 0dadf66dc7
2 changed files with 45 additions and 15 deletions

View File

@ -143,9 +143,6 @@ pub fn do_tape_backup_job(
set_tape_device_state(&tape_job.drive, &worker.upid().to_string())?; set_tape_device_state(&tape_job.drive, &worker.upid().to_string())?;
job.start(&worker.upid().to_string())?; job.start(&worker.upid().to_string())?;
let eject_media = false;
let export_media_set = false;
task_log!(worker,"Starting tape backup job '{}'", job_id); task_log!(worker,"Starting tape backup job '{}'", job_id);
if let Some(event_str) = schedule { if let Some(event_str) = schedule {
task_log!(worker,"task triggered by schedule '{}'", event_str); task_log!(worker,"task triggered by schedule '{}'", event_str);
@ -156,8 +153,9 @@ pub fn do_tape_backup_job(
datastore, datastore,
&tape_job.drive, &tape_job.drive,
&pool_config, &pool_config,
eject_media, tape_job.eject_media.unwrap_or(false),
export_media_set, tape_job.export_media_set.unwrap_or(false),
tape_job.latest_only.unwrap_or(false),
); );
let status = worker.create_state(&job_result); let status = worker.create_state(&job_result);
@ -233,6 +231,11 @@ pub fn run_tape_backup_job(
type: bool, type: bool,
optional: true, optional: true,
}, },
"latest-only": {
description: "Backup latest snapshots only.",
type: bool,
optional: true,
},
}, },
}, },
returns: { returns: {
@ -246,6 +249,7 @@ pub fn backup(
drive: String, drive: String,
eject_media: Option<bool>, eject_media: Option<bool>,
export_media_set: Option<bool>, export_media_set: Option<bool>,
latest_only: Option<bool>,
rpcenv: &mut dyn RpcEnvironment, rpcenv: &mut dyn RpcEnvironment,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
@ -265,6 +269,7 @@ pub fn backup(
let eject_media = eject_media.unwrap_or(false); let eject_media = eject_media.unwrap_or(false);
let export_media_set = export_media_set.unwrap_or(false); let export_media_set = export_media_set.unwrap_or(false);
let latest_only = latest_only.unwrap_or(false);
let job_id = format!("{}:{}:{}", store, pool, drive); let job_id = format!("{}:{}:{}", store, pool, drive);
@ -276,7 +281,16 @@ pub fn backup(
move |worker| { move |worker| {
let _drive_lock = drive_lock; // keep lock guard let _drive_lock = drive_lock; // keep lock guard
set_tape_device_state(&drive, &worker.upid().to_string())?; set_tape_device_state(&drive, &worker.upid().to_string())?;
backup_worker(&worker, datastore, &drive, &pool_config, eject_media, export_media_set)?; backup_worker(
&worker,
datastore,
&drive,
&pool_config,
eject_media,
export_media_set,
latest_only,
)?;
// ignore errors // ignore errors
let _ = set_tape_device_state(&drive, ""); let _ = set_tape_device_state(&drive, "");
Ok(()) Ok(())
@ -293,6 +307,7 @@ fn backup_worker(
pool_config: &MediaPoolConfig, pool_config: &MediaPoolConfig,
eject_media: bool, eject_media: bool,
export_media_set: bool, export_media_set: bool,
latest_only: bool,
) -> Result<(), Error> { ) -> Result<(), Error> {
let status_path = Path::new(TAPE_STATUS_DIR); let status_path = Path::new(TAPE_STATUS_DIR);
@ -310,10 +325,24 @@ fn backup_worker(
group_list.sort_unstable(); group_list.sort_unstable();
if latest_only {
task_log!(worker, "latest-only: true (only considering latest snapshots)");
}
for group in group_list { for group in group_list {
let mut snapshot_list = group.list_backups(&datastore.base_path())?; let mut snapshot_list = group.list_backups(&datastore.base_path())?;
BackupInfo::sort_list(&mut snapshot_list, true); // oldest first BackupInfo::sort_list(&mut snapshot_list, true); // oldest first
if latest_only {
if let Some(info) = snapshot_list.pop() {
if pool_writer.contains_snapshot(&info.backup_dir.to_string()) {
continue;
}
task_log!(worker, "backup snapshot {}", info.backup_dir);
backup_snapshot(worker, &mut pool_writer, datastore.clone(), info.backup_dir)?;
}
} else {
for info in snapshot_list { for info in snapshot_list {
if pool_writer.contains_snapshot(&info.backup_dir.to_string()) { if pool_writer.contains_snapshot(&info.backup_dir.to_string()) {
continue; continue;
@ -322,6 +351,7 @@ fn backup_worker(
backup_snapshot(worker, &mut pool_writer, datastore.clone(), info.backup_dir)?; backup_snapshot(worker, &mut pool_writer, datastore.clone(), info.backup_dir)?;
} }
} }
}
pool_writer.commit()?; pool_writer.commit()?;

View File

@ -78,11 +78,11 @@ pub struct TapeBackupJobConfig {
pub pool: String, pub pool: String,
pub drive: String, pub drive: String,
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
eject_media: Option<bool>, pub eject_media: Option<bool>,
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
export_media_set: Option<bool>, pub export_media_set: Option<bool>,
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
latest_only: Option<bool>, pub latest_only: Option<bool>,
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
pub comment: Option<String>, pub comment: Option<String>,
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]