[pve-devel] [PATCH container] implement CT reinstall option for restore

Oguz Bektas o.bektas at proxmox.com
Wed Apr 1 12:44:02 CEST 2020


this adds the 'reinstall' flag, which is a special forced restore
(overwrites an existing container with chosen template)

testing command example:

pct restore <CTID> /path/to/template/file --reinstall --storage local-lvm --unprivileged 1 --password 123456

should reinstall the CT with the given template (different distros can
be chosen as well, f.e. existing alpine container reinstalled as
archlinux).
password or ssh key is required for this, since it calls setup
routines like post_create_hook (otherwise we won't be able to log-in to
CT).

Signed-off-by: Oguz Bektas <o.bektas at proxmox.com>
---
 src/PVE/API2/LXC.pm   | 40 ++++++++++++++++++++++++++++++++++++----
 src/PVE/LXC/Create.pm | 11 ++++++++---
 2 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/src/PVE/API2/LXC.pm b/src/PVE/API2/LXC.pm
index f4c1a49..f1cd67e 100644
--- a/src/PVE/API2/LXC.pm
+++ b/src/PVE/API2/LXC.pm
@@ -147,6 +147,11 @@ __PACKAGE__->register_method({
 		type => 'boolean',
 		description => "Mark this as restore task.",
 	    },
+	    reinstall => {
+		optional => 1,
+		type => 'boolean',
+		description => "Reinstall container using a template.",
+	    },
 	    unique => {
 		optional => 1,
 		type => 'boolean',
@@ -208,26 +213,39 @@ __PACKAGE__->register_method({
 	my $unprivileged = extract_param($param, 'unprivileged');
 	my $restore = extract_param($param, 'restore');
 	my $unique = extract_param($param, 'unique');
+	my $reinstall = extract_param($param, 'reinstall');
 
 	# used to skip firewall config restore if user lacks permission
 	my $skip_fw_config_restore = 0;
+	my $force = extract_param($param, 'force');
+
+	if ($reinstall) {
+	    # reinstall is handled as a special force restore (possibly w/ extra config opts
+	    # given in the call)
+	    $restore = 1;
+	    $force = 1;
+	}
 
 	if ($restore) {
 	    # fixme: limit allowed parameters
 	}
 
-	my $force = extract_param($param, 'force');
 
+	my $reinstall_conf;
 	if (!($same_container_exists && $restore && $force)) {
 	    PVE::Cluster::check_vmid_unused($vmid);
 	} else {
 	    die "can't overwrite running container\n" if PVE::LXC::check_running($vmid);
 	    my $conf = PVE::LXC::Config->load_config($vmid);
+	    $reinstall_conf = $conf;
 	    PVE::LXC::Config->check_protection($conf, "unable to restore CT $vmid");
 	}
 
 	my $password = extract_param($param, 'password');
 	my $ssh_keys = extract_param($param, 'ssh-public-keys');
+	if ($reinstall && !defined($password) && !defined($ssh_keys)) {
+	    die "password/ssh key required during reinstall. aborting...\n";
+	}
 	PVE::Tools::validate_ssh_public_keys($ssh_keys) if defined($ssh_keys);
 
 	my $pool = extract_param($param, 'pool');
@@ -354,7 +372,15 @@ __PACKAGE__->register_method({
 		    die "can't overwrite running container\n" if PVE::LXC::check_running($vmid);
 		    if ($is_root && $archive ne '-') {
 			my $orig_conf;
-			($orig_conf, $orig_mp_param) = PVE::LXC::Create::recover_config($storage_cfg, $archive);
+			if ($reinstall) {
+			    PVE::LXC::Config->foreach_mountpoint($reinstall_conf, sub {
+				my ($ms, $mountpoint) = @_;
+				$orig_mp_param->{$ms} = $reinstall_conf->{$ms};
+			    });
+			}
+			else {
+			    ($orig_conf, $orig_mp_param) = PVE::LXC::Create::recover_config($storage_cfg, $archive);
+			}
 			$was_template = delete $orig_conf->{template};
 			# When we're root call 'restore_configuration' with restricted=0,
 			# causing it to restore the raw lxc entries, among which there may be
@@ -365,7 +391,12 @@ __PACKAGE__->register_method({
 		}
 		if ($storage_only_mode) {
 		    if ($restore) {
-			if (!defined($orig_mp_param)) {
+			if ($reinstall) {
+			    PVE::LXC::Config->foreach_mountpoint($reinstall_conf, sub {
+			        my ($ms, $mountpoint) = @_;
+				$orig_mp_param->{$ms} = $reinstall_conf->{$ms};
+			    });
+			} elsif (!defined($orig_mp_param)) {
 			    (undef, $orig_mp_param) = PVE::LXC::Create::recover_config($storage_cfg, $archive);
 			}
 			$mp_param = $orig_mp_param;
@@ -417,9 +448,10 @@ __PACKAGE__->register_method({
 		    PVE::LXC::Create::restore_archive($storage_cfg, $archive, $rootdir, $conf, $ignore_unpack_errors, $bwlimit);
 
 		    if ($restore) {
-			PVE::LXC::Create::restore_configuration($vmid, $storage_cfg, $archive, $rootdir, $conf, !$is_root, $unique, $skip_fw_config_restore);
+			PVE::LXC::Create::restore_configuration($vmid, $storage_cfg, $archive, $rootdir, $conf, !$is_root, $unique, $skip_fw_config_restore, $reinstall_conf);
 			my $lxc_setup = PVE::LXC::Setup->new($conf, $rootdir);
 			$lxc_setup->template_fixup($conf);
+			$lxc_setup->post_create_hook($password, $ssh_keys) if $reinstall;
 		    } else {
 			my $lxc_setup = PVE::LXC::Setup->new($conf, $rootdir); # detect OS
 			PVE::LXC::Config->write_config($vmid, $conf); # safe config (after OS detection)
diff --git a/src/PVE/LXC/Create.pm b/src/PVE/LXC/Create.pm
index 9faec63..342e790 100644
--- a/src/PVE/LXC/Create.pm
+++ b/src/PVE/LXC/Create.pm
@@ -251,7 +251,7 @@ sub recover_config_from_tar {
 }
 
 sub restore_configuration {
-    my ($vmid, $storage_cfg, $archive, $rootdir, $conf, $restricted, $unique, $skip_fw) = @_;
+    my ($vmid, $storage_cfg, $archive, $rootdir, $conf, $restricted, $unique, $skip_fw, $reinstall_conf) = @_;
 
     my ($storeid, $volname) = PVE::Storage::parse_volume_id($archive, 1);
     if (defined($storeid)) {
@@ -260,7 +260,7 @@ sub restore_configuration {
 	    return restore_configuration_from_proxmox_backup($vmid, $storage_cfg, $archive, $rootdir, $conf, $restricted, $unique, $skip_fw);
 	}
     }
-    restore_configuration_from_etc_vzdump($vmid, $rootdir, $conf, $restricted, $unique, $skip_fw);
+    restore_configuration_from_etc_vzdump($vmid, $rootdir, $conf, $restricted, $unique, $skip_fw, $reinstall_conf);
 }
 
 sub restore_configuration_from_proxmox_backup {
@@ -332,13 +332,16 @@ sub sanitize_and_merge_config {
 }
 
 sub restore_configuration_from_etc_vzdump {
-    my ($vmid, $rootdir, $conf, $restricted, $unique, $skip_fw) = @_;
+    my ($vmid, $rootdir, $conf, $restricted, $unique, $skip_fw, $reinstall_conf) = @_;
 
     # restore: try to extract configuration from archive
 
     my $pct_cfg_fn = "$rootdir/etc/vzdump/pct.conf";
     my $pct_fwcfg_fn = "$rootdir/etc/vzdump/pct.fw";
     my $ovz_cfg_fn = "$rootdir/etc/vzdump/vps.conf";
+
+    my $reinstall = defined($reinstall_conf);
+
     if (-f $pct_cfg_fn) {
 	my $raw = PVE::Tools::file_get_contents($pct_cfg_fn);
 	my $oldconf = PVE::LXC::Config::parse_pct_config("/lxc/$vmid.conf", $raw);
@@ -380,6 +383,8 @@ sub restore_configuration_from_etc_vzdump {
 	}
 	unlink($ovz_cfg_fn);
 
+    } elsif ($reinstall) {
+	sanitize_and_merge_config($conf, $reinstall_conf, $restricted, $unique);
     } else {
 	print "###########################################################\n";
 	print "Backup archive does not contain any configuration\n";
-- 
2.20.1




More information about the pve-devel mailing list