file restore: move allow-memory-hotplug param from CLI to environment

avoid the need to loop a parameter through a dozen function which all
don't care about it at all; iff this should be a global oncecell or
lock guarded param.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
Thomas Lamprecht 2022-11-14 15:41:07 +01:00
parent fa1c3eaea1
commit 69e3beb941
3 changed files with 24 additions and 70 deletions

View File

@ -43,7 +43,6 @@ pub trait BlockRestoreDriver {
details: SnapRestoreDetails, details: SnapRestoreDetails,
img_file: String, img_file: String,
path: Vec<u8>, path: Vec<u8>,
auto_memory_hotplug: bool,
) -> Async<Result<Vec<ArchiveEntry>, Error>>; ) -> Async<Result<Vec<ArchiveEntry>, Error>>;
/// pxar=true: /// pxar=true:
@ -58,7 +57,6 @@ pub trait BlockRestoreDriver {
path: Vec<u8>, path: Vec<u8>,
format: Option<FileRestoreFormat>, format: Option<FileRestoreFormat>,
zstd: bool, zstd: bool,
auto_memory_hotplug: bool,
) -> Async<Result<Box<dyn tokio::io::AsyncRead + Unpin + Send>, Error>>; ) -> Async<Result<Box<dyn tokio::io::AsyncRead + Unpin + Send>, Error>>;
/// Return status of all running/mapped images, result value is (id, extra data), where id must /// Return status of all running/mapped images, result value is (id, extra data), where id must
@ -94,12 +92,9 @@ pub async fn data_list(
details: SnapRestoreDetails, details: SnapRestoreDetails,
img_file: String, img_file: String,
path: Vec<u8>, path: Vec<u8>,
auto_memory_hotplug: bool,
) -> Result<Vec<ArchiveEntry>, Error> { ) -> Result<Vec<ArchiveEntry>, Error> {
let driver = driver.unwrap_or(DEFAULT_DRIVER).resolve(); let driver = driver.unwrap_or(DEFAULT_DRIVER).resolve();
driver driver.data_list(details, img_file, path).await
.data_list(details, img_file, path, auto_memory_hotplug)
.await
} }
pub async fn data_extract( pub async fn data_extract(
@ -109,11 +104,10 @@ pub async fn data_extract(
path: Vec<u8>, path: Vec<u8>,
format: Option<FileRestoreFormat>, format: Option<FileRestoreFormat>,
zstd: bool, zstd: bool,
auto_memory_hotplug: bool,
) -> Result<Box<dyn tokio::io::AsyncRead + Send + Unpin>, Error> { ) -> Result<Box<dyn tokio::io::AsyncRead + Send + Unpin>, Error> {
let driver = driver.unwrap_or(DEFAULT_DRIVER).resolve(); let driver = driver.unwrap_or(DEFAULT_DRIVER).resolve();
driver driver
.data_extract(details, img_file, path, format, zstd, auto_memory_hotplug) .data_extract(details, img_file, path, format, zstd)
.await .await
} }

View File

@ -19,7 +19,7 @@ use pbs_datastore::catalog::ArchiveEntry;
use super::block_driver::*; use super::block_driver::*;
use crate::get_user_run_dir; use crate::get_user_run_dir;
use crate::qemu_helper::set_auto_memory_hotplug; use crate::qemu_helper;
const RESTORE_VM_MAP: &str = "restore-vm-map.json"; const RESTORE_VM_MAP: &str = "restore-vm-map.json";
@ -198,6 +198,20 @@ fn path_is_zfs(path: &[u8]) -> bool {
part == OsStr::new("zpool") && components.next().is_some() part == OsStr::new("zpool") && components.next().is_some()
} }
async fn handle_extra_guest_memory_needs(cid: i32, path: &[u8]) {
use std::env::var;
match var("PBS_FILE_RESTORE_MEM_HOTPLUG_ALLOW").ok().as_deref() {
Some("true") => (),
_ => return, // this is opt-in
}
if path_is_zfs(path) {
if let Err(err) = qemu_helper::set_dynamic_memory(cid, None).await {
log::error!("could not increase memory: {err}");
}
}
}
async fn start_vm(cid_request: i32, details: &SnapRestoreDetails) -> Result<VMState, Error> { async fn start_vm(cid_request: i32, details: &SnapRestoreDetails) -> Result<VMState, Error> {
let ticket = new_ticket(); let ticket = new_ticket();
let files = details let files = details
@ -218,18 +232,13 @@ impl BlockRestoreDriver for QemuBlockDriver {
details: SnapRestoreDetails, details: SnapRestoreDetails,
img_file: String, img_file: String,
mut path: Vec<u8>, mut path: Vec<u8>,
auto_memory_hotplug: bool,
) -> Async<Result<Vec<ArchiveEntry>, Error>> { ) -> Async<Result<Vec<ArchiveEntry>, Error>> {
async move { async move {
let (cid, client) = ensure_running(&details).await?; let (cid, client) = ensure_running(&details).await?;
if !path.is_empty() && path[0] != b'/' { if !path.is_empty() && path[0] != b'/' {
path.insert(0, b'/'); path.insert(0, b'/');
} }
if path_is_zfs(&path) && auto_memory_hotplug { handle_extra_guest_memory_needs(cid, &path).await;
if let Err(err) = set_auto_memory_hotplug(cid, None).await {
log::error!("could not increase memory: {err}");
}
}
let path = base64::encode(img_file.bytes().chain(path).collect::<Vec<u8>>()); let path = base64::encode(img_file.bytes().chain(path).collect::<Vec<u8>>());
let mut result = client let mut result = client
.get("api2/json/list", Some(json!({ "path": path }))) .get("api2/json/list", Some(json!({ "path": path })))
@ -246,18 +255,13 @@ impl BlockRestoreDriver for QemuBlockDriver {
mut path: Vec<u8>, mut path: Vec<u8>,
format: Option<FileRestoreFormat>, format: Option<FileRestoreFormat>,
zstd: bool, zstd: bool,
auto_memory_hotplug: bool,
) -> Async<Result<Box<dyn tokio::io::AsyncRead + Unpin + Send>, Error>> { ) -> Async<Result<Box<dyn tokio::io::AsyncRead + Unpin + Send>, Error>> {
async move { async move {
let (cid, client) = ensure_running(&details).await?; let (cid, client) = ensure_running(&details).await?;
if !path.is_empty() && path[0] != b'/' { if !path.is_empty() && path[0] != b'/' {
path.insert(0, b'/'); path.insert(0, b'/');
} }
if path_is_zfs(&path) && auto_memory_hotplug { handle_extra_guest_memory_needs(cid, &path).await;
if let Err(err) = set_auto_memory_hotplug(cid, None).await {
log::error!("could not increase memory: {err}");
}
}
let path = base64::encode(img_file.bytes().chain(path).collect::<Vec<u8>>()); let path = base64::encode(img_file.bytes().chain(path).collect::<Vec<u8>>());
let (mut tx, rx) = tokio::io::duplex(1024 * 4096); let (mut tx, rx) = tokio::io::duplex(1024 * 4096);
let mut data = json!({ "path": path, "zstd": zstd }); let mut data = json!({ "path": path, "zstd": zstd });

View File

@ -96,7 +96,6 @@ fn keyfile_path(param: &Value) -> Option<String> {
None None
} }
#[allow(clippy::too_many_arguments)]
async fn list_files( async fn list_files(
repo: BackupRepository, repo: BackupRepository,
namespace: BackupNamespace, namespace: BackupNamespace,
@ -105,7 +104,6 @@ async fn list_files(
crypt_config: Option<Arc<CryptConfig>>, crypt_config: Option<Arc<CryptConfig>>,
keyfile: Option<String>, keyfile: Option<String>,
driver: Option<BlockDriverType>, driver: Option<BlockDriverType>,
auto_memory_hotplug: bool,
) -> Result<Vec<ArchiveEntry>, Error> { ) -> Result<Vec<ArchiveEntry>, Error> {
let client = connect(&repo)?; let client = connect(&repo)?;
let client = BackupReader::start( let client = BackupReader::start(
@ -172,7 +170,7 @@ async fn list_files(
snapshot, snapshot,
keyfile, keyfile,
}; };
data_list(driver, details, file, path, auto_memory_hotplug).await data_list(driver, details, file, path).await
} }
} }
} }
@ -228,12 +226,6 @@ async fn list_files(
minimum: 1, minimum: 1,
optional: true, optional: true,
}, },
"auto-memory-hotplug": {
type: Boolean,
description: "If enabled, automatically hot-plugs memory for started VM if a ZFS pool is accessed.",
default: false,
optional: true,
},
} }
}, },
returns: { returns: {
@ -251,7 +243,6 @@ async fn list(
path: String, path: String,
base64: bool, base64: bool,
timeout: Option<u64>, timeout: Option<u64>,
auto_memory_hotplug: bool,
param: Value, param: Value,
) -> Result<(), Error> { ) -> Result<(), Error> {
let repo = extract_repository_from_value(&param)?; let repo = extract_repository_from_value(&param)?;
@ -281,16 +272,7 @@ async fn list(
let result = if let Some(timeout) = timeout { let result = if let Some(timeout) = timeout {
match tokio::time::timeout( match tokio::time::timeout(
std::time::Duration::from_secs(timeout), std::time::Duration::from_secs(timeout),
list_files( list_files(repo, ns, snapshot, path, crypt_config, keyfile, driver),
repo,
ns,
snapshot,
path,
crypt_config,
keyfile,
driver,
auto_memory_hotplug,
),
) )
.await .await
{ {
@ -298,17 +280,7 @@ async fn list(
Err(_) => Err(http_err!(SERVICE_UNAVAILABLE, "list not finished in time")), Err(_) => Err(http_err!(SERVICE_UNAVAILABLE, "list not finished in time")),
} }
} else { } else {
list_files( list_files(repo, ns, snapshot, path, crypt_config, keyfile, driver).await
repo,
ns,
snapshot,
path,
crypt_config,
keyfile,
driver,
auto_memory_hotplug,
)
.await
}; };
let output_format = get_output_format(&param); let output_format = get_output_format(&param);
@ -415,12 +387,6 @@ async fn list(
type: BlockDriverType, type: BlockDriverType,
optional: true, optional: true,
}, },
"auto-memory-hotplug": {
type: Boolean,
description: "If enabled, automatically hot-plugs memory for started VM if a ZFS pool is accessed.",
default: false,
optional: true,
},
} }
} }
)] )]
@ -434,7 +400,6 @@ async fn extract(
target: Option<String>, target: Option<String>,
format: Option<FileRestoreFormat>, format: Option<FileRestoreFormat>,
zstd: bool, zstd: bool,
auto_memory_hotplug: bool,
param: Value, param: Value,
) -> Result<(), Error> { ) -> Result<(), Error> {
let repo = extract_repository_from_value(&param)?; let repo = extract_repository_from_value(&param)?;
@ -516,7 +481,6 @@ async fn extract(
path.clone(), path.clone(),
Some(FileRestoreFormat::Pxar), Some(FileRestoreFormat::Pxar),
false, false,
auto_memory_hotplug,
) )
.await?; .await?;
let decoder = Decoder::from_tokio(reader).await?; let decoder = Decoder::from_tokio(reader).await?;
@ -529,16 +493,8 @@ async fn extract(
format_err!("unable to remove temporary .pxarexclude-cli file - {}", e) format_err!("unable to remove temporary .pxarexclude-cli file - {}", e)
})?; })?;
} else { } else {
let mut reader = data_extract( let mut reader =
driver, data_extract(driver, details, file, path.clone(), format, zstd).await?;
details,
file,
path.clone(),
format,
zstd,
auto_memory_hotplug,
)
.await?;
tokio::io::copy(&mut reader, &mut tokio::io::stdout()).await?; tokio::io::copy(&mut reader, &mut tokio::io::stdout()).await?;
} }
} }