]> git.proxmox.com Git - pve-container.git/blobdiff - src/PVE/API2/LXC.pm
update_lxc_config: remove unused parameter
[pve-container.git] / src / PVE / API2 / LXC.pm
index 09b71c880bda86dba3a6c8c218d7b0f1d8036020..9b92c13491e5d34bbfaafa830ad2185904af2723 100644 (file)
@@ -107,7 +107,7 @@ __PACKAGE__->register_method({
     proxyto => 'node',
     parameters => {
        additionalProperties => 0,
-       properties => PVE::LXC::json_config_properties({
+       properties => PVE::LXC::Config->json_config_properties({
            node => get_standard_option('pve-node'),
            vmid => get_standard_option('pve-vmid', { completion => \&PVE::Cluster::complete_next_vmid }),
            ostemplate => {
@@ -148,6 +148,12 @@ __PACKAGE__->register_method({
                type => 'boolean',
                description => "Ignore errors when extracting the template.",
            },
+           'ssh-public-keys' => {
+               optional => 1,
+               type => 'string',
+               description => "Setup public SSH keys (one key per line, " .
+                               "OpenSSH format).",
+           },
        }),
     },
     returns => {
@@ -166,7 +172,7 @@ __PACKAGE__->register_method({
 
        my $ignore_unpack_errors = extract_param($param, 'ignore-unpack-errors');
 
-       my $basecfg_fn = PVE::LXC::config_file($vmid);
+       my $basecfg_fn = PVE::LXC::Config->config_file($vmid);
 
        my $same_container_exists = -f $basecfg_fn;
 
@@ -185,12 +191,15 @@ __PACKAGE__->register_method({
        if (!($same_container_exists && $restore && $force)) {
            PVE::Cluster::check_vmid_unused($vmid);
        } else {
-           my $conf = PVE::LXC::load_config($vmid);
-           PVE::LXC::check_protection($conf, "unable to restore CT $vmid");
+           my $conf = PVE::LXC::Config->load_config($vmid);
+           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');
+       PVE::Tools::validate_ssh_public_keys($ssh_keys) if defined($ssh_keys);
+
        my $pool = extract_param($param, 'pool');
 
        if (defined($pool)) {
@@ -209,7 +218,7 @@ __PACKAGE__->register_method({
            raise_perm_exc();
        }
 
-       PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, $pool, [ keys %$param]);
+       PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, $pool, $param, []);
 
        my $storage = extract_param($param, 'storage') // 'local';
 
@@ -247,18 +256,32 @@ __PACKAGE__->register_method({
        my $conf = {};
 
        my $no_disk_param = {};
+       my $mp_param = {};
+       my $storage_only_mode = 1;
        foreach my $opt (keys %$param) {
            my $value = $param->{$opt};
            if ($opt eq 'rootfs' || $opt =~ m/^mp\d+$/) {
                # allow to use simple numbers (add default storage in that case)
-               $param->{$opt} = "$storage:$value" if $value =~ m/^\d+(\.\d+)?$/;
+               if ($value =~ m/^\d+(\.\d+)?$/) {
+                   $mp_param->{$opt} = "$storage:$value";
+               } else {
+                   $mp_param->{$opt} = $value;
+               }
+               $storage_only_mode = 0;
+           } elsif ($opt =~ m/^unused\d+$/) {
+               warn "ignoring '$opt', cannot create/restore with unused volume\n";
+               delete $param->{$opt};
            } else {
                $no_disk_param->{$opt} = $value;
            }
        }
 
+       die "mountpoints configured, but 'rootfs' not set - aborting\n"
+           if !$storage_only_mode && !defined($mp_param->{rootfs});
+
        # check storage access, activate storage
-       PVE::LXC::foreach_mountpoint($param, sub {
+       my $delayed_mp_param = {};
+       PVE::LXC::Config->foreach_mountpoint($mp_param, sub {
            my ($ms, $mountpoint) = @_;
 
            my $volid = $mountpoint->{volume};
@@ -274,9 +297,9 @@ __PACKAGE__->register_method({
        });
 
        # check/activate default storage
-       &$check_and_activate_storage($storage) if !defined($param->{rootfs});
+       &$check_and_activate_storage($storage) if !defined($mp_param->{rootfs});
 
-       PVE::LXC::update_pct_config($vmid, $conf, 0, $no_disk_param);
+       PVE::LXC::Config->update_pct_config($vmid, $conf, 0, $no_disk_param);
 
        $conf->{unprivileged} = 1 if $unprivileged;
 
@@ -291,31 +314,91 @@ __PACKAGE__->register_method({
 
        my $code = sub {
            &$check_vmid_usage(); # final check after locking
-                   
+           my $old_conf;
+
+           my $config_fn = PVE::LXC::Config->config_file($vmid);
+           if (-f $config_fn) {
+               die "container exists" if !$restore; # just to be sure
+               $old_conf = PVE::LXC::Config->load_config($vmid);
+           } else {
+               eval {
+                   # try to create empty config on local node, we have an flock
+                   PVE::LXC::Config->write_config($vmid, {});
+               };
+
+               # another node was faster, abort
+               die "Could not reserve ID $vmid, already taken\n" if $@;
+           }
+
            PVE::Cluster::check_cfs_quorum();
            my $vollist = [];
 
            eval {
-               if (!defined($param->{rootfs})) {
+               if ($storage_only_mode) {
                    if ($restore) {
-                       my (undef, $disksize) = PVE::LXC::Create::recover_config($archive);
-                       die "unable to detect disk size - please specify rootfs (size)\n"
-                           if !$disksize;
-                       $disksize /= 1024 * 1024 * 1024; # create_disks expects GB as unit size
-                       $param->{rootfs} = "$storage:$disksize";
+                       (undef, $mp_param) = PVE::LXC::Create::recover_config($archive);
+                       die "rootfs configuration could not be recovered, please check and specify manually!\n"
+                           if !defined($mp_param->{rootfs});
+                       PVE::LXC::Config->foreach_mountpoint($mp_param, sub {
+                           my ($ms, $mountpoint) = @_;
+                           my $type = $mountpoint->{type};
+                           if ($type eq 'volume') {
+                               die "unable to detect disk size - please specify $ms (size)\n"
+                                   if !defined($mountpoint->{size});
+                               my $disksize = $mountpoint->{size} / (1024 * 1024 * 1024); # create_disks expects GB as unit size
+                               delete $mountpoint->{size};
+                               $mountpoint->{volume} = "$storage:$disksize";
+                               $mp_param->{$ms} = PVE::LXC::Config->print_ct_mountpoint($mountpoint, $ms eq 'rootfs');
+                           } else {
+                               my $type = $mountpoint->{type};
+                               die "restoring rootfs to $type mount is only possible by specifying -rootfs manually!\n"
+                                   if ($ms eq 'rootfs');
+
+                               if ($mountpoint->{backup}) {
+                                   warn "WARNING - unsupported configuration!\n";
+                                   warn "backup was enabled for $type mountpoint $ms ('$mountpoint->{mp}')\n";
+                                   warn "mountpoint configuration will be restored after archive extraction!\n";
+                                   warn "contained files will be restored to wrong directory!\n";
+                               }
+                               $delayed_mp_param->{$ms} = PVE::LXC::Config->print_ct_mountpoint($mountpoint, $ms eq 'rootfs');
+                           }
+                       });
                    } else {
-                       $param->{rootfs} = "$storage:4"; # defaults to 4GB
+                       $mp_param->{rootfs} = "$storage:4"; # defaults to 4GB
                    }
                }
 
-               $vollist = PVE::LXC::create_disks($storage_cfg, $vmid, $param, $conf);
+               $vollist = PVE::LXC::create_disks($storage_cfg, $vmid, $mp_param, $conf);
+
+               if (defined($old_conf)) {
+                   # destroy old container volumes
+                   PVE::LXC::destroy_lxc_container($storage_cfg, $vmid, $old_conf, {});
+               }
+
+               eval {
+                   my $rootdir = PVE::LXC::mount_all($vmid, $storage_cfg, $conf, 1);
+                   PVE::LXC::Create::restore_archive($archive, $rootdir, $conf, $ignore_unpack_errors);
 
-               PVE::LXC::Create::create_rootfs($storage_cfg, $vmid, $conf, $archive, $password, $restore, $ignore_unpack_errors);
+                   if ($restore) {
+                       PVE::LXC::Create::restore_configuration($vmid, $rootdir, $conf);
+                   } else {
+                       my $lxc_setup = PVE::LXC::Setup->new($conf, $rootdir); # detect OS
+                       PVE::LXC::Config->write_config($vmid, $conf); # safe config (after OS detection)
+                       $lxc_setup->post_create_hook($password, $ssh_keys);
+                   }
+               };
+               my $err = $@;
+               PVE::LXC::umount_all($vmid, $storage_cfg, $conf, $err ? 1 : 0);
+               PVE::Storage::deactivate_volumes($storage_cfg, PVE::LXC::Config->get_vm_volumes($conf));
+               die $err if $err;
                # set some defaults
                $conf->{hostname} ||= "CT$vmid";
                $conf->{memory} ||= 512;
                $conf->{swap} //= 512;
-               PVE::LXC::create_config($vmid, $conf);
+               foreach my $mp (keys %$delayed_mp_param) {
+                   $conf->{$mp} = $delayed_mp_param->{$mp};
+               }
+               PVE::LXC::Config->write_config($vmid, $conf);
            };
            if (my $err = $@) {
                PVE::LXC::destroy_disks($storage_cfg, $vollist);
@@ -325,7 +408,7 @@ __PACKAGE__->register_method({
            PVE::AccessControl::add_vm_to_pool($vmid, $pool) if $pool;
        };
 
-       my $realcmd = sub { PVE::LXC::lock_container($vmid, 1, $code); };
+       my $realcmd = sub { PVE::LXC::Config->lock_config($vmid, $code); };
 
        &$check_vmid_usage(); # first check before locking
 
@@ -364,7 +447,7 @@ __PACKAGE__->register_method({
        my ($param) = @_;
 
        # test if VM exists
-       my $conf = PVE::LXC::load_config($param->{vmid});
+       my $conf = PVE::LXC::Config->load_config($param->{vmid});
 
        my $res = [
            { subdir => 'config' },
@@ -503,11 +586,11 @@ __PACKAGE__->register_method({
        my $vmid = $param->{vmid};
 
        # test if container exists
-       my $conf = PVE::LXC::load_config($vmid);
+       my $conf = PVE::LXC::Config->load_config($vmid);
 
        my $storage_cfg = cfs_read_file("storage.cfg");
 
-       PVE::LXC::check_protection($conf, "can't remove CT $vmid");
+       PVE::LXC::Config->check_protection($conf, "can't remove CT $vmid");
 
        die "unable to remove CT $vmid - used in HA resources\n"
            if PVE::HA::Config::vm_is_ha_managed($vmid);
@@ -518,8 +601,8 @@ __PACKAGE__->register_method({
 
        my $code = sub {
            # reload config after lock
-           $conf = PVE::LXC::load_config($vmid);
-           PVE::LXC::check_lock($conf);
+           $conf = PVE::LXC::Config->load_config($vmid);
+           PVE::LXC::Config->check_lock($conf);
 
            die $running_error_msg if PVE::LXC::check_running($vmid);
 
@@ -528,7 +611,7 @@ __PACKAGE__->register_method({
            PVE::Firewall::remove_vmfw_conf($vmid);
        };
 
-       my $realcmd = sub { PVE::LXC::lock_container($vmid, 1, $code); };
+       my $realcmd = sub { PVE::LXC::Config->lock_config($vmid, $code); };
        
        return $rpcenv->fork_worker('vzdestroy', $vmid, $authuser, $realcmd);
     }});
@@ -598,7 +681,7 @@ __PACKAGE__->register_method ({
        my $remcmd = $remip ?
            ['/usr/bin/ssh', '-t', $remip] : [];
 
-       my $conf = PVE::LXC::load_config($vmid, $node);
+       my $conf = PVE::LXC::Config->load_config($vmid, $node);
        my $concmd = PVE::LXC::get_console_command($vmid, $conf);
 
        my $shcmd = [ '/usr/bin/dtach', '-A',
@@ -719,7 +802,7 @@ __PACKAGE__->register_method ({
        my $authpath = "/vms/$vmid";
        my $permissions = 'VM.Console';
 
-       my $conf = PVE::LXC::load_config($vmid);
+       my $conf = PVE::LXC::Config->load_config($vmid);
 
        die "CT $vmid not running\n" if !PVE::LXC::check_running($vmid);
 
@@ -759,6 +842,13 @@ __PACKAGE__->register_method({
                description => "Use online/live migration.",
                optional => 1,
            },
+           force => {
+               type => 'boolean',
+               description => "Force migration despite local bind / device" .
+                   " mounts. WARNING: identical bind / device mounts need to ".
+                   " be available on the target node.",
+               optional => 1,
+           },
        },
     },
     returns => {
@@ -786,7 +876,7 @@ __PACKAGE__->register_method({
        my $vmid = extract_param($param, 'vmid');
 
        # test if VM exists
-       PVE::LXC::load_config($vmid);
+       PVE::LXC::Config->load_config($vmid);
 
        # try to detect errors early
        if (PVE::LXC::check_running($vmid)) {
@@ -872,7 +962,7 @@ __PACKAGE__->register_method({
 
        my $feature = extract_param($param, 'feature');
 
-       my $conf = PVE::LXC::load_config($vmid);
+       my $conf = PVE::LXC::Config->load_config($vmid);
 
        if($snapname){
            my $snap = $conf->{snapshots}->{$snapname};
@@ -882,7 +972,7 @@ __PACKAGE__->register_method({
        my $storage_cfg = PVE::Storage::config();
        #Maybe include later
        #my $nodelist = PVE::LXC::shared_nodes($conf, $storage_cfg);
-       my $hasFeature = PVE::LXC::has_feature($feature, $conf, $storage_cfg, $snapname);
+       my $hasFeature = PVE::LXC::Config->has_feature($feature, $conf, $storage_cfg, $snapname);
 
        return {
            hasFeature => $hasFeature,
@@ -906,6 +996,12 @@ __PACKAGE__->register_method({
        properties => {
            node => get_standard_option('pve-node'),
            vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid_stopped }),
+           experimental => {
+               type => 'boolean',
+               description => "The template feature is experimental, set this " .
+                   "flag if you know what you are doing.",
+               default => 0,
+           },
        },
     },
     returns => { type => 'null'},
@@ -922,14 +1018,14 @@ __PACKAGE__->register_method({
 
        my $updatefn =  sub {
 
-           my $conf = PVE::LXC::load_config($vmid);
-           PVE::LXC::check_lock($conf);
+           my $conf = PVE::LXC::Config->load_config($vmid);
+           PVE::LXC::Config->check_lock($conf);
 
            die "unable to create template, because CT contains snapshots\n"
                if $conf->{snapshots} && scalar(keys %{$conf->{snapshots}});
 
            die "you can't convert a template to a template\n"
-               if PVE::LXC::is_template($conf);
+               if PVE::LXC::Config->is_template($conf);
 
            die "you can't convert a CT to template if the CT is running\n"
                if PVE::LXC::check_running($vmid);
@@ -940,14 +1036,14 @@ __PACKAGE__->register_method({
 
            $conf->{template} = 1;
 
-           PVE::LXC::write_config($vmid, $conf);
+           PVE::LXC::Config->write_config($vmid, $conf);
            # and remove lxc config
-           PVE::LXC::update_lxc_config(undef, $vmid, $conf);
+           PVE::LXC::update_lxc_config($vmid, $conf);
 
            return $rpcenv->fork_worker('vztemplate', $vmid, $authuser, $realcmd);
        };
 
-       PVE::LXC::lock_container($vmid, undef, $updatefn);
+       PVE::LXC::Config->lock_config($vmid, $updatefn);
 
        return undef;
     }});
@@ -1011,6 +1107,12 @@ __PACKAGE__->register_method({
                    "you clone a normal CT. For CT templates, we try to create a linked clone by default.",
                default => 0,
            },
+           experimental => {
+               type => 'boolean',
+               description => "The clone feature is experimental, set this " .
+                   "flag if you know what you are doing.",
+               default => 0,
+           },
 #          target => get_standard_option('pve-node', {
 #              description => "Target node. Only allowed if the original VM is on shared storage.",
 #              optional => 1,
@@ -1060,9 +1162,9 @@ __PACKAGE__->register_method({
 
            # do all tests after lock
            # we also try to do all tests before we fork the worker
-           my $conf = PVE::LXC::load_config($vmid);
+           my $conf = PVE::LXC::Config->load_config($vmid);
 
-           PVE::LXC::check_lock($conf);
+           PVE::LXC::Config->check_lock($conf);
 
            my $verify_running = PVE::LXC::check_running($vmid) || 0;
 
@@ -1073,7 +1175,7 @@ __PACKAGE__->register_method({
 
            my $oldconf = $snapname ? $conf->{snapshots}->{$snapname} : $conf;
 
-           my $conffile = PVE::LXC::config_file($newid);
+           my $conffile = PVE::LXC::Config->config_file($newid);
            die "unable to create CT $newid: config file already exists\n"
                if -f $conffile;
 
@@ -1090,8 +1192,8 @@ __PACKAGE__->register_method({
 
                if (($opt eq 'rootfs') || ($opt =~ m/^mp\d+$/)) {
                    my $mp = $opt eq 'rootfs' ?
-                       PVE::LXC::parse_ct_rootfs($value) :
-                       PVE::LXC::parse_ct_mountpoint($value);
+                       PVE::LXC::Config->parse_ct_rootfs($value) :
+                       PVE::LXC::Config->parse_ct_mountpoint($value);
 
                    if ($mp->{type} eq 'volume') {
                        my $volid = $mp->{volume};
@@ -1155,13 +1257,13 @@ __PACKAGE__->register_method({
                            push @$newvollist, $newvolid;
                            $mp->{volume} = $newvolid;
 
-                           $newconf->{$opt} = PVE::LXC::print_ct_mountpoint($mp, $opt eq 'rootfs');
-                           PVE::LXC::write_config($newid, $newconf);
+                           $newconf->{$opt} = PVE::LXC::Config->print_ct_mountpoint($mp, $opt eq 'rootfs');
+                           PVE::LXC::Config->write_config($newid, $newconf);
                        }
                    }
 
                    delete $newconf->{lock};
-                   PVE::LXC::write_config($newid, $newconf);
+                   PVE::LXC::Config->write_config($newid, $newconf);
 
                    PVE::AccessControl::add_vm_to_pool($newid, $pool) if $pool;
                };
@@ -1186,7 +1288,7 @@ __PACKAGE__->register_method({
 
        };
 
-       return PVE::LXC::lock_container($vmid, undef, $clonefn);
+       return PVE::LXC::Config->lock_config($vmid, $clonefn);
     }});
 
 
@@ -1208,7 +1310,7 @@ __PACKAGE__->register_method({
            disk => {
                type => 'string',
                description => "The disk you want to resize.",
-               enum => [PVE::LXC::mountpoint_names()],
+               enum => [PVE::LXC::Config->mountpoint_names()],
            },
            size => {
                type => 'string',
@@ -1247,22 +1349,22 @@ __PACKAGE__->register_method({
 
        die "no options specified\n" if !scalar(keys %$param);
 
-       PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, [keys %$param]);
+       PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, $param, []);
 
        my $storage_cfg = cfs_read_file("storage.cfg");
 
        my $code = sub {
 
-           my $conf = PVE::LXC::load_config($vmid);
-           PVE::LXC::check_lock($conf);
+           my $conf = PVE::LXC::Config->load_config($vmid);
+           PVE::LXC::Config->check_lock($conf);
 
            PVE::Tools::assert_if_modified($digest, $conf->{digest});
 
            my $running = PVE::LXC::check_running($vmid);
 
            my $disk = $param->{disk};
-           my $mp = $disk eq 'rootfs' ? PVE::LXC::parse_ct_rootfs($conf->{$disk}) :
-               PVE::LXC::parse_ct_mountpoint($conf->{$disk});
+           my $mp = $disk eq 'rootfs' ? PVE::LXC::Config->parse_ct_rootfs($conf->{$disk}) :
+               PVE::LXC::Config->parse_ct_mountpoint($conf->{$disk});
 
            my $volid = $mp->{volume};
 
@@ -1279,6 +1381,8 @@ __PACKAGE__->register_method({
 
            $rpcenv->check($authuser, "/storage/$storeid", ['Datastore.AllocateSpace']);
 
+           PVE::Storage::activate_volumes($storage_cfg, [$volid]);
+
            my $size = PVE::Storage::volume_size_info($storage_cfg, $volid, 5);
            $newsize += $size if $ext;
            $newsize = int($newsize);
@@ -1294,9 +1398,9 @@ __PACKAGE__->register_method({
                PVE::Storage::volume_resize($storage_cfg, $volid, $newsize, 0);
 
                $mp->{size} = $newsize;
-               $conf->{$disk} = PVE::LXC::print_ct_mountpoint($mp, $disk eq 'rootfs');
+               $conf->{$disk} = PVE::LXC::Config->print_ct_mountpoint($mp, $disk eq 'rootfs');
 
-               PVE::LXC::write_config($vmid, $conf);
+               PVE::LXC::Config->write_config($vmid, $conf);
 
                if ($format eq 'raw') {
                    my $path = PVE::Storage::path($storage_cfg, $volid, undef);
@@ -1317,10 +1421,16 @@ __PACKAGE__->register_method({
                        # interestingly we don't need to e2fsck on mounted systems...
                        my $quoted = PVE::Tools::shellquote($path);
                        my $cmd = "mount --make-rprivate / && mount $quoted /tmp && resize2fs $quoted";
-                       PVE::Tools::run_command(['unshare', '-m', '--', 'sh', '-c', $cmd]);
+                       eval {
+                           PVE::Tools::run_command(['unshare', '-m', '--', 'sh', '-c', $cmd]);
+                       };
+                       warn "Failed to update the container's filesystem: $@\n" if $@;
                    } else {
-                       PVE::Tools::run_command(['e2fsck', '-f', '-y', $path]);
-                       PVE::Tools::run_command(['resize2fs', $path]);
+                       eval {
+                           PVE::Tools::run_command(['e2fsck', '-f', '-y', $path]);
+                           PVE::Tools::run_command(['resize2fs', $path]);
+                       };
+                       warn "Failed to update the container's filesystem: $@\n" if $@;
                    }
                }
            };
@@ -1328,7 +1438,7 @@ __PACKAGE__->register_method({
            return $rpcenv->fork_worker('resize', $vmid, $authuser, $realcmd);
        };
 
-       return PVE::LXC::lock_container($vmid, undef, $code);;
+       return PVE::LXC::Config->lock_config($vmid, $code);;
     }});
 
 1;