-use failure::*;
+use anyhow::{bail, format_err, Error};
use futures::*;
use hyper::header::{HeaderValue, UPGRADE};
use hyper::http::request::Parts;
use serde_json::{json, Value};
use proxmox::{sortable, identity, list_subdirs_api_method};
-use proxmox::api::{ApiResponseFuture, ApiHandler, ApiMethod, Router, RpcEnvironment};
+use proxmox::api::{ApiResponseFuture, ApiHandler, ApiMethod, Router, RpcEnvironment, Permission};
use proxmox::api::router::SubdirMap;
use proxmox::api::schema::*;
use crate::server::{WorkerTask, H2Service};
use crate::backup::*;
use crate::api2::types::*;
+use crate::config::acl::PRIV_DATASTORE_BACKUP;
+use crate::config::cached_user_info::CachedUserInfo;
mod environment;
use environment::*;
("debug", true, &BooleanSchema::new("Enable verbose debug logging.").schema()),
]),
)
+).access(
+ // Note: parameter 'store' is no uri parameter, so we need to test inside function body
+ Some("The user needs Datastore.Backup privilege on /datastore/{store} and needs to own the backup group."),
+ &Permission::Anybody
);
fn upgrade_to_backup_protocol(
rpcenv: Box<dyn RpcEnvironment>,
) -> ApiResponseFuture {
- async move {
+async move {
let debug = param["debug"].as_bool().unwrap_or(false);
+ let username = rpcenv.get_user().unwrap();
+
let store = tools::required_string_param(¶m, "store")?.to_owned();
+
+ let user_info = CachedUserInfo::new()?;
+ user_info.check_privs(&username, &["datastore", &store], PRIV_DATASTORE_BACKUP, false)?;
+
let datastore = DataStore::lookup_datastore(&store)?;
let backup_type = tools::required_string_param(¶m, "backup-type")?;
let worker_id = format!("{}_{}_{}", store, backup_type, backup_id);
- let username = rpcenv.get_user().unwrap();
let env_type = rpcenv.env_type();
let backup_group = BackupGroup::new(backup_type, backup_id);
+ let owner = datastore.create_backup_group(&backup_group, &username)?;
+ // permission check
+ if owner != username { // only the owner is allowed to create additional snapshots
+ bail!("backup owner check failed ({} != {})", username, owner);
+ }
+
let last_backup = BackupInfo::last_backup(&datastore.base_path(), &backup_group).unwrap_or(None);
let backup_dir = BackupDir::new_with_group(backup_group, backup_time);
}
let (path, is_new) = datastore.create_backup_dir(&backup_dir)?;
- if !is_new { bail!("backup directorty already exists."); }
+ if !is_new { bail!("backup directory already exists."); }
WorkerTask::spawn("backup", Some(worker_id), &username.clone(), true, move |worker| {
let mut env = BackupEnvironment::new(
match (res, env.ensure_finished()) {
(Ok(_), Ok(())) => {
- env.log("backup finished sucessfully");
+ env.log("backup finished successfully");
Ok(())
},
(Err(err), Ok(())) => {
env.dynamic_writer_append_chunk(wid, offset, size, &digest)?;
- env.debug(format!("sucessfully added chunk {} to dynamic index {} (offset {}, size {})", digest_str, wid, offset, size));
+ env.debug(format!("successfully added chunk {} to dynamic index {} (offset {}, size {})", digest_str, wid, offset, size));
}
Ok(Value::Null)
env.fixed_writer_append_chunk(wid, offset, size, &digest)?;
- env.debug(format!("sucessfully added chunk {} to fixed index {} (offset {}, size {})", digest_str, wid, offset, size));
+ env.debug(format!("successfully added chunk {} to fixed index {} (offset {}, size {})", digest_str, wid, offset, size));
}
Ok(Value::Null)
env.dynamic_writer_close(wid, chunk_count, size, csum)?;
- env.log(format!("sucessfully closed dynamic index {}", wid));
+ env.log(format!("successfully closed dynamic index {}", wid));
Ok(Value::Null)
}
env.fixed_writer_close(wid, chunk_count, size, csum)?;
- env.log(format!("sucessfully closed fixed index {}", wid));
+ env.log(format!("successfully closed fixed index {}", wid));
Ok(Value::Null)
}
let env: &BackupEnvironment = rpcenv.as_ref();
env.finish_backup()?;
- env.log("sucessfully finished backup");
+ env.log("successfully finished backup");
Ok(Value::Null)
}