From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id 1D58C1FF0DF for ; Fri, 28 Aug 2026 15:32:52 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 92C712174C; Fri, 28 Aug 2026 15:31:15 +0200 (CEST) From: Shannon Sterz To: pve-devel@lists.proxmox.com Subject: [PATCH installer 17/21] low-level-installer: add support for restoring backups Date: Fri, 28 Aug 2026 15:30:26 +0200 Message-ID: <20260828133030.351140-18-s.sterz@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260828133030.351140-1-s.sterz@proxmox.com> References: <20260828133030.351140-1-s.sterz@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1787923825076 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.852 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: WRNBKEGHPQVHZEYTAMA6WK4KZ56YFYCE X-Message-ID-Hash: WRNBKEGHPQVHZEYTAMA6WK4KZ56YFYCE X-MailFrom: s.sterz@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: and integrate it with the tui restoring installer. Signed-off-by: Shannon Sterz --- Proxmox/Install.pm | 63 +++++++++++++++++++++++++++++++++++++-- Proxmox/Install/Config.pm | 6 ++++ 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/Proxmox/Install.pm b/Proxmox/Install.pm index 7bb8e29..1d4f56b 100644 --- a/Proxmox/Install.pm +++ b/Proxmox/Install.pm @@ -849,6 +849,9 @@ sub extract_data { my $bootloader_err; my $diskcount = 0; + my $backup_mp = Proxmox::Install::Config::get_restore_mount_point(); + my $kapi; + eval { my $maxper = 0.25; @@ -1488,7 +1491,7 @@ _EOD my $ask_for_patience = ""; $ask_for_patience = " (multiple disks detected, please be patient)" if $diskcount > 3; - update_progress(0.8, 0.95, 1, "make system bootable$ask_for_patience"); + update_progress(0.5, 0.95, 1, "make system bootable$ask_for_patience"); setup_proxmox_first_boot_service($targetdir); stage_subscription_key($targetdir); @@ -1538,7 +1541,6 @@ _EOD diversion_remove($targetdir, "/usr/sbin/update-grub"); diversion_remove($targetdir, "/usr/sbin/update-initramfs"); - my $kapi; foreach my $fn (<$targetdir/lib/modules/*>) { if ($fn =~ m!/(\d+\.\d+\.\d+-\d+(?:-\w+)?-pve)$!) { die "found multiple kernels\n" if defined($kapi); @@ -1610,6 +1612,10 @@ _EOD diversion_remove($targetdir, "/sbin/start-stop-daemon"); + # return early, the next setup steps are overwritten by the backup and might fail (for + # example, setting a root password). + return if defined($backup_mp); + setup_root_password($targetdir); # set root ssh keys @@ -1697,7 +1703,9 @@ _EOD my $err = $@; - update_progress(1, 0, 1, "installation finished"); + if ($err || !defined($kapi) || !defined($backup_mp)) { + update_progress(1, 0, 1, "installation finished"); + } print STDERR $err if $err && $err ne "\n"; @@ -1709,6 +1717,55 @@ _EOD "chroot $targetdir /usr/bin/dpkg-query -W --showformat='\${package}\n'> final.pkglist"); } + if (!$err && defined($kapi) && defined($backup_mp)) { + eval { + update_progress(0.8, 0.95, 1, "restoring backup, this may take a little while..."); + my @backup_files = glob("$backup_mp/*"); + + foreach my $file (@backup_files) { + if ($file !~ m/\/(dev|run|tmp|sys|proc|mnt)\/?$/) { + syscmd(["cp", "--archive", "--recursive", "--force", $file, $targetdir]) == + 0 + || die("could not restore backup - $!\n"); + } + } + + # Copy the latest pmxcfs backup into the "live" position. + my @backed_up_dbs = + sort(glob($backup_mp . "/var/lib/pve-cluster/backup/config-backup*.db")); + my $db = $backed_up_dbs[-1]; + + die "could not restore live pmxcfs db.\n" if !defined($db); + + syscmd([ + "cp", "--archive", "--force", $db, "$targetdir/var/lib/pve-cluster/config.db", + ]) == 0 + || die("could not restore live pmxcfs backup - $!\n"); + + # unmount backup location as we are done restoring. ignore failures, + # nothing bad should happen if we reboot here while it's still + # mounted. + syscmd(["umount", "$backup_mp"]); + + if (!is_test_mode()) { + syscmd("mount -n --bind /dev $targetdir/dev"); # re-bind mount dev + + syscmd("chroot $targetdir /usr/sbin/update-initramfs -c -k $kapi") == 0 + || die "unable to install initramfs on restore\n"; + + syscmd("chroot $targetdir /usr/sbin/update-grub") == 0 + || die "unable to update boot loader config on restore\n"; + } + }; + + $err = $@; + update_progress(1, 0, 1, "installation finished"); + + if (!is_test_mode()) { + syscmd("umount $targetdir/dev"); # unmount again + } + } + syscmd("umount $targetdir/run"); syscmd("umount $targetdir/mnt/hostrun"); syscmd("umount $targetdir/tmp/pkg"); diff --git a/Proxmox/Install/Config.pm b/Proxmox/Install/Config.pm index dba3692..00b713f 100644 --- a/Proxmox/Install/Config.pm +++ b/Proxmox/Install/Config.pm @@ -121,6 +121,9 @@ my sub init_cfg { # and the service files in the proxmox-first-boot package ordering_target => 'multi-user', # one of `network-pre`, `network-online` or `multi-user` }, + + # directory to restore contents from + restore_mount_point => undef, }; $initial = parse_kernel_cmdline($initial); @@ -310,4 +313,7 @@ sub get_first_boot_opt { return defined($k) ? $opts->{$k} : $opts; } +sub get_restore_mount_point { return get('restore_mount_point'); } +sub set_restore_mount_point { set_key('restore_mount_point', $_[0]); } + 1; -- 2.47.3