From 67afe46efb6583662e6e9e0c263a162f75fdd524 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fabian=20Gr=C3=BCnbichler?= Date: Wed, 2 Mar 2016 14:03:49 +0100 Subject: [PATCH] Refactor config-related methods into AbstractConfig Move load_config, write_config, lock_config[_xx], check_lock, has_lock, set_lock, remove_lock, is_template, check_protection and config_file to pve-common/src/PVE/ AbstractConfig.pm since they are identical for LXC and Qemu. Move cfs_config_path and config_file_lock to implementation of PVE::AbstractConfig in src/PVE/LXC/Config.pm Drop create_config and replace it with write_config. --- src/PVE/API2/LXC.pm | 60 +++++----- src/PVE/API2/LXC/Config.pm | 10 +- src/PVE/API2/LXC/Snapshot.pm | 12 +- src/PVE/API2/LXC/Status.pm | 34 +++--- src/PVE/CLI/pct.pm | 32 +++--- src/PVE/LXC.pm | 210 ++++++----------------------------- src/PVE/LXC/Config.pm | 43 +++++++ src/PVE/LXC/Create.pm | 10 +- src/PVE/LXC/Makefile | 2 +- src/PVE/LXC/Migrate.pm | 14 +-- src/PVE/VZDump/LXC.pm | 22 ++-- src/lxc-pve-poststop-hook | 4 +- src/lxc-pve-prestart-hook | 8 +- src/lxcnetaddbr | 2 +- src/test/snapshot-test.pm | 34 +++--- 15 files changed, 206 insertions(+), 291 deletions(-) create mode 100644 src/PVE/LXC/Config.pm diff --git a/src/PVE/API2/LXC.pm b/src/PVE/API2/LXC.pm index 52ce4b0..5e98792 100644 --- a/src/PVE/API2/LXC.pm +++ b/src/PVE/API2/LXC.pm @@ -166,7 +166,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,8 +185,8 @@ __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'); @@ -315,7 +315,7 @@ __PACKAGE__->register_method({ $conf->{hostname} ||= "CT$vmid"; $conf->{memory} ||= 512; $conf->{swap} //= 512; - PVE::LXC::create_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); }; if (my $err = $@) { PVE::LXC::destroy_disks($storage_cfg, $vollist); @@ -325,7 +325,7 @@ __PACKAGE__->register_method({ PVE::AccessControl::add_vm_to_pool($vmid, $pool) if $pool; }; - my $realcmd = sub { PVE::LXC::lock_config($vmid, $code); }; + my $realcmd = sub { PVE::LXC::Config->lock_config($vmid, $code); }; &$check_vmid_usage(); # first check before locking @@ -364,7 +364,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 +503,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 +518,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 +528,7 @@ __PACKAGE__->register_method({ PVE::Firewall::remove_vmfw_conf($vmid); }; - my $realcmd = sub { PVE::LXC::lock_config($vmid, $code); }; + my $realcmd = sub { PVE::LXC::Config->lock_config($vmid, $code); }; return $rpcenv->fork_worker('vzdestroy', $vmid, $authuser, $realcmd); }}); @@ -598,7 +598,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 +719,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); @@ -786,7 +786,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 +872,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}; @@ -922,14 +922,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 +940,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); return $rpcenv->fork_worker('vztemplate', $vmid, $authuser, $realcmd); }; - PVE::LXC::lock_config($vmid, $updatefn); + PVE::LXC::Config->lock_config($vmid, $updatefn); return undef; }}); @@ -1060,9 +1060,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 +1073,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; @@ -1156,12 +1156,12 @@ __PACKAGE__->register_method({ $mp->{volume} = $newvolid; $newconf->{$opt} = PVE::LXC::print_ct_mountpoint($mp, $opt eq 'rootfs'); - PVE::LXC::write_config($newid, $newconf); + 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 +1186,7 @@ __PACKAGE__->register_method({ }; - return PVE::LXC::lock_config($vmid, $clonefn); + return PVE::LXC::Config->lock_config($vmid, $clonefn); }}); @@ -1253,8 +1253,8 @@ __PACKAGE__->register_method({ 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}); @@ -1296,7 +1296,7 @@ __PACKAGE__->register_method({ $mp->{size} = $newsize; $conf->{$disk} = PVE::LXC::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); @@ -1334,7 +1334,7 @@ __PACKAGE__->register_method({ return $rpcenv->fork_worker('resize', $vmid, $authuser, $realcmd); }; - return PVE::LXC::lock_config($vmid, $code);; + return PVE::LXC::Config->lock_config($vmid, $code);; }}); 1; diff --git a/src/PVE/API2/LXC/Config.pm b/src/PVE/API2/LXC/Config.pm index c1a97bd..04a6d85 100644 --- a/src/PVE/API2/LXC/Config.pm +++ b/src/PVE/API2/LXC/Config.pm @@ -48,7 +48,7 @@ __PACKAGE__->register_method({ code => sub { my ($param) = @_; - my $conf = PVE::LXC::load_config($param->{vmid}); + my $conf = PVE::LXC::Config->load_config($param->{vmid}); delete $conf->{snapshots}; delete $conf->{lxc}; @@ -130,8 +130,8 @@ __PACKAGE__->register_method({ 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}); @@ -139,11 +139,11 @@ __PACKAGE__->register_method({ PVE::LXC::update_pct_config($vmid, $conf, $running, $param, \@delete); - PVE::LXC::write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); PVE::LXC::update_lxc_config($storage_cfg, $vmid, $conf); }; - PVE::LXC::lock_config($vmid, $code); + PVE::LXC::Config->lock_config($vmid, $code); return undef; }}); diff --git a/src/PVE/API2/LXC/Snapshot.pm b/src/PVE/API2/LXC/Snapshot.pm index 4da2d87..90c187e 100644 --- a/src/PVE/API2/LXC/Snapshot.pm +++ b/src/PVE/API2/LXC/Snapshot.pm @@ -48,7 +48,7 @@ __PACKAGE__->register_method({ my $vmid = $param->{vmid}; - my $conf = PVE::LXC::load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); my $snaphash = $conf->{snapshots} || {}; my $res = []; @@ -299,8 +299,8 @@ __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); my $snap = $conf->{snapshots}->{$snapname}; @@ -308,10 +308,10 @@ __PACKAGE__->register_method({ $snap->{description} = $param->{description} if defined($param->{description}); - PVE::LXC::write_config($vmid, $conf, 1); + PVE::LXC::Config->write_config($vmid, $conf, 1); }; - PVE::LXC::lock_config($vmid, $updatefn); + PVE::LXC::Config->lock_config($vmid, $updatefn); return undef; }}); @@ -345,7 +345,7 @@ __PACKAGE__->register_method({ my $snapname = extract_param($param, 'snapname'); - my $conf = PVE::LXC::load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); my $snap = $conf->{snapshots}->{$snapname}; diff --git a/src/PVE/API2/LXC/Status.pm b/src/PVE/API2/LXC/Status.pm index a4498d1..c5fca29 100644 --- a/src/PVE/API2/LXC/Status.pm +++ b/src/PVE/API2/LXC/Status.pm @@ -52,7 +52,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 => 'current' }, @@ -87,7 +87,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 $vmstatus = PVE::LXC::vmstatus($param->{vmid}); my $status = $vmstatus->{$param->{vmid}}; @@ -163,13 +163,13 @@ __PACKAGE__->register_method({ syslog('info', "starting CT $vmid: $upid\n"); - my $conf = PVE::LXC::load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); die "you can't start a CT if it's a template\n" - if PVE::LXC::is_template($conf); + if PVE::LXC::Config->is_template($conf); - if (!$skiplock && !PVE::LXC::has_lock($conf, 'mounted')) { - PVE::LXC::check_lock($conf); + if (!$skiplock && !PVE::LXC::Config->has_lock($conf, 'mounted')) { + PVE::LXC::Config->check_lock($conf); } my $storage_cfg = cfs_read_file("storage.cfg"); @@ -188,7 +188,7 @@ __PACKAGE__->register_method({ return $rpcenv->fork_worker('vzstart', $vmid, $authuser, $realcmd); }; - return PVE::LXC::lock_config($vmid, $lockcmd); + return PVE::LXC::Config->lock_config($vmid, $lockcmd); } }}); @@ -256,10 +256,10 @@ __PACKAGE__->register_method({ syslog('info', "stopping CT $vmid: $upid\n"); - my $conf = PVE::LXC::load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); - if (!$skiplock && !PVE::LXC::has_lock($conf, 'mounted')) { - PVE::LXC::check_lock($conf); + if (!$skiplock && !PVE::LXC::Config->has_lock($conf, 'mounted')) { + PVE::LXC::Config->check_lock($conf); } my $cmd = ['lxc-stop', '-n', $vmid, '--kill']; @@ -272,7 +272,7 @@ __PACKAGE__->register_method({ return $rpcenv->fork_worker('vzstop', $vmid, $authuser, $realcmd); }; - return PVE::LXC::lock_config($vmid, $lockcmd); + return PVE::LXC::Config->lock_config($vmid, $lockcmd); } }}); @@ -334,9 +334,9 @@ __PACKAGE__->register_method({ $timeout = 60 if !defined($timeout); - 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 $storage_cfg = PVE::Storage::config(); @@ -365,7 +365,7 @@ __PACKAGE__->register_method({ return $rpcenv->fork_worker('vzshutdown', $vmid, $authuser, $realcmd); }; - return PVE::LXC::lock_config($vmid, $lockcmd); + return PVE::LXC::Config->lock_config($vmid, $lockcmd); }}); __PACKAGE__->register_method({ @@ -407,9 +407,9 @@ __PACKAGE__->register_method({ syslog('info', "suspend CT $vmid: $upid\n"); - 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 $cmd = ['lxc-checkpoint', '-n', $vmid, '-s', '-D', '/var/lib/vz/dump']; @@ -421,7 +421,7 @@ __PACKAGE__->register_method({ return $rpcenv->fork_worker('vzsuspend', $vmid, $authuser, $realcmd); }; - return PVE::LXC::lock_config($vmid, $lockcmd); + return PVE::LXC::Config->lock_config($vmid, $lockcmd); }}); __PACKAGE__->register_method({ diff --git a/src/PVE/CLI/pct.pm b/src/PVE/CLI/pct.pm index 6e7fcc0..1fde039 100755 --- a/src/PVE/CLI/pct.pm +++ b/src/PVE/CLI/pct.pm @@ -48,10 +48,10 @@ __PACKAGE__->register_method ({ my $vmid = $param->{vmid}; - PVE::LXC::lock_config($vmid, sub { - my $conf = PVE::LXC::load_config($vmid); + PVE::LXC::Config->lock_config($vmid, sub { + my $conf = PVE::LXC::Config->load_config($vmid); delete $conf->{lock}; - PVE::LXC::write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); }); return undef; @@ -74,7 +74,7 @@ __PACKAGE__->register_method ({ my ($param) = @_; # test if container exists on this node - my $conf = PVE::LXC::load_config($param->{vmid}); + my $conf = PVE::LXC::Config->load_config($param->{vmid}); my $cmd = PVE::LXC::get_console_command($param->{vmid}, $conf); exec(@$cmd); @@ -99,7 +99,7 @@ __PACKAGE__->register_method ({ my $vmid = $param->{vmid}; # test if container exists on this node - PVE::LXC::load_config($vmid); + PVE::LXC::Config->load_config($vmid); die "Error: container '$vmid' not running!\n" if !PVE::LXC::check_running($vmid); @@ -124,7 +124,7 @@ __PACKAGE__->register_method ({ my ($param) = @_; # test if container exists on this node - PVE::LXC::load_config($param->{vmid}); + PVE::LXC::Config->load_config($param->{vmid}); if (!@{$param->{'extra-args'}}) { die "missing command"; @@ -168,7 +168,7 @@ __PACKAGE__->register_method ({ # critical path: all of this will be done while the container is locked my $do_fsck = sub { - my $conf = PVE::LXC::load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); my $storage_cfg = PVE::Storage::config(); defined($conf->{$device}) || die "cannot run command on unexisting mountpoint $device\n"; @@ -207,7 +207,7 @@ __PACKAGE__->register_method ({ PVE::Tools::run_command($command); }; - PVE::LXC::lock_config($vmid, $do_fsck); + PVE::LXC::Config->lock_config($vmid, $do_fsck); return undef; }}); @@ -232,8 +232,8 @@ __PACKAGE__->register_method({ my $vmid = extract_param($param, 'vmid'); my $storecfg = PVE::Storage::config(); - PVE::LXC::lock_config($vmid, sub { - my $conf = PVE::LXC::set_lock($vmid, 'mounted'); + PVE::LXC::Config->lock_config($vmid, sub { + my $conf = PVE::LXC::Config->set_lock($vmid, 'mounted'); PVE::LXC::mount_all($vmid, $storecfg, $conf); }); return undef; @@ -258,10 +258,10 @@ __PACKAGE__->register_method({ my $vmid = extract_param($param, 'vmid'); my $storecfg = PVE::Storage::config(); - PVE::LXC::lock_config($vmid, sub { - my $conf = PVE::LXC::load_config($vmid); + PVE::LXC::Config->lock_config($vmid, sub { + my $conf = PVE::LXC::Config->load_config($vmid); PVE::LXC::umount_all($vmid, $storecfg, $conf, 0); - PVE::LXC::remove_lock($vmid, 'mounted'); + PVE::LXC::Config->remove_lock($vmid, 'mounted'); }); return undef; }}); @@ -401,7 +401,7 @@ __PACKAGE__->register_method({ return $rpcenv->fork_worker('pull_file', $vmid, undef, $realcmd); }; - return PVE::LXC::lock_config($vmid, $code); + return PVE::LXC::Config->lock_config($vmid, $code); }}); __PACKAGE__->register_method({ @@ -459,7 +459,7 @@ __PACKAGE__->register_method({ my $running = PVE::LXC::check_running($vmid); die "can only push files to a running VM" if !$running; - my $conf = PVE::LXC::load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); my $unprivileged = $conf->{unprivileged}; my $realcmd = sub { @@ -503,7 +503,7 @@ __PACKAGE__->register_method({ return $rpcenv->fork_worker('push_file', $vmid, undef, $realcmd); }; - return PVE::LXC::lock_config($vmid, $code); + return PVE::LXC::Config->lock_config($vmid, $code); }}); our $cmddef = { diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm index 096c88b..8f90bad 100644 --- a/src/PVE/LXC.pm +++ b/src/PVE/LXC.pm @@ -2,6 +2,7 @@ package PVE::LXC; use strict; use warnings; + use POSIX qw(EINTR); use Socket; @@ -21,6 +22,7 @@ use PVE::Tools qw($IPV6RE $IPV4RE dir_glob_foreach lock_file lock_file_full); use PVE::Network; use PVE::AccessControl; use PVE::ProcFSTools; +use PVE::LXC::Config; use Time::HiRes qw (gettimeofday); use Data::Dumper; @@ -605,99 +607,10 @@ sub config_list { return $res; } -sub cfs_config_path { - my ($vmid, $node) = @_; - - $node = $nodename if !$node; - return "nodes/$node/lxc/$vmid.conf"; -} - -sub config_file { - my ($vmid, $node) = @_; - - my $cfspath = cfs_config_path($vmid, $node); - return "/etc/pve/$cfspath"; -} - -sub load_config { - my ($vmid, $node) = @_; - - $node = $nodename if !$node; - my $cfspath = cfs_config_path($vmid, $node); - - my $conf = PVE::Cluster::cfs_read_file($cfspath); - die "container $vmid does not exist\n" if !defined($conf); - - return $conf; -} - -sub create_config { - my ($vmid, $conf) = @_; - - my $dir = "/etc/pve/nodes/$nodename/lxc"; - mkdir $dir; - - write_config($vmid, $conf); -} - sub destroy_config { my ($vmid) = @_; - unlink config_file($vmid, $nodename); -} - -sub write_config { - my ($vmid, $conf) = @_; - - my $cfspath = cfs_config_path($vmid); - - PVE::Cluster::cfs_write_file($cfspath, $conf); -} - -# flock: we use one file handle per process, so lock file -# can be called multiple times and will succeed for the same process. - -my $lock_handles = {}; -my $lockdir = "/run/lock/lxc"; - -sub config_file_lock { - my ($vmid) = @_; - - return "$lockdir/pve-config-${vmid}.lock"; -} - -sub lock_config_full { - my ($vmid, $timeout, $code, @param) = @_; - - my $filename = config_file_lock($vmid); - - mkdir $lockdir if !-d $lockdir; - - my $res = lock_file($filename, $timeout, $code, @param); - - die $@ if $@; - - return $res; -} - -sub lock_config_mode { - my ($vmid, $timeout, $shared, $code, @param) = @_; - - my $filename = config_file_lock($vmid); - - mkdir $lockdir if !-d $lockdir; - - my $res = lock_file_full($filename, $timeout, $shared, $code, @param); - - die $@ if $@; - - return $res; -} - -sub lock_config { - my ($vmid, $code, @param) = @_; - - return lock_config_full($vmid, 10, $code, @param); + unlink PVE::LXC::Config->config_file($vmid, $nodename); } sub option_exists { @@ -802,7 +715,7 @@ sub vmstatus { $d->{status} = $d->{pid} ? 'running' : 'stopped'; - my $cfspath = cfs_config_path($vmid); + my $cfspath = PVE::LXC::Config->cfs_config_path($vmid); my $conf = PVE::Cluster::cfs_read_file($cfspath) || {}; $d->{name} = $conf->{'hostname'} || "CT$vmid"; @@ -841,7 +754,7 @@ sub vmstatus { $d->{diskread} = 0; $d->{diskwrite} = 0; - $d->{template} = is_template($conf); + $d->{template} = PVE::LXC::Config->is_template($conf); } foreach my $vmid (keys %$list) { @@ -1063,24 +976,6 @@ sub parse_ipv4_cidr { die "unable to parse ipv4 address/mask\n"; } -sub check_lock { - my ($conf) = @_; - - die "VM is locked ($conf->{'lock'})\n" if $conf->{'lock'}; -} - -sub has_lock { - my ($conf, $lock) = @_; - return $conf->{lock} && (!defined($lock) || $lock eq $conf->{lock}); -} - -sub check_protection { - my ($vm_conf, $err_msg) = @_; - - if ($vm_conf->{protection}) { - die "$err_msg - protection mode enabled\n"; - } -} sub update_lxc_config { my ($storage_cfg, $vmid, $conf) = @_; @@ -1326,7 +1221,7 @@ sub update_pct_config { } else { die "implement me (delete: $opt)" } - write_config($vmid, $conf) if $running; + PVE::LXC::Config->write_config($vmid, $conf) if $running; } } @@ -1356,7 +1251,7 @@ sub update_pct_config { $conf->{memory} = $wanted_memory; $conf->{swap} = $wanted_swap; - write_config($vmid, $conf) if $running; + PVE::LXC::Config->write_config($vmid, $conf) if $running; } my $used_volids = {}; @@ -1433,7 +1328,7 @@ sub update_pct_config { } else { die "implement me: $opt"; } - write_config($vmid, $conf) if $running; + PVE::LXC::Config->write_config($vmid, $conf) if $running; } # Apply deletions and creations of new volumes @@ -1598,7 +1493,7 @@ sub update_net { PVE::Network::veth_delete($veth); delete $conf->{$opt}; - write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); hotplug_net($vmid, $conf, $opt, $newnet, $netid); @@ -1612,7 +1507,7 @@ sub update_net { delete $oldnet->{$_}; } $conf->{$opt} = print_lxc_network($oldnet); - write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); } PVE::Network::tap_plug($veth, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}); @@ -1620,7 +1515,7 @@ sub update_net { $oldnet->{$_} = $newnet->{$_} if $newnet->{$_}; } $conf->{$opt} = print_lxc_network($oldnet); - write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); } } else { hotplug_net($vmid, $conf, $opt, $newnet, $netid); @@ -1653,7 +1548,7 @@ sub hotplug_net { } $conf->{$opt} = print_lxc_network($done); - write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); } sub update_ipconfig { @@ -1757,7 +1652,7 @@ sub update_ipconfig { } } $conf->{$opt} = print_lxc_network($optdata); - write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); $lxc_setup->setup_network($conf); }; @@ -1820,12 +1715,12 @@ sub snapshot_prepare { my $updatefn = sub { - my $conf = load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); die "you can't take a snapshot if it's a template\n" - if is_template($conf); + if PVE::LXC::Config->is_template($conf); - check_lock($conf); + PVE::LXC::Config->check_lock($conf); $conf->{lock} = 'snapshot'; @@ -1848,10 +1743,10 @@ sub snapshot_prepare { $snap->{snaptime} = time(); $snap->{description} = $comment if $comment; - write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); }; - lock_config($vmid, $updatefn); + PVE::LXC::Config->lock_config($vmid, $updatefn); return $snap; } @@ -1861,7 +1756,7 @@ sub snapshot_commit { my $updatefn = sub { - my $conf = load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); die "missing snapshot lock\n" if !($conf->{lock} && $conf->{lock} eq 'snapshot'); @@ -1877,10 +1772,10 @@ sub snapshot_commit { $conf->{parent} = $snapname; - write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); }; - lock_config($vmid, $updatefn); + PVE::LXC::Config->lock_config($vmid, $updatefn); } sub has_feature { @@ -1983,7 +1878,7 @@ sub snapshot_create { $save_vmstate = 0 if !$snap->{vmstate}; - my $conf = load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); my ($running, $freezefs) = check_freeze_needed($vmid, $conf, $snap->{vmstate}); @@ -2047,12 +1942,12 @@ sub snapshot_delete { my $updatefn = sub { my ($remove_drive) = @_; - my $conf = load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); if (!$drivehash) { - check_lock($conf); + PVE::LXC::Config->check_lock($conf); die "you can't delete a snapshot if vm is a template\n" - if is_template($conf); + if PVE::LXC::Config->is_template($conf); } $snap = $conf->{snapshots}->{$snapname}; @@ -2089,10 +1984,10 @@ sub snapshot_delete { } } - write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); }; - lock_config($vmid, $updatefn); + PVE::LXC::Config->lock_config($vmid, $updatefn); # now remove vmstate file # never set for LXC! @@ -2116,13 +2011,13 @@ sub snapshot_delete { } # save changes (remove mp from snapshot) - lock_config($vmid, $updatefn, $ms) if !$force; + PVE::LXC::Config->lock_config($vmid, $updatefn, $ms) if !$force; push @$unused, $mountpoint->{volume}; }); # now cleanup config $prepare = 0; - lock_config($vmid, $updatefn); + PVE::LXC::Config->lock_config($vmid, $updatefn); } sub snapshot_rollback { @@ -2132,11 +2027,11 @@ sub snapshot_rollback { my $storecfg = PVE::Storage::config(); - my $conf = load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); my $get_snapshot_config = sub { - die "you can't rollback if vm is a template\n" if is_template($conf); + die "you can't rollback if vm is a template\n" if PVE::LXC::Config->is_template($conf); my $res = $conf->{snapshots}->{$snapname}; @@ -2155,7 +2050,7 @@ sub snapshot_rollback { my $updatefn = sub { - $conf = load_config($vmid); + $conf = PVE::LXC::Config->load_config($vmid); $snap = &$get_snapshot_config(); @@ -2163,7 +2058,7 @@ sub snapshot_rollback { if $snap->{snapstate}; if ($prepare) { - check_lock($conf); + PVE::LXC::Config->check_lock($conf); PVE::Tools::run_command(['/usr/bin/lxc-stop', '-n', $vmid, '--kill']) if check_running($vmid); } @@ -2186,14 +2081,14 @@ sub snapshot_rollback { $conf->{parent} = $snapname; } - write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); if (!$prepare && $snap->{vmstate}) { die "implement me - save vmstate\n"; } }; - lock_config($vmid, $updatefn); + PVE::LXC::Config->lock_config($vmid, $updatefn); foreach_mountpoint($snap, sub { my ($ms, $mountpoint) = @_; @@ -2202,7 +2097,7 @@ sub snapshot_rollback { }); $prepare = 0; - lock_config($vmid, $updatefn); + PVE::LXC::Config->lock_config($vmid, $updatefn); } sub template_create { @@ -2222,13 +2117,7 @@ sub template_create { $rootinfo->{volume} = $template_volid; $conf->{rootfs} = print_ct_mountpoint($rootinfo, 1); - write_config($vmid, $conf); -} - -sub is_template { - my ($conf) = @_; - - return 1 if defined $conf->{template} && $conf->{template} == 1; + PVE::LXC::Config->write_config($vmid, $conf); } sub mountpoint_names { @@ -2785,30 +2674,5 @@ sub userns_command { return []; } -sub set_lock { - my ($vmid, $lock) = @_; - my $conf; - lock_config($vmid, sub { - $conf = load_config($vmid); - check_lock($conf); - $conf->{lock} = $lock; - write_config($vmid, $conf); - }); - return $conf; -} - -sub remove_lock { - my ($vmid, $lock) = @_; - lock_config($vmid, sub { - my $conf = load_config($vmid); - if (!$conf->{lock}) { - die "no lock found trying to remove lock '$lock'\n"; - } elsif (defined($lock) && $conf->{lock} ne $lock) { - die "found lock '$conf->{lock}' trying to remove lock '$lock'\n"; - } - delete $conf->{lock}; - write_config($vmid, $conf); - }); -} 1; diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm new file mode 100644 index 0000000..f37586a --- /dev/null +++ b/src/PVE/LXC/Config.pm @@ -0,0 +1,43 @@ +package PVE::LXC::Config; + +use strict; +use warnings; + +use PVE::AbstractConfig; +use PVE::Cluster qw(cfs_register_file); +use PVE::INotify; +use PVE::JSONSchema qw(get_standard_option); +use PVE::Tools; + +use base qw(PVE::AbstractConfig); + +my $nodename = PVE::INotify::nodename(); +my $lock_handles = {}; +my $lockdir = "/run/lock/lxc"; +mkdir $lockdir; +mkdir "/etc/pve/nodes/$nodename/lxc"; +my $MAX_MOUNT_POINTS = 10; +my $MAX_UNUSED_DISKS = $MAX_MOUNT_POINTS; + +# BEGIN implemented abstract methods from PVE::AbstractConfig + +sub guest_type { + return "CT"; +} + +sub config_file_lock { + my ($class, $vmid) = @_; + + return "$lockdir/pve-config-${vmid}.lock"; +} + +sub cfs_config_path { + my ($class, $vmid, $node) = @_; + + $node = $nodename if !$node; + return "nodes/$node/lxc/$vmid.conf"; +} + +# END implemented abstract methods from PVE::AbstractConfig + +return 1; diff --git a/src/PVE/LXC/Create.pm b/src/PVE/LXC/Create.pm index ac51a7c..a7c66a1 100644 --- a/src/PVE/LXC/Create.pm +++ b/src/PVE/LXC/Create.pm @@ -141,7 +141,7 @@ sub restore_and_configure { if (!$restore) { my $lxc_setup = PVE::LXC::Setup->new($conf, $rootdir); # detect OS - PVE::LXC::write_config($vmid, $conf); # safe config (after OS detection) + PVE::LXC::Config->write_config($vmid, $conf); # safe config (after OS detection) $lxc_setup->post_create_hook($password); } else { # restore: try to extract configuration from archive @@ -193,11 +193,11 @@ sub restore_and_configure { sub create_rootfs { my ($storage_cfg, $vmid, $conf, $archive, $password, $restore, $no_unpack_error) = @_; - my $config_fn = PVE::LXC::config_file($vmid); + my $config_fn = PVE::LXC::Config->config_file($vmid); if (-f $config_fn) { die "container exists" if !$restore; # just to be sure - my $old_conf = PVE::LXC::load_config($vmid); + my $old_conf = PVE::LXC::Config->load_config($vmid); # destroy old container volume PVE::LXC::destroy_lxc_container($storage_cfg, $vmid, $old_conf); @@ -212,11 +212,11 @@ sub create_rootfs { PVE::LXC::update_pct_config($vmid, $conf, 0, $old_conf); - PVE::LXC::create_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); } else { - PVE::LXC::create_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); } eval { diff --git a/src/PVE/LXC/Makefile b/src/PVE/LXC/Makefile index f0ada85..8a0224b 100644 --- a/src/PVE/LXC/Makefile +++ b/src/PVE/LXC/Makefile @@ -1,4 +1,4 @@ -SOURCES=Setup.pm Create.pm Migrate.pm +SOURCES=Setup.pm Create.pm Migrate.pm Config.pm .PHONY: install install: ${SOURCES} diff --git a/src/PVE/LXC/Migrate.pm b/src/PVE/LXC/Migrate.pm index 94d53a2..ba23f1a 100644 --- a/src/PVE/LXC/Migrate.pm +++ b/src/PVE/LXC/Migrate.pm @@ -16,7 +16,7 @@ use base qw(PVE::AbstractMigrate); sub lock_vm { my ($self, $vmid, $code, @param) = @_; - return PVE::LXC::lock_config($vmid, $code, @param); + return PVE::LXC::Config->lock_config($vmid, $code, @param); } sub prepare { @@ -27,9 +27,9 @@ sub prepare { $self->{storecfg} = PVE::Storage::config(); # test is VM exist - my $conf = $self->{vmconf} = PVE::LXC::load_config($vmid); + my $conf = $self->{vmconf} = PVE::LXC::Config->load_config($vmid); - PVE::LXC::check_lock($conf); + PVE::LXC::Config->check_lock($conf); my $running = 0; if (PVE::LXC::check_running($vmid)) { @@ -75,7 +75,7 @@ sub phase1 { my $conf = $self->{vmconf}; $conf->{lock} = 'migrate'; - PVE::LXC::write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); if ($self->{running}) { $self->log('info', "container is running - using online migration"); @@ -100,8 +100,8 @@ sub phase1 { } }); - my $conffile = PVE::LXC::config_file($vmid); - my $newconffile = PVE::LXC::config_file($vmid, $self->{node}); + my $conffile = PVE::LXC::Config->config_file($vmid); + my $newconffile = PVE::LXC::Config->config_file($vmid, $self->{node}); if ($self->{running}) { die "implement me"; @@ -162,7 +162,7 @@ sub final_cleanup { my $conf = $self->{vmconf}; delete $conf->{lock}; - eval { PVE::LXC::write_config($vmid, $conf); }; + eval { PVE::LXC::Config->write_config($vmid, $conf); }; if (my $err = $@) { $self->log('err', $err); } diff --git a/src/PVE/VZDump/LXC.pm b/src/PVE/VZDump/LXC.pm index 4401f50..2e431f9 100644 --- a/src/PVE/VZDump/LXC.pm +++ b/src/PVE/VZDump/LXC.pm @@ -97,7 +97,7 @@ my $check_mountpoint_empty = sub { sub prepare { my ($self, $task, $vmid, $mode) = @_; - my $conf = $self->{vmlist}->{$vmid} = PVE::LXC::load_config($vmid); + my $conf = $self->{vmlist}->{$vmid} = PVE::LXC::Config->load_config($vmid); my $storage_cfg = $self->{storecfg}; my $running = PVE::LXC::check_running($vmid); @@ -177,15 +177,15 @@ sub lock_vm { my $lockconfig = sub { my ($self, $vmid) = @_; - 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); $conf->{lock} = 'backup'; - PVE::LXC::write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); }; - PVE::LXC::lock_config($vmid, $lockconfig, ($self, $vmid)); + PVE::LXC::Config->lock_config($vmid, $lockconfig, ($self, $vmid)); } sub unlock_vm { @@ -194,15 +194,15 @@ sub unlock_vm { my $unlockconfig = sub { my ($self, $vmid) = @_; - my $conf = PVE::LXC::load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); if ($conf->{lock} && $conf->{lock} eq 'backup') { delete $conf->{lock}; - PVE::LXC::write_config($vmid, $conf); + PVE::LXC::Config->write_config($vmid, $conf); } }; - PVE::LXC::lock_config($vmid, $unlockconfig, ($self, $vmid)); + PVE::LXC::Config->lock_config($vmid, $unlockconfig, ($self, $vmid)); } sub snapshot { @@ -215,7 +215,7 @@ sub snapshot { $task->{cleanup}->{remove_snapshot} = 1; # reload config - my $conf = $self->{vmlist}->{$vmid} = PVE::LXC::load_config($vmid); + my $conf = $self->{vmlist}->{$vmid} = PVE::LXC::Config->load_config($vmid); die "unable to read vzdump snapshot config - internal error" if !($conf->{snapshots} && $conf->{snapshots}->{vzdump}); @@ -288,7 +288,7 @@ sub assemble { mkpath "$tmpdir/etc/vzdump/"; - my $conf = PVE::LXC::load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); delete $conf->{lock}; delete $conf->{snapshots}; delete $conf->{'pve.parent'}; @@ -376,7 +376,7 @@ sub archive { sub cleanup { my ($self, $task, $vmid) = @_; - my $conf = PVE::LXC::load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); if ($task->{mode} ne 'suspend') { my $rootdir = $default_mount_point; diff --git a/src/lxc-pve-poststop-hook b/src/lxc-pve-poststop-hook index 4415ee3..6f37088 100755 --- a/src/lxc-pve-poststop-hook +++ b/src/lxc-pve-poststop-hook @@ -49,9 +49,9 @@ __PACKAGE__->register_method ({ my $vmid = $param->{name}; - return undef if ! -f PVE::LXC::config_file($vmid); + return undef if ! -f PVE::LXC::Config->config_file($vmid); - my $conf = PVE::LXC::load_config($vmid); + my $conf = PVE::LXC::Config->load_config($vmid); my $storage_cfg = PVE::Storage::config(); diff --git a/src/lxc-pve-prestart-hook b/src/lxc-pve-prestart-hook index 28e1a36..7cb9cb6 100755 --- a/src/lxc-pve-prestart-hook +++ b/src/lxc-pve-prestart-hook @@ -60,11 +60,11 @@ __PACKAGE__->register_method ({ PVE::Cluster::check_cfs_quorum(); # only start if we have quorum - return undef if ! -f PVE::LXC::config_file($vmid); + return undef if ! -f PVE::LXC::Config->config_file($vmid); - my $conf = PVE::LXC::load_config($vmid); - if (!$ENV{PVE_SKIPLOCK} && !PVE::LXC::has_lock($conf, 'mounted')) { - PVE::LXC::check_lock($conf); + my $conf = PVE::LXC::Config->load_config($vmid); + if (!$ENV{PVE_SKIPLOCK} && !PVE::LXC::Config->has_lock($conf, 'mounted')) { + PVE::LXC::Config->check_lock($conf); } my $storage_cfg = PVE::Storage::config(); diff --git a/src/lxcnetaddbr b/src/lxcnetaddbr index 254ea6c..a297bf2 100755 --- a/src/lxcnetaddbr +++ b/src/lxcnetaddbr @@ -24,7 +24,7 @@ die "got unexpected environment" if $vmid ne $ENV{LXC_NAME}; die "missing vmid parameter\n" if !$vmid; die "missing iface parameter\n" if !$iface; -my $conf = PVE::LXC::load_config($vmid); +my $conf = PVE::LXC::Config->load_config($vmid); my $netconf; if ($iface =~ m/^veth(\d+)i(\d+)$/) { diff --git a/src/test/snapshot-test.pm b/src/test/snapshot-test.pm index c0504f6..60b63fb 100644 --- a/src/test/snapshot-test.pm +++ b/src/test/snapshot-test.pm @@ -8,6 +8,7 @@ use lib qw(..); use PVE::Storage; use PVE::Storage::Plugin; use PVE::LXC; +use PVE::LXC::Config; use PVE::Tools; use Test::MockModule; @@ -212,22 +213,22 @@ sub testcase_rollback { }; } -# BEGIN redefine PVE::LXC methods -sub config_file_lock { +# BEGIN mocked PVE::LXC::Config methods +sub mocked_config_file_lock { return "snapshot-working/pve-test.lock"; } -sub cfs_config_path { - my ($vmid, $node) = @_; +sub mocked_cfs_config_path { + my ($class, $vmid, $node) = @_; $node = $nodename if !$node; return "snapshot-working/$node/lxc/$vmid.conf"; } -sub load_config { - my ($vmid, $node) = @_; +sub mocked_load_config { + my ($class, $vmid, $node) = @_; - my $filename = cfs_config_path($vmid, $node); + my $filename = PVE::LXC::Config->cfs_config_path($vmid, $node); my $raw = PVE::Tools::file_get_contents($filename); @@ -235,10 +236,10 @@ sub load_config { return $conf; } -sub write_config { - my ($vmid, $conf) = @_; +sub mocked_write_config { + my ($class, $vmid, $conf) = @_; - my $filename = cfs_config_path($vmid); + my $filename = PVE::LXC::Config->cfs_config_path($vmid); if ($conf->{snapshots}) { foreach my $snapname (keys %{$conf->{snapshots}}) { @@ -260,6 +261,7 @@ sub has_feature { sub check_running { return $running; } +# END mocked PVE::LXC methods sub sync_container_namespace { return; @@ -270,6 +272,12 @@ sub sync_container_namespace { PVE::Tools::run_command("rm -rf snapshot-working"); PVE::Tools::run_command("cp -a snapshot-input snapshot-working"); +my $lxc_config_module = new Test::MockModule('PVE::LXC::Config'); +$lxc_config_module->mock('config_file_lock', sub { return "snapshot-working/pve-test.lock"; }); +$lxc_config_module->mock('cfs_config_path', \&mocked_cfs_config_path); +$lxc_config_module->mock('load_config', \&mocked_load_config); +$lxc_config_module->mock('write_config', \&mocked_write_config); + $running = 1; $freeze_possible = 1; @@ -290,7 +298,7 @@ printf("Successful snapshot_prepare with one existing snapshot\n"); testcase_prepare("102", "test2", 0, "test comment", ""); printf("Expected error for snapshot_prepare on locked container\n"); -testcase_prepare("200", "test", 0, "test comment", "VM is locked (snapshot)\n"); +testcase_prepare("200", "test", 0, "test comment", "CT is locked (snapshot)\n"); printf("Expected error for snapshot_prepare with duplicate snapshot name\n"); testcase_prepare("201", "test", 0, "test comment", "snapshot name 'test' already used\n"); @@ -416,7 +424,7 @@ printf("Expected error when snapshot_delete fails with broken mp volume_snapshot testcase_delete("203", "test", 0, "volume snapshot delete disabled\n", { "local:snapshotable-disk-1" => "test" }); printf("Expected error for snapshot_delete with locked config\n"); -testcase_delete("202", "test", 0, "VM is locked (backup)\n"); +testcase_delete("202", "test", 0, "CT is locked (backup)\n"); $nodename = "rollback"; printf("\n"); @@ -450,7 +458,7 @@ printf("Expected error for snapshot_rollback with incomplete snapshot\n"); testcase_rollback("203", "test", "unable to rollback to incomplete snapshot (snapstate = delete)\n"); printf("Expected error for snapshot_rollback with lock\n"); -testcase_rollback("204", "test", "VM is locked (backup)\n"); +testcase_rollback("204", "test", "CT is locked (backup)\n"); printf("Expected error for snapshot_rollback with saved vmstate\n"); testcase_rollback("205", "test", "implement me - save vmstate\n", { "local:snapshotable-disk-1" => "test" }); -- 2.39.2