proxmox-backup/src/api3/admin/datastore/upload_catar.rs

108 lines
3.2 KiB
Rust
Raw Normal View History

use failure::*;
use crate::tools;
use crate::backup::datastore::*;
use crate::backup::archive_index::*;
2019-01-16 09:19:49 +00:00
//use crate::server::rest::*;
use crate::api::schema::*;
use crate::api::router::*;
2019-01-16 09:19:49 +00:00
use serde_json::Value;
use std::io::Write;
use futures::*;
use std::path::PathBuf;
use std::sync::Arc;
use hyper::Body;
use hyper::http::request::Parts;
pub struct UploadCaTar {
stream: Body,
index: ArchiveIndexWriter,
count: usize,
}
impl Future for UploadCaTar {
type Item = ();
type Error = failure::Error;
fn poll(&mut self) -> Poll<(), failure::Error> {
loop {
match try_ready!(self.stream.poll()) {
Some(chunk) => {
self.count += chunk.len();
if let Err(err) = self.index.write(&chunk) {
bail!("writing chunk failed - {}", err);
}
}
None => {
2019-01-16 09:19:49 +00:00
self.index.close()?;
return Ok(Async::Ready(()))
}
}
}
}
}
fn upload_catar(parts: Parts, req_body: Body, param: Value, _info: &ApiUploadMethod) -> Result<BoxFut, Error> {
let store = tools::required_string_param(&param, "store")?;
let archive_name = tools::required_string_param(&param, "archive_name")?;
let backup_type = tools::required_string_param(&param, "type")?;
let backup_id = tools::required_string_param(&param, "id")?;
let backup_time = tools::required_integer_param(&param, "time")?;
println!("Upload {}.catar to {} ({}/{}/{}/{}.aidx)", archive_name, store,
backup_type, backup_id, backup_time, archive_name);
let content_type = parts.headers.get(http::header::CONTENT_TYPE)
.ok_or(format_err!("missing content-type header"))?;
if content_type != "application/x-proxmox-backup-catar" {
bail!("got wrong content-type for catar archive upload");
}
let chunk_size = 4*1024*1024;
let datastore = DataStore::lookup_datastore(store)?;
let mut path = datastore.create_backup_dir(backup_type, backup_id, backup_time)?;
let mut full_archive_name = PathBuf::from(archive_name);
full_archive_name.set_extension("aidx");
path.push(full_archive_name);
let index = datastore.create_archive_writer(path, chunk_size).unwrap();
let upload = UploadCaTar { stream: req_body, index, count: 0};
2019-01-16 09:19:49 +00:00
let resp = upload.and_then(|_| {
let response = http::Response::builder()
.status(200)
.body(hyper::Body::empty())
.unwrap();
Ok(response)
});
Ok(Box::new(resp))
}
pub fn api_method_upload_catar() -> ApiUploadMethod {
ApiUploadMethod::new(
upload_catar,
ObjectSchema::new("Upload .catar backup file.")
.required("store", StringSchema::new("Datastore name."))
.required("archive_name", StringSchema::new("Backup archive name."))
.required("type", StringSchema::new("Backup type.")
.format(Arc::new(ApiStringFormat::Enum(vec!["ct".into(), "host".into()]))))
.required("id", StringSchema::new("Backup ID."))
.required("time", IntegerSchema::new("Backup time (Unix epoch.)")
.minimum(1547797308))
)
}