[pbs-devel] [PATCH proxmox-backup 1/9] file-restore: add debug mode with serial access

Stefan Reiter s.reiter at proxmox.com
Thu May 6 17:26:16 CEST 2021


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 at proxmox.com>
---
 debian/proxmox-backup-file-restore.postinst | 12 ++++-
 src/bin/proxmox_file_restore/qemu_helper.rs | 55 ++++++++++++++++++---
 src/buildcfg.rs                             |  4 ++
 3 files changed, 62 insertions(+), 9 deletions(-)

diff --git a/debian/proxmox-backup-file-restore.postinst b/debian/proxmox-backup-file-restore.postinst
index 27eb87e9..feb0557b 100755
--- a/debian/proxmox-backup-file-restore.postinst
+++ b/debian/proxmox-backup-file-restore.postinst
@@ -6,6 +6,7 @@ update_initramfs() {
     # regenerate initramfs for single file restore VM
     INST_PATH="/usr/lib/x86_64-linux-gnu/proxmox-backup/file-restore"
     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
     # not want an unuseable image lying around
@@ -20,7 +21,7 @@ update_initramfs() {
 
     # avoid leftover temp file
     cleanup() {
-        rm -f "$CACHE_PATH.tmp"
+        rm -f "$CACHE_PATH.tmp" "$CACHE_PATH_DBG.tmp"
     }
     trap cleanup EXIT
 
@@ -34,6 +35,15 @@ update_initramfs() {
         | cpio -o --format=newc -A -F "$CACHE_PATH.tmp" )
     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
 }
 
diff --git a/src/bin/proxmox_file_restore/qemu_helper.rs b/src/bin/proxmox_file_restore/qemu_helper.rs
index 9328addf..20b4f344 100644
--- a/src/bin/proxmox_file_restore/qemu_helper.rs
+++ b/src/bin/proxmox_file_restore/qemu_helper.rs
@@ -47,9 +47,13 @@ fn create_restore_log_dir() -> Result<String, Error> {
     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 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() {
         bail!("cannot run file-restore VM: package 'proxmox-backup-restore-image' is not (correctly) installed");
     }
@@ -79,7 +83,7 @@ fn try_kill_vm(pid: i32) -> Result<(), Error> {
     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 tokio::fs::File;
 
@@ -88,8 +92,14 @@ async fn create_temp_initramfs(ticket: &str) -> Result<(Fd, String), Error> {
     nix::unistd::unlink(&tmp_path)?;
     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 base = File::open(buildcfg::PROXMOX_BACKUP_INITRAMFS_FN).await?;
+    let mut base = File::open(initramfs).await?;
 
     tokio::io::copy(&mut base, &mut f).await?;
 
@@ -122,18 +132,24 @@ pub async fn start_vm(
     files: impl Iterator<Item = String>,
     ticket: &str,
 ) -> Result<(i32, i32), Error> {
-    validate_img_existance()?;
-
     if let Err(_) = std::env::var("PBS_PASSWORD") {
         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_fd, pid_path) = make_tmp_file("/tmp/file-restore-qemu.pid.tmp", CreateOptions::new())?;
     nix::unistd::unlink(&pid_path)?;
     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 logfile = &format!("{}/qemu.log", logpath);
@@ -174,7 +190,11 @@ pub async fn start_vm(
         "-initrd",
         &ramfs_path,
         "-append",
-        "quiet panic=1",
+        if debug {
+            "debug panic=1"
+        } else {
+            "quiet panic=1"
+        },
         "-daemonize",
         "-pidfile",
         &format!("/dev/fd/{}", pid_fd.as_raw_fd()),
@@ -218,6 +238,19 @@ pub async fn start_vm(
             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.stderr(std::process::Stdio::piped());
 
@@ -260,6 +293,12 @@ pub async fn start_vm(
         if let Ok(Ok(_)) =
             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));
         }
         if kill(pid_t, None).is_err() {
diff --git a/src/buildcfg.rs b/src/buildcfg.rs
index b0f61efb..c70ab6ea 100644
--- a/src/buildcfg.rs
+++ b/src/buildcfg.rs
@@ -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 =
     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
 pub const PROXMOX_BACKUP_KERNEL_FN: &str =
     concat!(PROXMOX_BACKUP_FILE_RESTORE_BIN_DIR_M!(), "/bzImage");
-- 
2.20.1






More information about the pbs-devel mailing list