src/api2/admin/datastore/backup.rs: implement config file upload
This commit is contained in:
parent
1c0472e88f
commit
39d6846e1e
@ -150,6 +150,10 @@ fn upgrade_to_backup_protocol(
|
|||||||
fn backup_api() -> Router {
|
fn backup_api() -> Router {
|
||||||
|
|
||||||
let router = Router::new()
|
let router = Router::new()
|
||||||
|
.subdir(
|
||||||
|
"config", Router::new()
|
||||||
|
.upload(api_method_upload_config())
|
||||||
|
)
|
||||||
.subdir(
|
.subdir(
|
||||||
"dynamic_chunk", Router::new()
|
"dynamic_chunk", Router::new()
|
||||||
.upload(api_method_upload_dynamic_chunk())
|
.upload(api_method_upload_dynamic_chunk())
|
||||||
|
@ -185,3 +185,65 @@ fn upload_speedtest(
|
|||||||
|
|
||||||
Ok(Box::new(resp))
|
Ok(Box::new(resp))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn api_method_upload_config() -> ApiAsyncMethod {
|
||||||
|
ApiAsyncMethod::new(
|
||||||
|
upload_config,
|
||||||
|
ObjectSchema::new("Upload configuration file.")
|
||||||
|
.required("file-name", crate::api2::types::BACKUP_ARCHIVE_NAME_SCHEMA.clone())
|
||||||
|
.required("size", IntegerSchema::new("File size.")
|
||||||
|
.minimum(1)
|
||||||
|
.maximum(1024*1024*16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_config(
|
||||||
|
_parts: Parts,
|
||||||
|
req_body: Body,
|
||||||
|
param: Value,
|
||||||
|
_info: &ApiAsyncMethod,
|
||||||
|
rpcenv: Box<RpcEnvironment>,
|
||||||
|
) -> Result<BoxFut, Error> {
|
||||||
|
|
||||||
|
let mut file_name = tools::required_string_param(¶m, "file-name")?.to_owned();
|
||||||
|
let size = tools::required_integer_param(¶m, "size")? as usize;
|
||||||
|
|
||||||
|
if !file_name.ends_with(".conf") {
|
||||||
|
bail!("wrong config file extension: '{}'", file_name);
|
||||||
|
} else {
|
||||||
|
file_name.push_str(".zstd");
|
||||||
|
}
|
||||||
|
|
||||||
|
let env: &BackupEnvironment = rpcenv.as_ref();
|
||||||
|
|
||||||
|
let mut path = env.datastore.base_path();
|
||||||
|
path.push(env.backup_dir.relative_path());
|
||||||
|
path.push(&file_name);
|
||||||
|
|
||||||
|
let env2 = env.clone();
|
||||||
|
let env3 = env.clone();
|
||||||
|
|
||||||
|
let resp = req_body
|
||||||
|
.map_err(Error::from)
|
||||||
|
.concat2()
|
||||||
|
.and_then(move |data| {
|
||||||
|
if size != data.len() {
|
||||||
|
bail!("got configuration file with unexpected length ({} != {})", size, data.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = zstd::block::compress(&data, 0)?;
|
||||||
|
|
||||||
|
tools::file_set_contents(&path, &data, None)?;
|
||||||
|
|
||||||
|
env2.debug(format!("upload config {:?} ({} bytes, comp: {})", path, size, data.len()));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.and_then(move |_| {
|
||||||
|
Ok(env3.format_response(Ok(Value::Null)))
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
Ok(Box::new(resp))
|
||||||
|
}
|
||||||
|
@ -431,6 +431,31 @@ impl BackupClient {
|
|||||||
self.h2.clone().post("finish", None).map(|_| ())
|
self.h2.clone().post("finish", None).map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn upload_config(
|
||||||
|
&self,
|
||||||
|
file_name: &str,
|
||||||
|
src_path: std::path::PathBuf,
|
||||||
|
) -> impl Future<Item=(), Error=Error> {
|
||||||
|
|
||||||
|
let h2 = self.h2.clone();
|
||||||
|
let file_name = file_name.to_owned();
|
||||||
|
|
||||||
|
let task = tokio::fs::File::open(src_path)
|
||||||
|
.map_err(Error::from)
|
||||||
|
.and_then(|file| {
|
||||||
|
let contents = vec![];
|
||||||
|
tokio::io::read_to_end(file, contents)
|
||||||
|
.map_err(Error::from)
|
||||||
|
.and_then(move |(_, contents)| {
|
||||||
|
let param = json!({"size": contents.len(), "file-name": file_name });
|
||||||
|
h2.upload("config", Some(param), contents)
|
||||||
|
.map(|_| {})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
task
|
||||||
|
}
|
||||||
|
|
||||||
pub fn upload_stream(
|
pub fn upload_stream(
|
||||||
&self,
|
&self,
|
||||||
archive_name: &str,
|
archive_name: &str,
|
||||||
|
Loading…
Reference in New Issue
Block a user