file-restore: add debug mode with serial access
Set PBS_QEMU_DEBUG=1 on a command that starts a VM and then connect to the debug root shell via: minicom -D \unix#/run/proxmox-backup/file-restore-serial-10.sock or similar. Note that this requires 'proxmox-backup-restore-image-debug' to work, the postinst script is updated to also generate the corresponding image. Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
This commit is contained in:
parent
5e91b40087
commit
572cd0381b
|
@ -6,6 +6,7 @@ update_initramfs() {
|
||||||
# regenerate initramfs for single file restore VM
|
# regenerate initramfs for single file restore VM
|
||||||
INST_PATH="/usr/lib/x86_64-linux-gnu/proxmox-backup/file-restore"
|
INST_PATH="/usr/lib/x86_64-linux-gnu/proxmox-backup/file-restore"
|
||||||
CACHE_PATH="/var/cache/proxmox-backup/file-restore-initramfs.img"
|
CACHE_PATH="/var/cache/proxmox-backup/file-restore-initramfs.img"
|
||||||
|
CACHE_PATH_DBG="/var/cache/proxmox-backup/file-restore-initramfs-debug.img"
|
||||||
|
|
||||||
# cleanup first, in case proxmox-file-restore was uninstalled since we do
|
# cleanup first, in case proxmox-file-restore was uninstalled since we do
|
||||||
# not want an unuseable image lying around
|
# not want an unuseable image lying around
|
||||||
|
@ -20,7 +21,7 @@ update_initramfs() {
|
||||||
|
|
||||||
# avoid leftover temp file
|
# avoid leftover temp file
|
||||||
cleanup() {
|
cleanup() {
|
||||||
rm -f "$CACHE_PATH.tmp"
|
rm -f "$CACHE_PATH.tmp" "$CACHE_PATH_DBG.tmp"
|
||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
@ -34,6 +35,15 @@ update_initramfs() {
|
||||||
| cpio -o --format=newc -A -F "$CACHE_PATH.tmp" )
|
| cpio -o --format=newc -A -F "$CACHE_PATH.tmp" )
|
||||||
mv -f "$CACHE_PATH.tmp" "$CACHE_PATH"
|
mv -f "$CACHE_PATH.tmp" "$CACHE_PATH"
|
||||||
|
|
||||||
|
if [ -f "$INST_PATH/initramfs-debug.img" ]; then
|
||||||
|
echo "Updating file-restore debug initramfs..."
|
||||||
|
cp "$INST_PATH/initramfs-debug.img" "$CACHE_PATH_DBG.tmp"
|
||||||
|
( cd "$INST_PATH"; \
|
||||||
|
printf "./proxmox-restore-daemon" \
|
||||||
|
| cpio -o --format=newc -A -F "$CACHE_PATH_DBG.tmp" )
|
||||||
|
mv -f "$CACHE_PATH_DBG.tmp" "$CACHE_PATH_DBG"
|
||||||
|
fi
|
||||||
|
|
||||||
trap - EXIT
|
trap - EXIT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,9 +47,13 @@ fn create_restore_log_dir() -> Result<String, Error> {
|
||||||
Ok(logpath)
|
Ok(logpath)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_img_existance() -> Result<(), Error> {
|
fn validate_img_existance(debug: bool) -> Result<(), Error> {
|
||||||
let kernel = PathBuf::from(buildcfg::PROXMOX_BACKUP_KERNEL_FN);
|
let kernel = PathBuf::from(buildcfg::PROXMOX_BACKUP_KERNEL_FN);
|
||||||
let initramfs = PathBuf::from(buildcfg::PROXMOX_BACKUP_INITRAMFS_FN);
|
let initramfs = PathBuf::from(if debug {
|
||||||
|
buildcfg::PROXMOX_BACKUP_INITRAMFS_DBG_FN
|
||||||
|
} else {
|
||||||
|
buildcfg::PROXMOX_BACKUP_INITRAMFS_FN
|
||||||
|
});
|
||||||
if !kernel.exists() || !initramfs.exists() {
|
if !kernel.exists() || !initramfs.exists() {
|
||||||
bail!("cannot run file-restore VM: package 'proxmox-backup-restore-image' is not (correctly) installed");
|
bail!("cannot run file-restore VM: package 'proxmox-backup-restore-image' is not (correctly) installed");
|
||||||
}
|
}
|
||||||
|
@ -79,7 +83,7 @@ pub fn try_kill_vm(pid: i32) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_temp_initramfs(ticket: &str) -> Result<(Fd, String), Error> {
|
async fn create_temp_initramfs(ticket: &str, debug: bool) -> Result<(Fd, String), Error> {
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
|
|
||||||
|
@ -88,8 +92,14 @@ async fn create_temp_initramfs(ticket: &str) -> Result<(Fd, String), Error> {
|
||||||
nix::unistd::unlink(&tmp_path)?;
|
nix::unistd::unlink(&tmp_path)?;
|
||||||
tools::fd_change_cloexec(tmp_fd.0, false)?;
|
tools::fd_change_cloexec(tmp_fd.0, false)?;
|
||||||
|
|
||||||
|
let initramfs = if debug {
|
||||||
|
buildcfg::PROXMOX_BACKUP_INITRAMFS_DBG_FN
|
||||||
|
} else {
|
||||||
|
buildcfg::PROXMOX_BACKUP_INITRAMFS_FN
|
||||||
|
};
|
||||||
|
|
||||||
let mut f = File::from_std(unsafe { std::fs::File::from_raw_fd(tmp_fd.0) });
|
let mut f = File::from_std(unsafe { std::fs::File::from_raw_fd(tmp_fd.0) });
|
||||||
let mut base = File::open(buildcfg::PROXMOX_BACKUP_INITRAMFS_FN).await?;
|
let mut base = File::open(initramfs).await?;
|
||||||
|
|
||||||
tokio::io::copy(&mut base, &mut f).await?;
|
tokio::io::copy(&mut base, &mut f).await?;
|
||||||
|
|
||||||
|
@ -122,18 +132,24 @@ pub async fn start_vm(
|
||||||
files: impl Iterator<Item = String>,
|
files: impl Iterator<Item = String>,
|
||||||
ticket: &str,
|
ticket: &str,
|
||||||
) -> Result<(i32, i32), Error> {
|
) -> Result<(i32, i32), Error> {
|
||||||
validate_img_existance()?;
|
|
||||||
|
|
||||||
if let Err(_) = std::env::var("PBS_PASSWORD") {
|
if let Err(_) = std::env::var("PBS_PASSWORD") {
|
||||||
bail!("environment variable PBS_PASSWORD has to be set for QEMU VM restore");
|
bail!("environment variable PBS_PASSWORD has to be set for QEMU VM restore");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let debug = if let Ok(val) = std::env::var("PBS_QEMU_DEBUG") {
|
||||||
|
!val.is_empty()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
validate_img_existance(debug)?;
|
||||||
|
|
||||||
let pid;
|
let pid;
|
||||||
let (pid_fd, pid_path) = make_tmp_file("/tmp/file-restore-qemu.pid.tmp", CreateOptions::new())?;
|
let (pid_fd, pid_path) = make_tmp_file("/tmp/file-restore-qemu.pid.tmp", CreateOptions::new())?;
|
||||||
nix::unistd::unlink(&pid_path)?;
|
nix::unistd::unlink(&pid_path)?;
|
||||||
tools::fd_change_cloexec(pid_fd.0, false)?;
|
tools::fd_change_cloexec(pid_fd.0, false)?;
|
||||||
|
|
||||||
let (_ramfs_pid, ramfs_path) = create_temp_initramfs(ticket).await?;
|
let (_ramfs_pid, ramfs_path) = create_temp_initramfs(ticket, debug).await?;
|
||||||
|
|
||||||
let logpath = create_restore_log_dir()?;
|
let logpath = create_restore_log_dir()?;
|
||||||
let logfile = &format!("{}/qemu.log", logpath);
|
let logfile = &format!("{}/qemu.log", logpath);
|
||||||
|
@ -172,7 +188,11 @@ pub async fn start_vm(
|
||||||
"-initrd",
|
"-initrd",
|
||||||
&ramfs_path,
|
&ramfs_path,
|
||||||
"-append",
|
"-append",
|
||||||
"quiet panic=1",
|
if debug {
|
||||||
|
"debug panic=1"
|
||||||
|
} else {
|
||||||
|
"quiet panic=1"
|
||||||
|
},
|
||||||
"-daemonize",
|
"-daemonize",
|
||||||
"-pidfile",
|
"-pidfile",
|
||||||
&format!("/dev/fd/{}", pid_fd.as_raw_fd()),
|
&format!("/dev/fd/{}", pid_fd.as_raw_fd()),
|
||||||
|
@ -240,6 +260,19 @@ pub async fn start_vm(
|
||||||
cid
|
cid
|
||||||
));
|
));
|
||||||
|
|
||||||
|
if debug {
|
||||||
|
let debug_args = [
|
||||||
|
"-chardev",
|
||||||
|
&format!(
|
||||||
|
"socket,id=debugser,path=/run/proxmox-backup/file-restore-serial-{}.sock,server,nowait",
|
||||||
|
cid
|
||||||
|
),
|
||||||
|
"-serial",
|
||||||
|
"chardev:debugser",
|
||||||
|
];
|
||||||
|
qemu_cmd.args(debug_args.iter());
|
||||||
|
}
|
||||||
|
|
||||||
qemu_cmd.stdout(std::process::Stdio::null());
|
qemu_cmd.stdout(std::process::Stdio::null());
|
||||||
qemu_cmd.stderr(std::process::Stdio::piped());
|
qemu_cmd.stderr(std::process::Stdio::piped());
|
||||||
|
|
||||||
|
@ -282,6 +315,12 @@ pub async fn start_vm(
|
||||||
if let Ok(Ok(_)) =
|
if let Ok(Ok(_)) =
|
||||||
time::timeout(Duration::from_secs(2), client.get("api2/json/status", None)).await
|
time::timeout(Duration::from_secs(2), client.get("api2/json/status", None)).await
|
||||||
{
|
{
|
||||||
|
if debug {
|
||||||
|
eprintln!(
|
||||||
|
"Connect to '/run/proxmox-backup/file-restore-serial-{}.sock' for shell access",
|
||||||
|
cid
|
||||||
|
)
|
||||||
|
}
|
||||||
return Ok((pid, cid as i32));
|
return Ok((pid, cid as i32));
|
||||||
}
|
}
|
||||||
if kill(pid_t, None).is_err() {
|
if kill(pid_t, None).is_err() {
|
||||||
|
|
|
@ -43,6 +43,10 @@ pub const PROXMOX_BACKUP_API_PID_FN: &str = concat!(PROXMOX_BACKUP_RUN_DIR_M!(),
|
||||||
pub const PROXMOX_BACKUP_INITRAMFS_FN: &str =
|
pub const PROXMOX_BACKUP_INITRAMFS_FN: &str =
|
||||||
concat!(PROXMOX_BACKUP_CACHE_DIR_M!(), "/file-restore-initramfs.img");
|
concat!(PROXMOX_BACKUP_CACHE_DIR_M!(), "/file-restore-initramfs.img");
|
||||||
|
|
||||||
|
/// filename of the cached initramfs to use for debugging single file restore
|
||||||
|
pub const PROXMOX_BACKUP_INITRAMFS_DBG_FN: &str =
|
||||||
|
concat!(PROXMOX_BACKUP_CACHE_DIR_M!(), "/file-restore-initramfs-debug.img");
|
||||||
|
|
||||||
/// filename of the kernel to use for booting single file restore VMs
|
/// filename of the kernel to use for booting single file restore VMs
|
||||||
pub const PROXMOX_BACKUP_KERNEL_FN: &str =
|
pub const PROXMOX_BACKUP_KERNEL_FN: &str =
|
||||||
concat!(PROXMOX_BACKUP_FILE_RESTORE_BIN_DIR_M!(), "/bzImage");
|
concat!(PROXMOX_BACKUP_FILE_RESTORE_BIN_DIR_M!(), "/bzImage");
|
||||||
|
|
Loading…
Reference in New Issue