[pve-devel] [PATCH v2 ha-manager 04/12] Implement update_service_config for simulation
Signed-off-by: Fabian Ebner --- src/PVE/HA/Sim/Hardware.pm | 16 1 file changed, 16 insertions(+) diff --git a/src/PVE/HA/Sim/Hardware.pm b/src/PVE/HA/Sim/Hardware.pm index 8bd5cbd..d2c0ec0 100644 --- a/src/PVE/HA/Sim/Hardware.pm +++ b/src/PVE/HA/Sim/Hardware.pm @@ -109,6 +109,22 @@ sub read_service_config { return $conf; } +sub update_service_config { +my ($self, $digest, $delete, $sid, $param) = @_; + +die "not implemented" if ($digest || $delete); + +my $conf = $self->read_service_config(); + +my $sconf = $conf->{$sid} || die "no such resource '$sid'\n"; + +foreach my $k (%$param) { + $sconf->{$k} = $param->{$k}; +} + +$self->write_service_config($conf); +} + sub write_service_config { my ($self, $conf) = @_; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 ha-manager 06/12] Use timeout for shutdown in LRM
Signed-off-by: Fabian Ebner --- src/PVE/HA/LRM.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PVE/HA/LRM.pm b/src/PVE/HA/LRM.pm index 3b4a572..e5eee94 100644 --- a/src/PVE/HA/LRM.pm +++ b/src/PVE/HA/LRM.pm @@ -535,7 +535,7 @@ sub manage_resources { my $req_state = $sd->{state}; next if !defined($req_state); next if $req_state eq 'freeze'; - $self->queue_resource_command($sid, $sd->{uid}, $req_state, {'target' => $sd->{target}}); + $self->queue_resource_command($sid, $sd->{uid}, $req_state, {'target' => $sd->{target}, 'timeout' => $sd->{timeout}}); } return $self->run_workers(); @@ -776,7 +776,7 @@ sub exec_resource_agent { $haenv->log("info", "stopping service $sid"); - $plugin->shutdown($haenv, $id); + $plugin->shutdown($haenv, $id, $params->{timeout}); $running = $plugin->check_running($haenv, $id); -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 ha-manager 01/12] Make parameters for LRM resource commands more flexible
This will allow for new parameters beside 'target' to be used. This is in preparation to allow for a 'timeout' parameter for a new 'stop' command. Signed-off-by: Fabian Ebner --- src/PVE/HA/LRM.pm | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/PVE/HA/LRM.pm b/src/PVE/HA/LRM.pm index af4e21e..3b4a572 100644 --- a/src/PVE/HA/LRM.pm +++ b/src/PVE/HA/LRM.pm @@ -477,7 +477,7 @@ sub run_workers { # do work my $res = -1; eval { - $res = $self->exec_resource_agent($sid, $sc->{$sid}, $w->{state}, $w->{target}); + $res = $self->exec_resource_agent($sid, $sc->{$sid}, $w->{state}, $w->{params}); }; if (my $err = $@) { $haenv->log('err', $err); @@ -491,7 +491,7 @@ sub run_workers { } else { my $res = -1; eval { - $res = $self->exec_resource_agent($sid, $sc->{$sid}, $w->{state}, $w->{target}); + $res = $self->exec_resource_agent($sid, $sc->{$sid}, $w->{state}, $w->{params}); $res = $res << 8 if $res > 0; }; if (my $err = $@) { @@ -535,14 +535,14 @@ sub manage_resources { my $req_state = $sd->{state}; next if !defined($req_state); next if $req_state eq 'freeze'; - $self->queue_resource_command($sid, $sd->{uid}, $req_state, $sd->{target}); + $self->queue_resource_command($sid, $sd->{uid}, $req_state, {'target' => $sd->{target}}); } return $self->run_workers(); } sub queue_resource_command { -my ($self, $sid, $uid, $state, $target) = @_; +my ($self, $sid, $uid, $state, $params) = @_; # do not queue the excatly same command twice as this may lead to # an inconsistent HA state when the first command fails but the CRM @@ -564,7 +564,7 @@ sub queue_resource_command { state => $state, }; -$self->{workers}->{$sid}->{target} = $target if $target; +$self->{workers}->{$sid}->{params} = $params if $params; } sub check_active_workers { @@ -711,7 +711,7 @@ sub handle_service_exitcode { } sub exec_resource_agent { -my ($self, $sid, $service_config, $cmd, @params) = @_; +my ($self, $sid, $service_config, $cmd, $params) = @_; # setup execution environment @@ -790,7 +790,7 @@ sub exec_resource_agent { } elsif ($cmd eq 'migrate' || $cmd eq 'relocate') { - my $target = $params[0]; + my $target = $params->{target}; if (!defined($target)) { die "$cmd '$sid' failed - missing target\n" if !defined($target); return EINVALID_PARAMETER; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 ha-manager 11/12] Log timeout parameter when present
Signed-off-by: Fabian Ebner --- src/PVE/HA/LRM.pm | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/PVE/HA/LRM.pm b/src/PVE/HA/LRM.pm index e5eee94..95ec351 100644 --- a/src/PVE/HA/LRM.pm +++ b/src/PVE/HA/LRM.pm @@ -774,7 +774,11 @@ sub exec_resource_agent { return SUCCESS if !$running; - $haenv->log("info", "stopping service $sid"); + if (defined($params->{timeout})) { + $haenv->log("info", "stopping service $sid (timeout=$params->{timeout})"); + } else { + $haenv->log("info", "stopping service $sid"); + } $plugin->shutdown($haenv, $id, $params->{timeout}); -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 ha-manager 07/12] Add stop command to the API
Signed-off-by: Fabian Ebner --- src/PVE/API2/HA/Resources.pm | 37 src/PVE/CLI/ha_manager.pm| 2 ++ 2 files changed, 39 insertions(+) diff --git a/src/PVE/API2/HA/Resources.pm b/src/PVE/API2/HA/Resources.pm index 2b62ee8..ecc5f0c 100644 --- a/src/PVE/API2/HA/Resources.pm +++ b/src/PVE/API2/HA/Resources.pm @@ -353,4 +353,41 @@ __PACKAGE__->register_method ({ return undef; }}); +__PACKAGE__->register_method ({ +name => 'stop', +protected => 1, +path => '{sid}/stop', +method => 'POST', +description => "Request the service to be stopped.", +permissions => { + check => ['perm', '/', [ 'Sys.Console' ]], +}, +parameters => { + additionalProperties => 0, + properties => { + sid => get_standard_option('pve-ha-resource-or-vm-id', + { completion => \&PVE::HA::Tools::complete_sid }), + timeout => { + description => "Timeout in seconds. If set to 0 a hard stop will be performed.", + type => 'integer', + minimum => 0, + optional => 1, + }, + }, +}, +returns => { type => 'null' }, +code => sub { + my ($param) = @_; + + my ($sid, $type, $name) = PVE::HA::Config::parse_sid(extract_param($param, 'sid')); + + PVE::HA::Config::service_is_ha_managed($sid); + + check_service_state($sid); + + PVE::HA::Config::queue_crm_commands("stop $sid $param->{timeout}"); + + return undef; +}}); + 1; diff --git a/src/PVE/CLI/ha_manager.pm b/src/PVE/CLI/ha_manager.pm index 5ce4c30..c9d4e7f 100644 --- a/src/PVE/CLI/ha_manager.pm +++ b/src/PVE/CLI/ha_manager.pm @@ -114,6 +114,8 @@ our $cmddef = { migrate => [ "PVE::API2::HA::Resources", 'migrate', ['sid', 'node'] ], relocate => [ "PVE::API2::HA::Resources", 'relocate', ['sid', 'node'] ], +stop => [ "PVE::API2::HA::Resources", 'stop', ['sid', 'timeout'] ], + }; 1; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 ha-manager 08/12] Rename target to param in simulation
In preparation to introduce a stop command with a timeout parameter. Signed-off-by: Fabian Ebner --- src/PVE/HA/Sim/Hardware.pm | 18 +- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/PVE/HA/Sim/Hardware.pm b/src/PVE/HA/Sim/Hardware.pm index d2c0ec0..ac0c142 100644 --- a/src/PVE/HA/Sim/Hardware.pm +++ b/src/PVE/HA/Sim/Hardware.pm @@ -553,7 +553,7 @@ sub sim_hardware_cmd { my $cstatus = $self->read_hardware_status_nolock(); - my ($cmd, $objid, $action, $target) = split(/\s+/, $cmdstr); + my ($cmd, $objid, $action, $param) = split(/\s+/, $cmdstr); die "sim_hardware_cmd: no node or service for command specified" if !$objid; @@ -617,10 +617,10 @@ sub sim_hardware_cmd { } elsif ($cmd eq 'cfs') { die "sim_hardware_cmd: unknown cfs action '$action' for node '$node'" if $action !~ m/^(rw|update)$/; - die "sim_hardware_cmd: unknown cfs command '$target' for '$action' on node '$node'" - if $target !~ m/^(work|fail)$/; + die "sim_hardware_cmd: unknown cfs command '$param' for '$action' on node '$node'" + if $param !~ m/^(work|fail)$/; - $cstatus->{$node}->{cfs}->{$action} = $target eq 'work'; + $cstatus->{$node}->{cfs}->{$action} = $param eq 'work'; $self->write_hardware_status_nolock($cstatus); } elsif ($cmd eq 'reboot' || $cmd eq 'shutdown') { @@ -656,13 +656,13 @@ sub sim_hardware_cmd { } elsif ($action eq 'migrate' || $action eq 'relocate') { die "sim_hardware_cmd: missing target node for '$action' command" - if !$target; + if !$param; - $self->queue_crm_commands_nolock("$action $sid $target"); + $self->queue_crm_commands_nolock("$action $sid $param"); } elsif ($action eq 'add') { - $self->add_service($sid, {state => 'started', node => $target}); + $self->add_service($sid, {state => 'started', node => $param}); } elsif ($action eq 'delete') { @@ -670,11 +670,11 @@ sub sim_hardware_cmd { } elsif ($action eq 'lock') { - $self->lock_service($sid, $target); + $self->lock_service($sid, $param); } elsif ($action eq 'unlock') { - $self->unlock_service($sid, $target); + $self->unlock_service($sid, $param); } else { die "sim_hardware_cmd: unknown service action '$action' " . -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 ha-manager 09/12] Add stop command to simulation
Signed-off-by: Fabian Ebner --- src/PVE/HA/Sim/Hardware.pm | 8 1 file changed, 8 insertions(+) diff --git a/src/PVE/HA/Sim/Hardware.pm b/src/PVE/HA/Sim/Hardware.pm index ac0c142..7e1a8bc 100644 --- a/src/PVE/HA/Sim/Hardware.pm +++ b/src/PVE/HA/Sim/Hardware.pm @@ -543,6 +543,7 @@ sub get_cfs_state { # restart-lrm # service # service +# service stop # service lock/unlock [lockname] sub sim_hardware_cmd { @@ -660,6 +661,13 @@ sub sim_hardware_cmd { $self->queue_crm_commands_nolock("$action $sid $param"); + } elsif ($action eq 'stop') { + + die "sim_hardware_cmd: missing timeout for '$action' command" + if !defined($param); + + $self->queue_crm_commands_nolock("$action $sid $param"); + } elsif ($action eq 'add') { $self->add_service($sid, {state => 'started', node => $param}); -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 ha-manager 05/12] Add timeout parameter for shutdown
Introduces a timeout parameter for shutting a resource down. If the parameter is 0, we perform a hard stop instead of a shutdown. Signed-off-by: Fabian Ebner --- src/PVE/HA/Resources.pm | 2 +- src/PVE/HA/Resources/PVECT.pm | 14 ++ src/PVE/HA/Resources/PVEVM.pm | 16 +++- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/PVE/HA/Resources.pm b/src/PVE/HA/Resources.pm index 7c373bc..835c314 100644 --- a/src/PVE/HA/Resources.pm +++ b/src/PVE/HA/Resources.pm @@ -126,7 +126,7 @@ sub start { } sub shutdown { -my ($class, $haenv, $id) = @_; +my ($class, $haenv, $id, $timeout) = @_; die "implement in subclass"; } diff --git a/src/PVE/HA/Resources/PVECT.pm b/src/PVE/HA/Resources/PVECT.pm index a0f05f4..282f4ef 100644 --- a/src/PVE/HA/Resources/PVECT.pm +++ b/src/PVE/HA/Resources/PVECT.pm @@ -74,18 +74,24 @@ sub start { } sub shutdown { -my ($class, $haenv, $id) = @_; +my ($class, $haenv, $id, $timeout) = @_; my $nodename = $haenv->nodename(); -my $shutdown_timeout = 60; # fixme: make this configurable +my $shutdown_timeout = $timeout // 60; +my $upid; my $params = { node => $nodename, vmid => $id, - timeout => $shutdown_timeout, }; -my $upid = PVE::API2::LXC::Status->vm_shutdown($params); +if ($shutdown_timeout) { + $params->{timeout} = $shutdown_timeout; + $upid = PVE::API2::LXC::Status->vm_shutdown($params); +} else { + $upid = PVE::API2::LXC::Status->vm_stop($params); +} + PVE::HA::Tools::upid_wait($upid, $haenv); } diff --git a/src/PVE/HA/Resources/PVEVM.pm b/src/PVE/HA/Resources/PVEVM.pm index 9dcf558..45d87e8 100644 --- a/src/PVE/HA/Resources/PVEVM.pm +++ b/src/PVE/HA/Resources/PVEVM.pm @@ -72,19 +72,25 @@ sub start { } sub shutdown { -my ($class, $haenv, $id) = @_; +my ($class, $haenv, $id, $timeout) = @_; my $nodename = $haenv->nodename(); -my $shutdown_timeout = 60; # fixme: make this configurable +my $shutdown_timeout = $timeout // 60; +my $upid; my $params = { node => $nodename, vmid => $id, - timeout => $shutdown_timeout, - forceStop => 1, }; -my $upid = PVE::API2::Qemu->vm_shutdown($params); +if ($shutdown_timeout) { + $params->{timeout} = $shutdown_timeout; + $params->{forceStop} = 1; + $upid = PVE::API2::Qemu->vm_shutdown($params); +} else { + $upid = PVE::API2::Qemu->vm_stop($params); +} + PVE::HA::Tools::upid_wait($upid, $haenv); } -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 ha-manager 00/12] Implement a stop command for HA
This patch series introduces a new 'stop' command for ha-manager. The command takes a timeout parameter and in case it is 0, it performs a hard stop. The series also includes a test for the new command. A few changes to how parameters were handled in CRM/LRM were necessary as well as allowing the service config to be updated from within the manager. Changes from v1: * Lock HA domain inside update_resources_config * Don't set a default timeout in LRM * Different logging depending on whether timeout parameter is present * Split old 08/13 into two patches to separate renaming and adding the new command Fabian Ebner (12): Make parameters for LRM resource commands more flexible Move code updating resource config from API2::HA::Resources to HA::Config Add update_service_config to HA environment interface Implement update_service_config for simulation Add timeout parameter for shutdown Use timeout for shutdown in LRM Add stop command to the API Rename target to param in simulation Add stop command to simulation Add crm command 'stop' Log timeout parameter when present Add test for the stop command src/PVE/API2/HA/Resources.pm| 71 +++-- src/PVE/CLI/ha_manager.pm | 2 + src/PVE/HA/Config.pm| 37 +++ src/PVE/HA/Env.pm | 6 ++ src/PVE/HA/Env/PVE2.pm | 6 ++ src/PVE/HA/LRM.pm | 22 --- src/PVE/HA/Manager.pm | 27 ++-- src/PVE/HA/Resources.pm | 2 +- src/PVE/HA/Resources/PVECT.pm | 14 ++-- src/PVE/HA/Resources/PVEVM.pm | 16 +++-- src/PVE/HA/Sim/Env.pm | 6 ++ src/PVE/HA/Sim/Hardware.pm | 42 +--- src/test/test-stop-command1/README | 2 + src/test/test-stop-command1/cmdlist | 8 +++ src/test/test-stop-command1/hardware_status | 5 ++ src/test/test-stop-command1/log.expect | 69 src/test/test-stop-command1/manager_status | 1 + src/test/test-stop-command1/service_config | 6 ++ 18 files changed, 277 insertions(+), 65 deletions(-) create mode 100644 src/test/test-stop-command1/README create mode 100644 src/test/test-stop-command1/cmdlist create mode 100644 src/test/test-stop-command1/hardware_status create mode 100644 src/test/test-stop-command1/log.expect create mode 100644 src/test/test-stop-command1/manager_status create mode 100644 src/test/test-stop-command1/service_config -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 ha-manager 03/12] Add update_service_config to HA environment interface
Signed-off-by: Fabian Ebner --- src/PVE/HA/Env.pm | 6 ++ src/PVE/HA/Env/PVE2.pm | 6 ++ src/PVE/HA/Sim/Env.pm | 6 ++ 3 files changed, 18 insertions(+) diff --git a/src/PVE/HA/Env.pm b/src/PVE/HA/Env.pm index bb37486..7acd7c5 100644 --- a/src/PVE/HA/Env.pm +++ b/src/PVE/HA/Env.pm @@ -87,6 +87,12 @@ sub read_service_config { return $self->{plug}->read_service_config(); } +sub update_service_config { +my ($self, $digest, $delete, $sid, $param) = @_; + +return $self->{plug}->update_service_config($digest, $delete, $sid, $param); +} + sub parse_sid { my ($self, $sid) = @_; diff --git a/src/PVE/HA/Env/PVE2.pm b/src/PVE/HA/Env/PVE2.pm index 796acd9..1e92687 100644 --- a/src/PVE/HA/Env/PVE2.pm +++ b/src/PVE/HA/Env/PVE2.pm @@ -120,6 +120,12 @@ sub read_service_config { return PVE::HA::Config::read_and_check_resources_config(); } +sub update_service_config { +my ($self, $digest, $delete, $sid, $param) = @_; + +return PVE::HA::Config::update_resources_config($digest, $delete, $sid, $param); +} + sub parse_sid { my ($self, $sid) = @_; diff --git a/src/PVE/HA/Sim/Env.pm b/src/PVE/HA/Sim/Env.pm index 22e13e6..f400365 100644 --- a/src/PVE/HA/Sim/Env.pm +++ b/src/PVE/HA/Sim/Env.pm @@ -203,6 +203,12 @@ sub read_service_config { return $self->{hardware}->read_service_config(); } +sub update_service_config { +my ($self, $digest, $delete, $sid, $param) = @_; + +return $self->{hardware}->update_service_config($digest, $delete, $sid, $param); +} + sub parse_sid { my ($self, $sid) = @_; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 ha-manager 02/12] Move code updating resource config from API2::HA::Resources to HA::Config
This makes it easier to update the resource configuration from within the CRM/LRM stack, which is needed for the new 'stop' command. Signed-off-by: Fabian Ebner --- src/PVE/API2/HA/Resources.pm | 34 + src/PVE/HA/Config.pm | 37 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/PVE/API2/HA/Resources.pm b/src/PVE/API2/HA/Resources.pm index 22d7f28..2b62ee8 100644 --- a/src/PVE/API2/HA/Resources.pm +++ b/src/PVE/API2/HA/Resources.pm @@ -237,39 +237,7 @@ __PACKAGE__->register_method ({ check_service_state($sid, $param->{state}); - PVE::HA::Config::lock_ha_domain( - sub { - - my $cfg = PVE::HA::Config::read_resources_config(); - - PVE::SectionConfig::assert_if_modified($cfg, $digest); - - my $scfg = $cfg->{ids}->{$sid} || - die "no such resource '$sid'\n"; - - my $plugin = PVE::HA::Resources->lookup($scfg->{type}); - my $opts = $plugin->check_config($sid, $param, 0, 1); - - foreach my $k (%$opts) { - $scfg->{$k} = $opts->{$k}; - } - - if ($delete) { - my $options = $plugin->private()->{options}->{$type}; - foreach my $k (PVE::Tools::split_list($delete)) { - my $d = $options->{$k} || - die "no such option '$k'\n"; - die "unable to delete required option '$k'\n" - if !$d->{optional}; - die "unable to delete fixed option '$k'\n" - if $d->{fixed}; - delete $scfg->{$k}; - } - } - - PVE::HA::Config::write_resources_config($cfg) - - }, "update resource failed"); + PVE::HA::Config::update_resources_config($digest, $delete, $sid, $param); return undef; }}); diff --git a/src/PVE/HA/Config.pm b/src/PVE/HA/Config.pm index ead1ee2..e800154 100644 --- a/src/PVE/HA/Config.pm +++ b/src/PVE/HA/Config.pm @@ -125,6 +125,43 @@ sub read_and_check_resources_config { return $conf; } +sub update_resources_config { +my ($digest, $delete, $sid, $param) = @_; + +lock_ha_domain( + sub { + my $cfg = read_resources_config(); + ($sid, my $type, my $name) = parse_sid($sid); + + PVE::SectionConfig::assert_if_modified($cfg, $digest); + + my $scfg = $cfg->{ids}->{$sid} || + die "no such resource '$sid'\n"; + + my $plugin = PVE::HA::Resources->lookup($scfg->{type}); + my $opts = $plugin->check_config($sid, $param, 0, 1); + + foreach my $k (%$opts) { + $scfg->{$k} = $opts->{$k}; + } + + if ($delete) { + my $options = $plugin->private()->{options}->{$type}; + foreach my $k (PVE::Tools::split_list($delete)) { + my $d = $options->{$k} || + die "no such option '$k'\n"; + die "unable to delete required option '$k'\n" + if !$d->{optional}; + die "unable to delete fixed option '$k'\n" + if $d->{fixed}; + delete $scfg->{$k}; + } + } + + write_resources_config($cfg); + }, "update resources config failed"); +} + sub parse_sid { my ($sid) = @_; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 ha-manager 12/12] Add test for the stop command
Signed-off-by: Fabian Ebner --- src/test/test-stop-command1/README | 2 + src/test/test-stop-command1/cmdlist | 8 +++ src/test/test-stop-command1/hardware_status | 5 ++ src/test/test-stop-command1/log.expect | 69 + src/test/test-stop-command1/manager_status | 1 + src/test/test-stop-command1/service_config | 6 ++ 6 files changed, 91 insertions(+) create mode 100644 src/test/test-stop-command1/README create mode 100644 src/test/test-stop-command1/cmdlist create mode 100644 src/test/test-stop-command1/hardware_status create mode 100644 src/test/test-stop-command1/log.expect create mode 100644 src/test/test-stop-command1/manager_status create mode 100644 src/test/test-stop-command1/service_config diff --git a/src/test/test-stop-command1/README b/src/test/test-stop-command1/README new file mode 100644 index 000..d725380 --- /dev/null +++ b/src/test/test-stop-command1/README @@ -0,0 +1,2 @@ +Test the stop command with different timeouts +and what happens with a failed service. diff --git a/src/test/test-stop-command1/cmdlist b/src/test/test-stop-command1/cmdlist new file mode 100644 index 000..c7c9e67 --- /dev/null +++ b/src/test/test-stop-command1/cmdlist @@ -0,0 +1,8 @@ +[ +[ "power node1 on", "power node2 on", "power node3 on" ], +[ "service vm:101 stop 0" ], +[ "service vm:101 stop 1" ], +[ "service vm:102 stop 37" ], +[ "service vm:103 stop 60" ], +[ "service fa:1001 stop 0" ] +] diff --git a/src/test/test-stop-command1/hardware_status b/src/test/test-stop-command1/hardware_status new file mode 100644 index 000..451beb1 --- /dev/null +++ b/src/test/test-stop-command1/hardware_status @@ -0,0 +1,5 @@ +{ + "node1": { "power": "off", "network": "off" }, + "node2": { "power": "off", "network": "off" }, + "node3": { "power": "off", "network": "off" } +} diff --git a/src/test/test-stop-command1/log.expect b/src/test/test-stop-command1/log.expect new file mode 100644 index 000..05f9712 --- /dev/null +++ b/src/test/test-stop-command1/log.expect @@ -0,0 +1,69 @@ +info 0 hardware: starting simulation +info 20 cmdlist: execute power node1 on +info 20node1/crm: status change startup => wait_for_quorum +info 20node1/lrm: status change startup => wait_for_agent_lock +info 20 cmdlist: execute power node2 on +info 20node2/crm: status change startup => wait_for_quorum +info 20node2/lrm: status change startup => wait_for_agent_lock +info 20 cmdlist: execute power node3 on +info 20node3/crm: status change startup => wait_for_quorum +info 20node3/lrm: status change startup => wait_for_agent_lock +info 20node1/crm: got lock 'ha_manager_lock' +info 20node1/crm: status change wait_for_quorum => master +info 20node1/crm: node 'node1': state changed from 'unknown' => 'online' +info 20node1/crm: node 'node2': state changed from 'unknown' => 'online' +info 20node1/crm: node 'node3': state changed from 'unknown' => 'online' +info 20node1/crm: adding new service 'fa:1001' on node 'node3' +info 20node1/crm: adding new service 'vm:101' on node 'node1' +info 20node1/crm: adding new service 'vm:102' on node 'node2' +info 20node1/crm: adding new service 'vm:103' on node 'node3' +info 21node1/lrm: got lock 'ha_agent_node1_lock' +info 21node1/lrm: status change wait_for_agent_lock => active +info 21node1/lrm: starting service vm:101 +info 21node1/lrm: service status vm:101 started +info 22node2/crm: status change wait_for_quorum => slave +info 23node2/lrm: got lock 'ha_agent_node2_lock' +info 23node2/lrm: status change wait_for_agent_lock => active +info 23node2/lrm: starting service vm:102 +info 23node2/lrm: service status vm:102 started +info 24node3/crm: status change wait_for_quorum => slave +info 25node3/lrm: got lock 'ha_agent_node3_lock' +info 25node3/lrm: status change wait_for_agent_lock => active +info 25node3/lrm: starting service fa:1001 +info 25node3/lrm: service status fa:1001 started +info 25node3/lrm: starting service vm:103 +info 25node3/lrm: service status vm:103 started +info120 cmdlist: execute service vm:101 stop 0 +info120node1/crm: got crm command: stop vm:101 0 +info120node1/crm: stop service with timeout '0' +info120node1/crm: service 'vm:101': state changed from 'started' to 'request_stop' (timeout = 0) +info121node1/lrm: stopping service vm:101 (timeout=0) +info121node1/lrm: service status vm:101 stopped +info140node1/crm: service 'vm:101': state changed from 'request_stop' to 'stopped' +info220 cmdlist: execute service vm:101 stop 1 +info220node1/crm: got crm command: stop vm:101 1 +info220node1/crm: ignore service 'vm:101' stop request - serv
[pve-devel] [PATCH v2 ha-manager 10/12] Add crm command 'stop'
Not every command parameter is 'target' anymore, so it was necessary to modify the parsing of $sd->{cmd}. Just changing the state to request_stop is not enough, we need to actually update the service configuration as well. Signed-off-by: Fabian Ebner --- src/PVE/HA/Manager.pm | 27 +++ 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/PVE/HA/Manager.pm b/src/PVE/HA/Manager.pm index 5137de8..3c4cf61 100644 --- a/src/PVE/HA/Manager.pm +++ b/src/PVE/HA/Manager.pm @@ -349,6 +349,14 @@ sub update_crm_commands { $haenv->log('err', "crm command error - no such service: $cmd"); } + } elsif ($cmd =~ m/^stop\s+(\S+)\s+(\S+)$/) { + my ($sid, $timeout) = ($1, $2); + if (my $sd = $ss->{$sid}) { + $haenv->log('info', "got crm command: $cmd"); + $ss->{$sid}->{cmd} = [ 'stop', $timeout ]; + } else { + $haenv->log('err', "crm command error - no such service: $cmd"); + } } else { $haenv->log('err', "unable to parse crm command: $cmd"); } @@ -561,10 +569,10 @@ sub next_state_stopped { } if ($sd->{cmd}) { - my ($cmd, $target) = @{$sd->{cmd}}; - delete $sd->{cmd}; + my $cmd = shift @{$sd->{cmd}}; if ($cmd eq 'migrate' || $cmd eq 'relocate') { + my $target = shift @{$sd->{cmd}}; if (!$ns->node_is_online($target)) { $haenv->log('err', "ignore service '$sid' $cmd request - node '$target' not online"); } elsif ($sd->{node} eq $target) { @@ -574,9 +582,12 @@ sub next_state_stopped { target => $target); return; } + } elsif ($cmd eq 'stop') { + $haenv->log('info', "ignore service '$sid' $cmd request - service already stopped"); } else { $haenv->log('err', "unknown command '$cmd' for service '$sid'"); } + delete $sd->{cmd}; } if ($cd->{state} eq 'disabled') { @@ -638,10 +649,10 @@ sub next_state_started { if ($cd->{state} eq 'started') { if ($sd->{cmd}) { - my ($cmd, $target) = @{$sd->{cmd}}; - delete $sd->{cmd}; + my $cmd = shift @{$sd->{cmd}}; if ($cmd eq 'migrate' || $cmd eq 'relocate') { + my $target = shift @{$sd->{cmd}}; if (!$ns->node_is_online($target)) { $haenv->log('err', "ignore service '$sid' $cmd request - node '$target' not online"); } elsif ($sd->{node} eq $target) { @@ -650,9 +661,17 @@ sub next_state_started { $haenv->log('info', "$cmd service '$sid' to node '$target'"); &$change_service_state($self, $sid, $cmd, node => $sd->{node}, target => $target); } + } elsif ($cmd eq 'stop') { + my $timeout = shift @{$sd->{cmd}}; + $haenv->log('info', "$cmd service with timeout '$timeout'"); + &$change_service_state($self, $sid, 'request_stop', timeout => $timeout); + $haenv->update_service_config(0, 0, $sid, {'state' => 'stopped'}); } else { $haenv->log('err', "unknown command '$cmd' for service '$sid'"); } + + delete $sd->{cmd}; + } else { my $try_next = 0; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH pve-network 3/8] add faucet sdn controller plugins
1 plugin for controller, 1 plugin for dataplane This is not 100% complete, but it's a proof of concept to test differents sdn controller Signed-off-by: Alexandre Derumier --- PVE/API2/Network/SDN.pm| 3 + PVE/Network/SDN.pm | 19 ++ PVE/Network/SDN/FaucetPlugin.pm| 102 + PVE/Network/SDN/Makefile | 2 +- PVE/Network/SDN/OVSFaucetPlugin.pm | 76 + PVE/Network/SDN/Plugin.pm | 5 ++ 6 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 PVE/Network/SDN/FaucetPlugin.pm create mode 100644 PVE/Network/SDN/OVSFaucetPlugin.pm diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm index 043aa0d..e4ed5cc 100644 --- a/PVE/API2/Network/SDN.pm +++ b/PVE/API2/Network/SDN.pm @@ -12,6 +12,9 @@ use PVE::Network::SDN::VlanPlugin; use PVE::Network::SDN::VxlanPlugin; use PVE::Network::SDN::VnetPlugin; use PVE::Network::SDN::FrrPlugin; +use PVE::Network::SDN::OVSFaucetPlugin; +use PVE::Network::SDN::FaucetPlugin; + use Storable qw(dclone); use PVE::JSONSchema qw(get_standard_option); use PVE::RPCEnvironment; diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm index b5d98b7..1946bc5 100644 --- a/PVE/Network/SDN.pm +++ b/PVE/Network/SDN.pm @@ -13,11 +13,15 @@ use PVE::Network::SDN::VnetPlugin; use PVE::Network::SDN::VlanPlugin; use PVE::Network::SDN::VxlanPlugin; use PVE::Network::SDN::FrrPlugin; +use PVE::Network::SDN::OVSFaucetPlugin; +use PVE::Network::SDN::FaucetPlugin; PVE::Network::SDN::VnetPlugin->register(); PVE::Network::SDN::VlanPlugin->register(); PVE::Network::SDN::VxlanPlugin->register(); PVE::Network::SDN::FrrPlugin->register(); +PVE::Network::SDN::OVSFaucetPlugin->register(); +PVE::Network::SDN::FaucetPlugin->register(); PVE::Network::SDN::Plugin->init(); @@ -203,6 +207,21 @@ sub generate_controller_config { $controller_plugin->generate_controller_transport_config($plugin_config, $controller, $id, $uplinks, $config); } } + } elsif ($role eq 'vnet') { + my $transportid = $plugin_config->{transportzone}; + if ($transportid) { + my $transport = $sdn_cfg->{ids}->{$transportid}; + if ($transport) { + my $controllerid = $transport->{controller}; + if ($controllerid) { + my $controller = $sdn_cfg->{ids}->{$controllerid}; + if ($controller) { + my $controller_plugin = PVE::Network::SDN::Plugin->lookup($controller->{type}); + $controller_plugin->generate_controller_vnet_config($plugin_config, $controller, $transportid, $id, $config); + } + } + } + } } } diff --git a/PVE/Network/SDN/FaucetPlugin.pm b/PVE/Network/SDN/FaucetPlugin.pm new file mode 100644 index 000..9e313c3 --- /dev/null +++ b/PVE/Network/SDN/FaucetPlugin.pm @@ -0,0 +1,102 @@ +package PVE::Network::SDN::FaucetPlugin; + +use strict; +use warnings; +use PVE::Network::SDN::Plugin; +use PVE::Tools; +use PVE::INotify; +use PVE::JSONSchema qw(get_standard_option); +use CPAN::Meta::YAML; +use Encode; + +use base('PVE::Network::SDN::Plugin'); + +sub type { +return 'faucet'; +} + +sub plugindata { +return { +role => 'controller', +}; +} + +sub properties { +return { +}; +} + +# Plugin implementation +sub generate_controller_config { +my ($class, $plugin_config, $router, $id, $uplinks, $config) = @_; + +} + +sub generate_controller_transport_config { +my ($class, $plugin_config, $router, $id, $uplinks, $config) = @_; + +my $dpid = $plugin_config->{'dp-id'}; +my $dphex = printf("%x",$dpid); + +my $transport_config = { + dp_id => $dphex, + hardware => "Open vSwitch", + }; + +$config->{faucet}->{dps}->{$id} = $transport_config; + +} + + +sub generate_controller_vnet_config { +my ($class, $plugin_config, $controller, $transportid, $vnetid, $config) = @_; + +my $mac = $plugin_config->{mac}; +my $ipv4 = $plugin_config->{ipv4}; +my $ipv6 = $plugin_config->{ipv6}; +my $tag = $plugin_config->{tag}; +my $alias = $plugin_config->{alias}; + +my @ips = (); +push @ips, $ipv4 if $ipv4; +push @ips, $ipv6 if $ipv6; + +my $vlan_config = { vid => $tag }; + +$vlan_config->{description} = $alias if $alias; +$vlan_config->{faucet_mac} = $mac if $mac; +$vlan_config->{faucet_vips} = \@ips if scalar @ips > 0; + +$config->{faucet}->{vlans}->{$vnetid} = $vlan_config; + +push(@{$config->{faucet}->{routers}->{$transportid}->{vlans}} , $vnetid); + +} + +sub on_delete_hook { +my ($class, $routerid, $sdn_cfg) = @_; + +} + +sub on_update_hook { +my ($class, $routerid, $sdn_cfg) = @_; + +} + +sub write_controller_config { +
[pve-devel] [PATCH pve-network 4/8] add evpnplugin (splitted from vxlanplugin)
Signed-off-by: Alexandre Derumier --- PVE/API2/Network/SDN.pm| 1 + PVE/Network/SDN.pm | 2 + PVE/Network/SDN/EvpnPlugin.pm | 200 + PVE/Network/SDN/Makefile | 2 +- PVE/Network/SDN/VxlanPlugin.pm | 54 - test/documentation.txt | 4 +- 6 files changed, 206 insertions(+), 57 deletions(-) create mode 100644 PVE/Network/SDN/EvpnPlugin.pm diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm index e4ed5cc..cbd393e 100644 --- a/PVE/API2/Network/SDN.pm +++ b/PVE/API2/Network/SDN.pm @@ -14,6 +14,7 @@ use PVE::Network::SDN::VnetPlugin; use PVE::Network::SDN::FrrPlugin; use PVE::Network::SDN::OVSFaucetPlugin; use PVE::Network::SDN::FaucetPlugin; +use PVE::Network::SDN::EvpnPlugin; use Storable qw(dclone); use PVE::JSONSchema qw(get_standard_option); diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm index 1946bc5..137f9f9 100644 --- a/PVE/Network/SDN.pm +++ b/PVE/Network/SDN.pm @@ -15,6 +15,7 @@ use PVE::Network::SDN::VxlanPlugin; use PVE::Network::SDN::FrrPlugin; use PVE::Network::SDN::OVSFaucetPlugin; use PVE::Network::SDN::FaucetPlugin; +use PVE::Network::SDN::EvpnPlugin; PVE::Network::SDN::VnetPlugin->register(); PVE::Network::SDN::VlanPlugin->register(); @@ -22,6 +23,7 @@ PVE::Network::SDN::VxlanPlugin->register(); PVE::Network::SDN::FrrPlugin->register(); PVE::Network::SDN::OVSFaucetPlugin->register(); PVE::Network::SDN::FaucetPlugin->register(); +PVE::Network::SDN::EvpnPlugin->register(); PVE::Network::SDN::Plugin->init(); diff --git a/PVE/Network/SDN/EvpnPlugin.pm b/PVE/Network/SDN/EvpnPlugin.pm new file mode 100644 index 000..f570f2f --- /dev/null +++ b/PVE/Network/SDN/EvpnPlugin.pm @@ -0,0 +1,200 @@ +package PVE::Network::SDN::EvpnPlugin; + +use strict; +use warnings; +use PVE::Network::SDN::Plugin; +use PVE::Tools qw($IPV4RE); +use PVE::INotify; + +use base('PVE::Network::SDN::VxlanPlugin'); + +sub type { +return 'evpn'; +} + +sub plugindata { +return { +role => 'transport', +}; +} + +sub properties { +return { + 'vrf' => { + description => "vrf name.", + type => 'string', #fixme: format + }, + 'vrf-vxlan' => { + type => 'integer', + description => "l3vni.", + }, + 'controller' => { + type => 'string', + description => "Frr router name", + }, +}; +} + +sub options { + +return { + 'uplink-id' => { optional => 0 }, +'vxlan-allowed' => { optional => 1 }, +'vrf' => { optional => 0 }, +'vrf-vxlan' => { optional => 0 }, +'controller' => { optional => 0 }, +}; +} + +# Plugin implementation +sub generate_sdn_config { +my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks, $config) = @_; + +my $tag = $vnet->{tag}; +my $alias = $vnet->{alias}; +my $ipv4 = $vnet->{ipv4}; +my $ipv6 = $vnet->{ipv6}; +my $mac = $vnet->{mac}; + +my $uplink = $plugin_config->{'uplink-id'}; +my $vxlanallowed = $plugin_config->{'vxlan-allowed'}; +my $vrf = $plugin_config->{'vrf'}; +my $vrfvxlan = $plugin_config->{'vrf-vxlan'}; + +die "missing vxlan tag" if !$tag; +my $iface = "uplink$uplink"; +my $ifaceip = ""; + +if($uplinks->{$uplink}->{name}) { + $iface = $uplinks->{$uplink}->{name}; + $ifaceip = PVE::Network::SDN::Plugin::get_first_local_ipv4_from_interface($iface); +} + +my $mtu = 1450; +$mtu = $uplinks->{$uplink}->{mtu} - 50 if $uplinks->{$uplink}->{mtu}; +$mtu = $vnet->{mtu} if $vnet->{mtu}; + +#vxlan interface +my @iface_config = (); +push @iface_config, "vxlan-id $tag"; + +push @iface_config, "vxlan-local-tunnelip $ifaceip" if $ifaceip; +push @iface_config, "bridge-learning off"; +push @iface_config, "bridge-arp-nd-suppress on"; + +push @iface_config, "mtu $mtu" if $mtu; +push(@{$config->{"vxlan$vnetid"}}, @iface_config) if !$config->{"vxlan$vnetid"}; + +#vnet bridge +@iface_config = (); +push @iface_config, "address $ipv4" if $ipv4; +push @iface_config, "address $ipv6" if $ipv6; +push @iface_config, "hwaddress $mac" if $mac; +push @iface_config, "bridge_ports vxlan$vnetid"; +push @iface_config, "bridge_stp off"; +push @iface_config, "bridge_fd 0"; +push @iface_config, "mtu $mtu" if $mtu; +push @iface_config, "alias $alias" if $alias; +push @iface_config, "ip-forward on" if $ipv4; +push @iface_config, "ip6-forward on" if $ipv6; +push @iface_config, "arp-accept on" if $ipv4||$ipv6; +push @iface_config, "vrf $vrf" if $vrf; +push(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid}; + +if ($vrf) { + #vrf interface + @iface_config = (); + push @iface_config, "vrf-table auto"; + push(@{$config->{$vrf}}, @iface_config) if !$config->{$vrf}; + + if ($vrfvxlan) { + #l3vni vxlan interface + my $iface_vxla
[pve-devel] [PATCH pve-network 5/8] add controller_reload
Signed-off-by: Alexandre Derumier --- PVE/Network/SDN.pm | 17 + PVE/Network/SDN/FaucetPlugin.pm | 11 +++ PVE/Network/SDN/FrrPlugin.pm| 18 ++ PVE/Network/SDN/Plugin.pm | 6 ++ 4 files changed, 52 insertions(+) diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm index 137f9f9..8e96084 100644 --- a/PVE/Network/SDN.pm +++ b/PVE/Network/SDN.pm @@ -230,6 +230,23 @@ sub generate_controller_config { return $config; } + +sub reload_controller { + +my $sdn_cfg = PVE::Cluster::cfs_read_file('sdn.cfg'); +return if !$sdn_cfg; + +foreach my $id (keys %{$sdn_cfg->{ids}}) { + my $plugin_config = $sdn_cfg->{ids}->{$id}; + my $plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type}); + my $pd = $plugin->plugindata(); + my $role = $pd->{role}; + if ($role eq 'controller') { + $plugin->reload_controller(); + } +} +} + sub write_etc_network_config { my ($rawconfig) = @_; diff --git a/PVE/Network/SDN/FaucetPlugin.pm b/PVE/Network/SDN/FaucetPlugin.pm index 9e313c3..fe75efb 100644 --- a/PVE/Network/SDN/FaucetPlugin.pm +++ b/PVE/Network/SDN/FaucetPlugin.pm @@ -98,5 +98,16 @@ sub write_controller_config { $writefh->close(); } +sub reload_controller { +my ($class) = @_; + +my $conf_file = "/etc/faucet/faucet.yaml"; +my $bin_path = "/usr/bin/faucet"; + +if (-e $conf_file && -e $bin_path) { +PVE::Tools::run_command(['systemctl', 'reload', 'faucet']); +} +} + 1; diff --git a/PVE/Network/SDN/FrrPlugin.pm b/PVE/Network/SDN/FrrPlugin.pm index 532247a..3410844 100644 --- a/PVE/Network/SDN/FrrPlugin.pm +++ b/PVE/Network/SDN/FrrPlugin.pm @@ -290,6 +290,24 @@ sub write_controller_config { $writefh->close(); } +sub reload_controller { +my ($class) = @_; + +my $conf_file = "/etc/frr/frr.conf"; +my $bin_path = "/usr/bin/vtysh"; + +my $err = sub { + my $line = shift; + if ($line =~ /^line (\S+)/) { + print "$line \n"; + } +}; + +if (-e $conf_file && -e $bin_path) { + PVE::Tools::run_command([$bin_path, '-m', '-f', $conf_file], outfunc => {}, errfunc => $err); +} +} + 1; diff --git a/PVE/Network/SDN/Plugin.pm b/PVE/Network/SDN/Plugin.pm index 605fd06..0c6eaf0 100644 --- a/PVE/Network/SDN/Plugin.pm +++ b/PVE/Network/SDN/Plugin.pm @@ -88,6 +88,12 @@ sub write_controller_config { die "please implement inside plugin"; } +sub controller_reload { +my ($class) = @_; + +die "please implement inside plugin"; +} + sub on_delete_hook { my ($class, $sndid, $scfg) = @_; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH pve-network 7/8] add qinq plugin
move code from vlanplugin, add transport tag option Signed-off-by: Alexandre Derumier --- PVE/API2/Network/SDN.pm | 1 + PVE/Network/SDN.pm| 2 + PVE/Network/SDN/Makefile | 2 +- PVE/Network/SDN/QinQPlugin.pm | 81 +++ PVE/Network/SDN/VlanPlugin.pm | 19 5 files changed, 85 insertions(+), 20 deletions(-) create mode 100644 PVE/Network/SDN/QinQPlugin.pm diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm index 8294cb8..36d293d 100644 --- a/PVE/API2/Network/SDN.pm +++ b/PVE/API2/Network/SDN.pm @@ -15,6 +15,7 @@ use PVE::Network::SDN::FaucetControllerPlugin; use PVE::Network::SDN::FaucetPlugin; use PVE::Network::SDN::EvpnControllerPlugin; use PVE::Network::SDN::EvpnPlugin; +use PVE::Network::SDN::QinQPlugin; use Storable qw(dclone); use PVE::JSONSchema qw(get_standard_option); diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm index 8e8e637..96f76d1 100644 --- a/PVE/Network/SDN.pm +++ b/PVE/Network/SDN.pm @@ -16,6 +16,7 @@ use PVE::Network::SDN::FaucetPlugin; use PVE::Network::SDN::FaucetControllerPlugin; use PVE::Network::SDN::EvpnPlugin; use PVE::Network::SDN::EvpnControllerPlugin; +use PVE::Network::SDN::QinQPlugin; PVE::Network::SDN::VnetPlugin->register(); PVE::Network::SDN::VlanPlugin->register(); @@ -24,6 +25,7 @@ PVE::Network::SDN::FaucetControllerPlugin->register(); PVE::Network::SDN::FaucetPlugin->register(); PVE::Network::SDN::EvpnPlugin->register(); PVE::Network::SDN::EvpnControllerPlugin->register(); +PVE::Network::SDN::QinQPlugin->register(); PVE::Network::SDN::Plugin->init(); diff --git a/PVE/Network/SDN/Makefile b/PVE/Network/SDN/Makefile index ba8f903..232db52 100644 --- a/PVE/Network/SDN/Makefile +++ b/PVE/Network/SDN/Makefile @@ -1,4 +1,4 @@ -SOURCES=Plugin.pm VnetPlugin.pm VlanPlugin.pm VxlanPlugin.pm FaucetControllerPlugin.pm FaucetPlugin.pm EvpnPlugin.pm EvpnControllerPlugin.pm +SOURCES=Plugin.pm VnetPlugin.pm VlanPlugin.pm VxlanPlugin.pm FaucetControllerPlugin.pm FaucetPlugin.pm EvpnPlugin.pm EvpnControllerPlugin.pm QinQPlugin.pm PERL5DIR=${DESTDIR}/usr/share/perl5 diff --git a/PVE/Network/SDN/QinQPlugin.pm b/PVE/Network/SDN/QinQPlugin.pm new file mode 100644 index 000..9f40e84 --- /dev/null +++ b/PVE/Network/SDN/QinQPlugin.pm @@ -0,0 +1,81 @@ +package PVE::Network::SDN::QinQPlugin; + +use strict; +use warnings; +use PVE::Network::SDN::VlanPlugin; + +use base('PVE::Network::SDN::VlanPlugin'); + +sub type { +return 'qinq'; +} + +sub plugindata { +return { + role => 'transport', +}; +} + +sub properties { +return { + 'vlan-protocol' => { + type => 'string', +enum => ['802.1q', '802.1ad'], + default => '802.1q', + optional => 1, + description => "vlan protocol", + } +}; +} + +sub options { + +return { + 'uplink-id' => { optional => 0 }, + 'tag' => { optional => 0 }, +'vlan-allowed' => { optional => 1 }, + 'vlan-protocol' => { optional => 1 }, +}; +} + +# Plugin implementation +sub generate_sdn_config { +my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks, $config) = @_; + +my $tag = $vnet->{tag}; +my $transport_tag = $plugin_config->{tag}; +my $mtu = $vnet->{mtu}; +my $alias = $vnet->{alias}; +my $vlanprotocol = $plugin_config->{'vlan-protocol'}; +my $uplink = $plugin_config->{'uplink-id'}; +my $vlanallowed = $plugin_config->{'vlan-allowed'}; + +die "missing vlan tag" if !$tag; +die "missing transport vlan tag" if !$transport_tag; + +my $iface = $uplinks->{$uplink}->{name}; +$iface = "uplink${uplink}" if !$iface; +$iface .= ".$transport_tag"; + +#tagged interface +my @iface_config = (); +push @iface_config, "vlan-protocol $vlanprotocol" if $vlanprotocol; +push @iface_config, "mtu $mtu" if $mtu; +push(@{$config->{$iface}}, @iface_config) if !$config->{$iface}; + +$iface .= ".$tag"; +#vnet bridge +@iface_config = (); +push @iface_config, "bridge_ports $iface"; +push @iface_config, "bridge_stp off"; +push @iface_config, "bridge_fd 0"; +push @iface_config, "mtu $mtu" if $mtu; +push @iface_config, "alias $alias" if $alias; +push(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid}; + +return $config; +} + +1; + + diff --git a/PVE/Network/SDN/VlanPlugin.pm b/PVE/Network/SDN/VlanPlugin.pm index 6078206..5a38f59 100644 --- a/PVE/Network/SDN/VlanPlugin.pm +++ b/PVE/Network/SDN/VlanPlugin.pm @@ -36,17 +36,6 @@ sub properties { type => 'string', format => 'pve-sdn-vlanrange', description => "Allowed vlan range", }, - 'vlan-aware' => { -type => 'boolean', - description => "enable 802.1q stacked vlan", - }, - 'vlan-protocol' => { - type => 'string', -enum => ['802.1q', '802.1ad'], - default => '802.1q', - optional => 1, -
[pve-devel] [PATCH pve-network 0/8] generic sdn controller plugins + improvments
This patch serie mainly rework the plugins to manage sdn controllers. currently it was working with frr only, now it's possible to define differents plugins for sdn controllers. Frr specific code has been move to his own plugins too. For true sdn, we have 2 plugins, 1 for dataplane (switch/bridge setup), 1 for controlplane (the controller). (As we can have multiple dataplanes for 1 controller) I have added a (not fully working yet) poc with faucet sdn controller plugin. I have made also split of some plugins (evpn,qinq) to their own plugins. Alexandre Derumier (8): make sdn controller plugin generic vxlan: move transport controller config to frrplugin add faucet sdn controller plugins add evpnplugin (splitted from vxlanplugin) add controller_reload rename plugins with controllers add qinq plugin api2 : sdn : add role and type to index PVE/API2/Network/SDN.pm | 18 +- PVE/Network/SDN.pm| 180 + PVE/Network/SDN/EvpnControllerPlugin.pm | 313 ++ PVE/Network/SDN/EvpnPlugin.pm | 200 ++ PVE/Network/SDN/FaucetControllerPlugin.pm | 113 PVE/Network/SDN/FaucetPlugin.pm | 76 ++ PVE/Network/SDN/FrrPlugin.pm | 142 -- PVE/Network/SDN/Makefile | 2 +- PVE/Network/SDN/Plugin.pm | 19 +- PVE/Network/SDN/QinQPlugin.pm | 81 ++ PVE/Network/SDN/VlanPlugin.pm | 25 +- PVE/Network/SDN/VnetPlugin.pm | 6 + PVE/Network/SDN/VxlanPlugin.pm| 110 +--- test/documentation.txt| 8 +- test/generateconfig.pl| 10 +- 15 files changed, 910 insertions(+), 393 deletions(-) create mode 100644 PVE/Network/SDN/EvpnControllerPlugin.pm create mode 100644 PVE/Network/SDN/EvpnPlugin.pm create mode 100644 PVE/Network/SDN/FaucetControllerPlugin.pm create mode 100644 PVE/Network/SDN/FaucetPlugin.pm delete mode 100644 PVE/Network/SDN/FrrPlugin.pm create mode 100644 PVE/Network/SDN/QinQPlugin.pm -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH pve-network 8/8] api2 : sdn : add role and type to index
Signed-off-by: Alexandre Derumier --- PVE/API2/Network/SDN.pm | 11 ++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm index 36d293d..b6dd23e 100644 --- a/PVE/API2/Network/SDN.pm +++ b/PVE/API2/Network/SDN.pm @@ -61,7 +61,10 @@ __PACKAGE__->register_method ({ type => 'array', items => { type => "object", - properties => { sdn => { type => 'string'} }, + properties => { sdn => { type => 'string'}, + type => { type => 'string'}, + role => { type => 'string'} + }, }, links => [ { rel => 'child', href => "{sdn}" } ], }, @@ -82,6 +85,12 @@ __PACKAGE__->register_method ({ my $scfg = &$api_sdn_config($cfg, $sdnid); next if $param->{type} && $param->{type} ne $scfg->{type}; + + my $plugin_config = $cfg->{ids}->{$sdnid}; + my $plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type}); + my $pd = $plugin->plugindata(); + my $role = $pd->{role}; + $scfg->{role} = $role; push @$res, $scfg; } -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH pve-network 2/8] vxlan: move transport controller config to frrplugin
To be able to use differents controllers model Signed-off-by: Alexandre Derumier --- PVE/Network/SDN.pm | 4 +-- PVE/Network/SDN/FrrPlugin.pm | 51 ++ PVE/Network/SDN/VxlanPlugin.pm | 50 - 3 files changed, 53 insertions(+), 52 deletions(-) diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm index 1e5ba67..b5d98b7 100644 --- a/PVE/Network/SDN.pm +++ b/PVE/Network/SDN.pm @@ -199,8 +199,8 @@ sub generate_controller_config { if ($controllerid) { my $controller = $sdn_cfg->{ids}->{$controllerid}; if ($controller) { - my $controller_plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type}); - $controller_plugin->generate_controller_config($plugin_config, $controller, $id, $uplinks, $config); + my $controller_plugin = PVE::Network::SDN::Plugin->lookup($controller->{type}); + $controller_plugin->generate_controller_transport_config($plugin_config, $controller, $id, $uplinks, $config); } } } diff --git a/PVE/Network/SDN/FrrPlugin.pm b/PVE/Network/SDN/FrrPlugin.pm index 455b185..532247a 100644 --- a/PVE/Network/SDN/FrrPlugin.pm +++ b/PVE/Network/SDN/FrrPlugin.pm @@ -119,6 +119,56 @@ sub generate_controller_config { return $config; } +sub generate_controller_transport_config { +my ($class, $plugin_config, $router, $id, $uplinks, $config) = @_; + +my $vrf = $plugin_config->{'vrf'}; +my $vrfvxlan = $plugin_config->{'vrf-vxlan'}; +my $asn = $router->{asn}; +my $gatewaynodes = $router->{'gateway-nodes'}; + +return if !$vrf || !$vrfvxlan || !$asn; + +#vrf +my @router_config = (); +push @router_config, "vni $vrfvxlan"; +push(@{$config->{frr}->{vrf}->{"$vrf"}}, @router_config); + +@router_config = (); + +my $is_gateway = undef; +my $local_node = PVE::INotify::nodename(); + +foreach my $gatewaynode (PVE::Tools::split_list($gatewaynodes)) { + $is_gateway = 1 if $gatewaynode eq $local_node; +} + +if ($is_gateway) { + + @router_config = (); + #import /32 routes of evpn network from vrf1 to default vrf (for packet return) + #frr 7.1 tag is bugged -> works fine with 7.1 stable branch(20190829-02-g6ba76bbc1) + #https://github.com/FRRouting/frr/issues/4905 + push @router_config, "import vrf $vrf"; + push(@{$config->{frr}->{router}->{"bgp $asn"}->{"address-family"}->{"ipv4 unicast"}}, @router_config); + push(@{$config->{frr}->{router}->{"bgp $asn"}->{"address-family"}->{"ipv6 unicast"}}, @router_config); + + @router_config = (); + #redistribute connected to be able to route to local vms on the gateway + push @router_config, "redistribute connected"; + push(@{$config->{frr}->{router}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"ipv4 unicast"}}, @router_config); + push(@{$config->{frr}->{router}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"ipv6 unicast"}}, @router_config); + + @router_config = (); + #add default originate to announce 0.0.0.0/0 type5 route in evpn + push @router_config, "default-originate ipv4"; + push @router_config, "default-originate ipv6"; + push(@{$config->{frr}->{router}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"l2vpn evpn"}}, @router_config); +} + +return $config; +} + sub on_delete_hook { my ($class, $routerid, $sdn_cfg) = @_; @@ -242,3 +292,4 @@ sub write_controller_config { 1; + diff --git a/PVE/Network/SDN/VxlanPlugin.pm b/PVE/Network/SDN/VxlanPlugin.pm index 986a250..d39a533 100644 --- a/PVE/Network/SDN/VxlanPlugin.pm +++ b/PVE/Network/SDN/VxlanPlugin.pm @@ -188,56 +188,6 @@ sub generate_sdn_config { return $config; } -sub generate_controller_config { -my ($class, $plugin_config, $router, $id, $uplinks, $config) = @_; - -my $vrf = $plugin_config->{'vrf'}; -my $vrfvxlan = $plugin_config->{'vrf-vxlan'}; -my $asn = $router->{asn}; -my $gatewaynodes = $router->{'gateway-nodes'}; - -return if !$vrf || !$vrfvxlan || !$asn; - -#vrf -my @router_config = (); -push @router_config, "vni $vrfvxlan"; -push(@{$config->{frr}->{vrf}->{"$vrf"}}, @router_config); - -@router_config = (); - -my $is_gateway = undef; -my $local_node = PVE::INotify::nodename(); - -foreach my $gatewaynode (PVE::Tools::split_list($gatewaynodes)) { - $is_gateway = 1 if $gatewaynode eq $local_node; -} - -if ($is_gateway) { - - @router_config = (); - #import /32 routes of evpn network from vrf1 to default vrf (for packet return) - #frr 7.1 tag is bugged -> works fine with 7.1 stable branch(20190829-02-g6ba76bbc1) - #https://github.com/FRRouting/frr/issues/4905 - push @router_config, "import vrf $vrf"; - push(@{$config->{frr}->{router}->{"bgp $asn"}->{"address-family"}->{"ipv4 uni
[pve-devel] [PATCH pve-network 6/8] rename plugins with controllers
For true sdn, We have 2 plugins, 1 for dataplane (switch), 1 for controlplane (controller) rename: - Frr to EvpnController - Faucet to FaucetController - OvsFaucet to Faucet Signed-off-by: Alexandre Derumier --- PVE/API2/Network/SDN.pm | 4 +- PVE/Network/SDN.pm| 8 +- .../{FrrPlugin.pm => EvpnControllerPlugin.pm} | 4 +- PVE/Network/SDN/FaucetControllerPlugin.pm | 113 + PVE/Network/SDN/FaucetPlugin.pm | 117 ++ PVE/Network/SDN/Makefile | 2 +- PVE/Network/SDN/OVSFaucetPlugin.pm| 76 test/documentation.txt| 4 +- 8 files changed, 164 insertions(+), 164 deletions(-) rename PVE/Network/SDN/{FrrPlugin.pm => EvpnControllerPlugin.pm} (99%) create mode 100644 PVE/Network/SDN/FaucetControllerPlugin.pm delete mode 100644 PVE/Network/SDN/OVSFaucetPlugin.pm diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm index cbd393e..8294cb8 100644 --- a/PVE/API2/Network/SDN.pm +++ b/PVE/API2/Network/SDN.pm @@ -11,9 +11,9 @@ use PVE::Network::SDN::Plugin; use PVE::Network::SDN::VlanPlugin; use PVE::Network::SDN::VxlanPlugin; use PVE::Network::SDN::VnetPlugin; -use PVE::Network::SDN::FrrPlugin; -use PVE::Network::SDN::OVSFaucetPlugin; +use PVE::Network::SDN::FaucetControllerPlugin; use PVE::Network::SDN::FaucetPlugin; +use PVE::Network::SDN::EvpnControllerPlugin; use PVE::Network::SDN::EvpnPlugin; use Storable qw(dclone); diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm index 8e96084..8e8e637 100644 --- a/PVE/Network/SDN.pm +++ b/PVE/Network/SDN.pm @@ -12,18 +12,18 @@ use PVE::Network::SDN::Plugin; use PVE::Network::SDN::VnetPlugin; use PVE::Network::SDN::VlanPlugin; use PVE::Network::SDN::VxlanPlugin; -use PVE::Network::SDN::FrrPlugin; -use PVE::Network::SDN::OVSFaucetPlugin; use PVE::Network::SDN::FaucetPlugin; +use PVE::Network::SDN::FaucetControllerPlugin; use PVE::Network::SDN::EvpnPlugin; +use PVE::Network::SDN::EvpnControllerPlugin; PVE::Network::SDN::VnetPlugin->register(); PVE::Network::SDN::VlanPlugin->register(); PVE::Network::SDN::VxlanPlugin->register(); -PVE::Network::SDN::FrrPlugin->register(); -PVE::Network::SDN::OVSFaucetPlugin->register(); +PVE::Network::SDN::FaucetControllerPlugin->register(); PVE::Network::SDN::FaucetPlugin->register(); PVE::Network::SDN::EvpnPlugin->register(); +PVE::Network::SDN::EvpnControllerPlugin->register(); PVE::Network::SDN::Plugin->init(); diff --git a/PVE/Network/SDN/FrrPlugin.pm b/PVE/Network/SDN/EvpnControllerPlugin.pm similarity index 99% rename from PVE/Network/SDN/FrrPlugin.pm rename to PVE/Network/SDN/EvpnControllerPlugin.pm index 3410844..b2c9345 100644 --- a/PVE/Network/SDN/FrrPlugin.pm +++ b/PVE/Network/SDN/EvpnControllerPlugin.pm @@ -1,4 +1,4 @@ -package PVE::Network::SDN::FrrPlugin; +package PVE::Network::SDN::EvpnControllerPlugin; use strict; use warnings; @@ -10,7 +10,7 @@ use PVE::JSONSchema qw(get_standard_option); use base('PVE::Network::SDN::Plugin'); sub type { -return 'frr'; +return 'evpncontroller'; } sub plugindata { diff --git a/PVE/Network/SDN/FaucetControllerPlugin.pm b/PVE/Network/SDN/FaucetControllerPlugin.pm new file mode 100644 index 000..ee15bdf --- /dev/null +++ b/PVE/Network/SDN/FaucetControllerPlugin.pm @@ -0,0 +1,113 @@ +package PVE::Network::SDN::FaucetControllerPlugin; + +use strict; +use warnings; +use PVE::Network::SDN::Plugin; +use PVE::Tools; +use PVE::INotify; +use PVE::JSONSchema qw(get_standard_option); +use CPAN::Meta::YAML; +use Encode; + +use base('PVE::Network::SDN::Plugin'); + +sub type { +return 'faucetcontroller'; +} + +sub plugindata { +return { +role => 'controller', +}; +} + +sub properties { +return { +}; +} + +# Plugin implementation +sub generate_controller_config { +my ($class, $plugin_config, $router, $id, $uplinks, $config) = @_; + +} + +sub generate_controller_transport_config { +my ($class, $plugin_config, $router, $id, $uplinks, $config) = @_; + +my $dpid = $plugin_config->{'dp-id'}; +my $dphex = printf("%x",$dpid); + +my $transport_config = { + dp_id => $dphex, + hardware => "Open vSwitch", + }; + +$config->{faucet}->{dps}->{$id} = $transport_config; + +} + + +sub generate_controller_vnet_config { +my ($class, $plugin_config, $controller, $transportid, $vnetid, $config) = @_; + +my $mac = $plugin_config->{mac}; +my $ipv4 = $plugin_config->{ipv4}; +my $ipv6 = $plugin_config->{ipv6}; +my $tag = $plugin_config->{tag}; +my $alias = $plugin_config->{alias}; + +my @ips = (); +push @ips, $ipv4 if $ipv4; +push @ips, $ipv6 if $ipv6; + +my $vlan_config = { vid => $tag }; + +$vlan_config->{description} = $alias if $alias; +$vlan_config->{faucet_mac} = $mac if $mac; +$vlan_config->{faucet_vip
[pve-devel] [PATCH pve-network 1/8] make sdn controller plugin generic
move all code for frr to frrplugin, rename router option to controller. This will allow to manage more controller in the future (ovn, faucet,) Signed-off-by: Alexandre Derumier --- PVE/Network/SDN.pm | 148 +++-- PVE/Network/SDN/FrrPlugin.pm | 114 +++-- PVE/Network/SDN/Plugin.pm | 8 +- PVE/Network/SDN/VlanPlugin.pm | 6 ++ PVE/Network/SDN/VnetPlugin.pm | 6 ++ PVE/Network/SDN/VxlanPlugin.pm | 24 -- test/documentation.txt | 6 +- test/generateconfig.pl | 10 +-- 8 files changed, 179 insertions(+), 143 deletions(-) diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm index 101464b..1e5ba67 100644 --- a/PVE/Network/SDN.pm +++ b/PVE/Network/SDN.pm @@ -162,7 +162,7 @@ sub generate_etc_network_config { return $raw_network_config; } -sub generate_frr_config { +sub generate_controller_config { my $sdn_cfg = PVE::Cluster::cfs_read_file('sdn.cfg'); return if !$sdn_cfg; @@ -184,124 +184,31 @@ sub generate_frr_config { } } -my $frr_cfg = undef; -my $transport_cfg = undef; - -foreach my $id (keys %{$sdn_cfg->{ids}}) { - if ($sdn_cfg->{ids}->{$id}->{type} eq 'frr') { - $frr_cfg->{ids}->{$id} = $sdn_cfg->{ids}->{$id}; - } elsif ($sdn_cfg->{ids}->{$id}->{type} ne 'vnet') { - $transport_cfg->{ids}->{$id} = $sdn_cfg->{ids}->{$id}; - } -} - -return undef if !$frr_cfg; - #generate configuration my $config = {}; -foreach my $id (sort keys %{$frr_cfg->{ids}}) { - my $plugin_config = $frr_cfg->{ids}->{$id}; +foreach my $id (keys %{$sdn_cfg->{ids}}) { + my $plugin_config = $sdn_cfg->{ids}->{$id}; my $plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type}); - $plugin->generate_frr_config($plugin_config, $plugin_config, $id, $uplinks, $config); -} - -foreach my $id (sort keys %{$transport_cfg->{ids}}) { - my $plugin_config = $transport_cfg->{ids}->{$id}; - my $routerid = $plugin_config->{router}; - if ($routerid) { - my $router = $frr_cfg->{ids}->{$routerid}; - if ($router) { - my $plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type}); - $plugin->generate_frr_config($plugin_config, $router, $id, $uplinks, $config); + my $pd = $plugin->plugindata(); + my $role = $pd->{role}; + if ($role eq 'controller') { + $plugin->generate_controller_config($plugin_config, $plugin_config, $id, $uplinks, $config); + } elsif ($role eq 'transport') { + my $controllerid = $plugin_config->{controller}; + if ($controllerid) { + my $controller = $sdn_cfg->{ids}->{$controllerid}; + if ($controller) { + my $controller_plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type}); + $controller_plugin->generate_controller_config($plugin_config, $controller, $id, $uplinks, $config); + } } } } -my $final_config = []; -push @{$final_config}, "log syslog informational"; -push @{$final_config}, "!"; - -generate_frr_recurse($final_config, $config, undef, 0); - -push @{$final_config}, "!"; -push @{$final_config}, "line vty"; -push @{$final_config}, "!"; - -my $raw_frr_config = join("\n", @{$final_config}); -return $raw_frr_config; -} - -sub sort_frr_config { -my $order = {}; -$order->{''} = 0; -$order->{'vrf'} = 1; -$order->{'ipv4 unicast'} = 1; -$order->{'ipv6 unicast'} = 2; -$order->{'l2vpn evpn'} = 3; - -my $a_val = 100; -my $b_val = 100; - -$a_val = $order->{$a} if defined($order->{$a}); -$b_val = $order->{$b} if defined($order->{$b}); - -if($a =~ /bgp (\d+)$/) { - $a_val = 2; -} - -if($b =~ /bgp (\d+)$/) { - $b_val = 2; -} - -return $a_val <=> $b_val; +return $config; } -sub generate_frr_recurse{ - my ($final_config, $content, $parentkey, $level) = @_; - - my $keylist = {}; - $keylist->{vrf} = 1; - $keylist->{'address-family'} = 1; - $keylist->{router} = 1; - - my $exitkeylist = {}; - $exitkeylist->{vrf} = 1; - $exitkeylist->{'address-family'} = 1; - - #fix me, make this generic - my $paddinglevel = undef; - if($level == 1 || $level == 2) { - $paddinglevel = $level - 1; - } elsif ($level == 3 || $level == 4) { - $paddinglevel = $level - 2; - } - - my $padding = ""; - $padding = ' ' x ($paddinglevel) if $paddinglevel; - - if (ref $content eq ref {}) { - foreach my $key (sort sort_frr_config keys %$content) { - if ($parentkey && defined($keylist->{$parentkey})) { - push @{$final_config}, $padding."!"; - push @{$final_config}, $padding."$parentkey $key"; - } else { - push @{$final_config}, $padding."$key" if $key ne '' &&
[pve-devel] [PATCH pve-manager] api2: network : reload sdn controller generic
From: root use config generation && reloading from plugins (require my last pve-network patch serie) Signed-off-by: Alexandre Derumier --- PVE/API2/Network.pm | 25 + 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/PVE/API2/Network.pm b/PVE/API2/Network.pm index fa605ba7..194b300a 100644 --- a/PVE/API2/Network.pm +++ b/PVE/API2/Network.pm @@ -554,22 +554,12 @@ __PACKAGE__->register_method({ my $new_config_file = "/etc/network/interfaces.new"; die "you need ifupdown2 to reload networking\n" if !-e '/usr/share/ifupdown2'; - die "ifupdown2 reload is not compatible if openvswitch currently" if -x '/usr/bin/ovs-vsctl'; + warn "openvswitch config can't be reloaded currently. Please reboot to apply ovs changes" if -x '/usr/bin/ovs-vsctl'; my $worker = sub { rename($new_config_file, $current_config_file) if -e $new_config_file; - my $frr_config; - if ($have_sdn) { - my $network_config = PVE::Network::SDN::generate_etc_network_config(); - PVE::Network::SDN::write_etc_network_config($network_config); - - $frr_config = PVE::Network::SDN::generate_frr_config(); - PVE::Network::SDN::write_frr_config($frr_config) if $frr_config; - } - - my $err = sub { my $line = shift; if ($line =~ /(warning|error): (\S+):/) { @@ -578,15 +568,10 @@ __PACKAGE__->register_method({ }; PVE::Tools::run_command(['ifreload', '-a'], errfunc => $err); - my $err_frr = sub { - my $line = shift; - if ($line =~ /^line (\S+)/) { - print "$line \n"; - } - }; - - if ($frr_config && -e "/usr/bin/vtysh") { - PVE::Tools::run_command(['/usr/bin/vtysh', '-m', '-f', '/etc/frr/frr.conf'], outfunc => {}, errfunc => $err_frr); + if ($have_sdn) { + my $controller_config = PVE::Network::SDN::generate_controller_config(); + PVE::Network::SDN::write_controller_config($controller_config) if ($controller_config); + PVE::Network::SDN::reload_controller(); } }; return $rpcenv->fork_worker('srvreload', 'networking', $authuser, $worker); -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
Re: [pve-devel] [PATCH v2 container] don't duplicate lxc.idmap entries during restore
seems good to me. (note: maybe send in again as separate mail? had to edit the mail because commit message wasn't picked up right and apply with --ignore-whitespace) Tested-by: Oguz Bektas On Wed, Sep 25, 2019 at 02:37:32PM +0200, Fabian Grünbichler wrote: > On September 25, 2019 1:30 pm, Oguz Bektas wrote: > > merging $conf->{lxc} causes lxc.idmap entries to be duplicated in the > > restored configuration. instead, we can overwrite the contents from the > > extracted configuration file. this way we don't duplicate these entries. > > (having duplicate idmap entries causes container to crash during start) > > > > Co-developed-by: Stefan Reiter > > Signed-off-by: Oguz Bektas > > What about the following instead (note, generated with -w for > readability)? seems simpler, and with less potential for future breakage > ;) > > From 8e0679858748be369d5ddc5695376b12504daa50 Mon Sep 17 00:00:00 2001 > From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= > Date: Wed, 25 Sep 2019 14:35:04 +0200 > Subject: [PATCH container] restore lxc.* entries once > MIME-Version: 1.0 > Content-Type: text/plain; charset=UTF-8 > Content-Transfer-Encoding: 8bit > > either via recover_config, OR via restore_configuration. non-root behaviour > stays the same. > > Signed-off-by: Fabian Grünbichler > --- > src/PVE/API2/LXC.pm | 4 ++-- > src/PVE/LXC/Create.pm | 6 +- > 2 files changed, 3 insertions(+), 7 deletions(-) > > diff --git a/src/PVE/API2/LXC.pm b/src/PVE/API2/LXC.pm > index 07280fb..28c9047 100644 > --- a/src/PVE/API2/LXC.pm > +++ b/src/PVE/API2/LXC.pm > @@ -353,11 +353,11 @@ __PACKAGE__->register_method({ > my $orig_conf; > ($orig_conf, $orig_mp_param) = > PVE::LXC::Create::recover_config($archive); > $was_template = delete $orig_conf->{template}; > - # When we're root call 'restore_configuration' with > ristricted=0, > + # When we're root call 'restore_configuration' with > restricted=0, > # causing it to restore the raw lxc entries, among > which there may be > # 'lxc.idmap' entries. We need to make sure that the > extracted contents > # of the container match up with the restored > configuration afterwards: > - $conf->{lxc} = [grep { $_->[0] eq 'lxc.idmap' } > @{$orig_conf->{lxc}}]; > + $conf->{lxc} = $orig_conf->{lxc}; > } > } > if ($storage_only_mode) { > diff --git a/src/PVE/LXC/Create.pm b/src/PVE/LXC/Create.pm > index a46a50c..241ca88 100644 > --- a/src/PVE/LXC/Create.pm > +++ b/src/PVE/LXC/Create.pm > @@ -176,18 +176,14 @@ sub restore_configuration { > # storage supports creating a template there > next if $key =~ /^template$/; > > - if ($key eq 'lxc') { > + if ($key eq 'lxc' && $restricted) { > my $lxc_list = $oldconf->{'lxc'}; > - if ($restricted) { > warn "skipping custom lxc options, restore manually as root:\n"; > warn "\n"; > foreach my $lxc_opt (@$lxc_list) { > warn "$lxc_opt->[0]: $lxc_opt->[1]\n" > } > warn "\n"; > - } else { > - @{$conf->{$key}} = (@$lxc_list, @{$conf->{$key}}); > - } > next; > } > > -- > 2.20.1 > > > --- > > src/PVE/LXC/Create.pm | 4 +++- > > 1 file changed, 3 insertions(+), 1 deletion(-) > > > > diff --git a/src/PVE/LXC/Create.pm b/src/PVE/LXC/Create.pm > > index a46a50c..8b2cfc9 100644 > > --- a/src/PVE/LXC/Create.pm > > +++ b/src/PVE/LXC/Create.pm > > @@ -186,7 +186,9 @@ sub restore_configuration { > > } > > warn "\n"; > > } else { > > - @{$conf->{$key}} = (@$lxc_list, @{$conf->{$key}}); > > + # $conf->{lxc} can only have lxc.idmap > > + # so we can overwrite the current $conf from $oldconf > > + $conf->{$key} = $lxc_list; > > } > > next; > > } > > -- > > 2.20.1 > > > > ___ > > pve-devel mailing list > > pve-devel@pve.proxmox.com > > https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel > > > > > > ___ > pve-devel mailing list > pve-devel@pve.proxmox.com > https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 pve-manager] api2: network : reload sdn controller generic
use config generation && reloading from plugins (require my last pve-network patch serie) Signed-off-by: Alexandre Derumier --- PVE/API2/Network.pm | 25 + 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/PVE/API2/Network.pm b/PVE/API2/Network.pm index fa605ba7..194b300a 100644 --- a/PVE/API2/Network.pm +++ b/PVE/API2/Network.pm @@ -554,22 +554,12 @@ __PACKAGE__->register_method({ my $new_config_file = "/etc/network/interfaces.new"; die "you need ifupdown2 to reload networking\n" if !-e '/usr/share/ifupdown2'; - die "ifupdown2 reload is not compatible if openvswitch currently" if -x '/usr/bin/ovs-vsctl'; + warn "openvswitch config can't be reloaded currently. Please reboot to apply ovs changes" if -x '/usr/bin/ovs-vsctl'; my $worker = sub { rename($new_config_file, $current_config_file) if -e $new_config_file; - my $frr_config; - if ($have_sdn) { - my $network_config = PVE::Network::SDN::generate_etc_network_config(); - PVE::Network::SDN::write_etc_network_config($network_config); - - $frr_config = PVE::Network::SDN::generate_frr_config(); - PVE::Network::SDN::write_frr_config($frr_config) if $frr_config; - } - - my $err = sub { my $line = shift; if ($line =~ /(warning|error): (\S+):/) { @@ -578,15 +568,10 @@ __PACKAGE__->register_method({ }; PVE::Tools::run_command(['ifreload', '-a'], errfunc => $err); - my $err_frr = sub { - my $line = shift; - if ($line =~ /^line (\S+)/) { - print "$line \n"; - } - }; - - if ($frr_config && -e "/usr/bin/vtysh") { - PVE::Tools::run_command(['/usr/bin/vtysh', '-m', '-f', '/etc/frr/frr.conf'], outfunc => {}, errfunc => $err_frr); + if ($have_sdn) { + my $controller_config = PVE::Network::SDN::generate_controller_config(); + PVE::Network::SDN::write_controller_config($controller_config) if ($controller_config); + PVE::Network::SDN::reload_controller(); } }; return $rpcenv->fork_worker('srvreload', 'networking', $authuser, $worker); -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] applied: [PATCH RESEND container] restore lxc.* entries once
either via recover_config, OR via restore_configuration. non-root behaviour stays the same. Tested-by: Oguz Bektas Signed-off-by: Fabian Grünbichler --- Note: added Tested-by src/PVE/API2/LXC.pm | 4 ++-- src/PVE/LXC/Create.pm | 16 ++-- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/PVE/API2/LXC.pm b/src/PVE/API2/LXC.pm index 07280fb..28c9047 100644 --- a/src/PVE/API2/LXC.pm +++ b/src/PVE/API2/LXC.pm @@ -353,11 +353,11 @@ __PACKAGE__->register_method({ my $orig_conf; ($orig_conf, $orig_mp_param) = PVE::LXC::Create::recover_config($archive); $was_template = delete $orig_conf->{template}; - # When we're root call 'restore_configuration' with ristricted=0, + # When we're root call 'restore_configuration' with restricted=0, # causing it to restore the raw lxc entries, among which there may be # 'lxc.idmap' entries. We need to make sure that the extracted contents # of the container match up with the restored configuration afterwards: - $conf->{lxc} = [grep { $_->[0] eq 'lxc.idmap' } @{$orig_conf->{lxc}}]; + $conf->{lxc} = $orig_conf->{lxc}; } } if ($storage_only_mode) { diff --git a/src/PVE/LXC/Create.pm b/src/PVE/LXC/Create.pm index a46a50c..241ca88 100644 --- a/src/PVE/LXC/Create.pm +++ b/src/PVE/LXC/Create.pm @@ -176,18 +176,14 @@ sub restore_configuration { # storage supports creating a template there next if $key =~ /^template$/; - if ($key eq 'lxc') { + if ($key eq 'lxc' && $restricted) { my $lxc_list = $oldconf->{'lxc'}; - if ($restricted) { - warn "skipping custom lxc options, restore manually as root:\n"; - warn "\n"; - foreach my $lxc_opt (@$lxc_list) { - warn "$lxc_opt->[0]: $lxc_opt->[1]\n" - } - warn "\n"; - } else { - @{$conf->{$key}} = (@$lxc_list, @{$conf->{$key}}); + warn "skipping custom lxc options, restore manually as root:\n"; + warn "\n"; + foreach my $lxc_opt (@$lxc_list) { + warn "$lxc_opt->[0]: $lxc_opt->[1]\n" } + warn "\n"; next; } -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH manager] ui: qemubiosedit: add gettext to efi disk hint
Signed-off-by: Aaron Lauterer --- Put the hint in one line because AFAIU our tooling cannot handle multiline gettext calls. www/manager6/qemu/QemuBiosEdit.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/www/manager6/qemu/QemuBiosEdit.js b/www/manager6/qemu/QemuBiosEdit.js index 7283df74..54c0271d 100644 --- a/www/manager6/qemu/QemuBiosEdit.js +++ b/www/manager6/qemu/QemuBiosEdit.js @@ -9,8 +9,7 @@ Ext.define('PVE.qemu.BiosEdit', { var EFIHint = Ext.createWidget({ xtype: 'displayfield', //submitValue is false, so we don't get submitted userCls: 'pve-hint', - value: 'You need to add an EFI disk for storing the ' + - 'EFI settings. See the online help for details.', + value: gettext('You need to add an EFI disk for storing the EFI settings. See the online help for details.'), hidden: true }); -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH qemu-server] qemu 4.0 : add Cascadelake-Server && KnightsMill cpu models
Signed-off-by: Alexandre Derumier --- PVE/QemuServer.pm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 70ed910..8376260 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -146,6 +146,9 @@ my $cpu_vendor_list = { 'Skylake-Client-IBRS' => 'GenuineIntel', 'Skylake-Server' => 'GenuineIntel', 'Skylake-Server-IBRS' => 'GenuineIntel', +'Cascadelake-Server' => 'GenuineIntel', +KnightsMill => 'GenuineIntel', + # AMD CPUs athlon => 'AuthenticAMD', -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH pve-manager] cpumodel: qemu 4.0: add Skylake-Server, Cascadelake-Server, KnightsMill
Signed-off-by: Alexandre Derumier --- www/manager6/form/CPUModelSelector.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/www/manager6/form/CPUModelSelector.js b/www/manager6/form/CPUModelSelector.js index 9eb5b0e9..505d27c8 100644 --- a/www/manager6/form/CPUModelSelector.js +++ b/www/manager6/form/CPUModelSelector.js @@ -26,6 +26,9 @@ Ext.define('PVE.form.CPUModelSelector', { ['Broadwell', 'Broadwell'], ['Broadwell-noTSX','Broadwell-noTSX'], ['Skylake-Client','Skylake-Client'], + ['Skylake-Server','Skylake-Server'], + ['Cascadelake-Server','Cascadelake-Server'], + ['KnightsMill','KnightsMill'], ['Opteron_G1', 'Opteron_G1'], ['Opteron_G2', 'Opteron_G2'], ['Opteron_G3', 'Opteron_G3'], -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
Re: [pve-devel] scsi-hd vs scsi-generic with iSCSI
On 9/30/19 8:00 AM, Daniel Berteaud wrote: > - Le 30 Sep 19, à 7:04, Thomas Lamprecht t.lampre...@proxmox.com a écrit : > >> But the interesting thing would be, why is there an issue with scsi-generic, >> i.e., the underlying issue for the two Bugs. IIUC, Dietmar had in mind to >> try to fix those - and thus help all scsi-generic users, instead of working >> around the issue. >> >> The initial question would be: what does the scsi-hd type differently. >> (maybe hard to tell if they're both complete different implementations) > > As much as I'd like to find this out, it's a above my skills. I can help as I > can reproduce it easily, but I won't be able to track it further. We'll see if we can get some infos about this here... > Waiting for this to be solved, would you accept a patch to either force > scsi-hd, or disable scsi-generic/scsi-block ? (not sure yet if it should be a > VM tuning, or at the DC level) Depends on the outcome of above, but effectively we would like to not have the choice between "working or not", so ideally we can just either fix it in QEMU or set the respective (working) option for all new started VMs (QEMU machine versioned, to not break live migration due to changed VM HW). cheers, Thomas ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH pve-zsync] Allow detecting a syncing instance of a job
Before, the check whether a syncing instance of the same job is already present was inside the locked section. This caused cron to continuously spawn new instances of pve-zsync on syncs (or rather groups of syncs) taking longer than 15 minutes, see [0] in the forum. This patch introduces a new locked section for checking the current status and a new 'waiting' status. The 'waiting' status is needed to mark jobs which are currently waiting for the lock for syncing. So if job A is syncing and job B is waiting for the lock then all new instances of job B will see that one instance is already scheduled to sync. [0]: https://forum.proxmox.com/threads/pve-zsync-bug-spawns-endless-cron-processes.58087/ Signed-off-by: Fabian Ebner --- pve-zsync | 25 - 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/pve-zsync b/pve-zsync index 425ffa2..90c1bb3 100755 --- a/pve-zsync +++ b/pve-zsync @@ -19,6 +19,7 @@ my $PVE_DIR = "/etc/pve/local"; my $QEMU_CONF = "${PVE_DIR}/qemu-server"; my $LXC_CONF = "${PVE_DIR}/lxc"; my $LOCKFILE = "$CONFIG_PATH/${PROGNAME}.lock"; +my $LOCKFILE_STATUS_CHECK = "$CONFIG_PATH/${PROGNAME}_status_check.lock"; my $PROG_PATH = "$PATH/${PROGNAME}"; my $INTERVAL = 15; my $DEBUG; @@ -578,20 +579,34 @@ sub destroy_job { sub sync { my ($param) = @_; +my $lock_status_check_fh = IO::File->new("> $LOCKFILE_STATUS_CHECK"); +die "Can't open Lock File: $LOCKFILE_STATUS_CHECK $!\n" if !$lock_status_check_fh; +lock($lock_status_check_fh); + +my $job; +eval { + $job = get_job($param); +}; + +if ($job && defined($job->{state}) && ($job->{state} eq "syncing" || $job->{state} eq "waiting")) { + unlock($lock_status_check_fh); + die "Job --source $param->{source} --name $param->{name} is already scheduled to sync\n"; +} + +$job->{state} = "waiting"; +update_state($job); +unlock($lock_status_check_fh); + my $lock_fh = IO::File->new("> $LOCKFILE"); die "Can't open Lock File: $LOCKFILE $!\n" if !$lock_fh; lock($lock_fh); +#job might've changed while we waited for the lock, but we can be sure it's not syncing my $date = get_date(); -my $job; eval { $job = get_job($param); }; -if ($job && defined($job->{state}) && $job->{state} eq "syncing") { - die "Job --source $param->{source} --name $param->{name} is syncing at the moment"; -} - my $dest = parse_target($param->{dest}); my $source = parse_target($param->{source}); -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 00/12] Add basics for custom CPU models
Based on the RFC and following on- and off-list discussion about custom CPU models [0]. In essence, this revised patch allows a user to specify custom CPU models in /etc/pve/cpu-models.conf (section-config style [1]), where VMs using that CPU model inherit details from the definition. This removes any fragile "auto-magical" CPU flag detection, while still giving the user a way to create VMs with the best possible subset of CPU features maintaining live-migration compatibility. Includes the infrastructure for broadcasting supported CPU flags for each cluster-node via the key-value store - this is not necessary for the custom-cpu feature in particular, but I think could prove useful for implementing the GUI part (e.g. show the user which flags are supported on which nodes). I intentionally wanted to send this series before starting any GUI or new API work, to get some feedback if this approach works better than the cluster-cpu one. v1 -> v2: Quite a big change to v1. Once I began reusing the $cpu_fmt hash for both custom CPU models and VM-specific settings, I realized the approach mentioned by Fabian - to move some helpers from QemuServer to the new CPUConfig - would actually make a lot of sense. * Re-query supported CPU flags when QEMU/KVM updates (without needing to restart pvestatd) using kvm_user_version * Improve documentation and error handling on CPU flag querying helpers * Rename CustomCPUConfig -> CPUConfig * Extract some CPU helpers from QemuServer to CPUConfig * Use cfs_ functions for IO, don't use 'bless' * Merge $cpu_fmt for custom models and VM-specific CPU settings * Rename 'basemodel' -> 'reported-model', only support default models as reported (avoids custom models depending on each other for now) * Add new CPU flag resolving infrastructure * Add and fix test cases Does not include any fix for versioning/live-migration with custom models for now, felt these changes were big enough. [0]: https://pve.proxmox.com/pipermail/pve-devel/2019-July/038268.html [1]: e.g.: cpu-model: custom-cpu-name host-phys-bits 1 flags +aes;+avx;+avx2 reported-model kvm64 manager: Stefan Reiter (1): Broadcast supported CPU flags PVE/Service/pvestatd.pm | 40 ++-- 1 file changed, 38 insertions(+), 2 deletions(-) qemu-server: Stefan Reiter (11): Add QEMU CPU flag querying helpers Add CPUConfig file and migrate some CPU helpers Adapt CPUConfig to handle custom models Add overrides and convenience functions to CPUConfig Verify VM-specific CPU configs seperately Add helpers to better structure CPU option handling Rework get_cpu_options and allow custom CPU models fix #2318: allow phys-bits and host-phys-bits CPU settings cfg2cmd: fix tests for new CPU flag resolving cfg2cmd: add test case for custom CPU model cfg2cmd: fix descriptions of cfg2cmd test cases PVE/QemuServer.pm | 334 PVE/QemuServer/CPUConfig.pm| 595 + PVE/QemuServer/Makefile| 1 + test/cfg2cmd/custom-cpu-model.conf | 8 + test/cfg2cmd/i440fx-win10-hostpci.conf | 2 +- test/cfg2cmd/i440fx-win10-hostpci.conf.cmd | 2 +- test/cfg2cmd/minimal-defaults.conf.cmd | 2 +- test/cfg2cmd/q35-linux-hostpci.conf| 2 +- test/cfg2cmd/q35-linux-hostpci.conf.cmd| 2 +- test/cfg2cmd/q35-win10-hostpci.conf.cmd| 2 +- test/cfg2cmd/simple1.conf.cmd | 2 +- test/cfg2cmd/spice-usb3.conf.cmd | 2 +- test/run_config2command_tests.pl | 21 + 13 files changed, 739 insertions(+), 236 deletions(-) create mode 100644 PVE/QemuServer/CPUConfig.pm create mode 100644 test/cfg2cmd/custom-cpu-model.conf -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 manager 01/12] Broadcast supported CPU flags
pvestatd will check if the KVM version has changed using kvm_user_version (which automatically clears its cache if QEMU/KVM updates), and if it has, query supported CPU flags and broadcast them as a key-value pair to the cluster. Detects value regressions and handles them gracefully (i.e. if query_supported_cpu_flags fails, we try to retain the previously detected flags). Signed-off-by: Stefan Reiter --- v1 -> v2: * broadcast directly in update_supported_cpuflags * use kvm_user_version to determine when to re-query CPU flags * don't broadcast flags when unchanged or empty PVE/Service/pvestatd.pm | 40 ++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/PVE/Service/pvestatd.pm b/PVE/Service/pvestatd.pm index bad1b73d..5ac97c98 100755 --- a/PVE/Service/pvestatd.pm +++ b/PVE/Service/pvestatd.pm @@ -78,6 +78,40 @@ sub hup { $restart_request = 1; } +my $last_kvm_version = ''; + +sub update_supported_cpuflags { +my $kvm_version = PVE::QemuServer::kvm_user_version(); + +# only update when QEMU/KVM version has changed, as that is the only reason +# why flags could change without restarting pvestatd +return if $last_kvm_version eq $kvm_version; +$last_kvm_version = $kvm_version; + +my $supported_cpuflags; + +eval { + $supported_cpuflags = join(" ", @{PVE::QemuServer::query_supported_cpu_flags()}); +}; +warn $@ if $@; + +# detect regression +if (!$supported_cpuflags || $supported_cpuflags eq '') { + my $prev_cpuflags = PVE::Cluster::get_node_kv('cpuflags', $nodename)->{$nodename}; + if ($prev_cpuflags && $prev_cpuflags ne '') { + warn "CPU flag detection failed, using old values\n"; + } else { + warn "CPU flag detection failed and no previous values found\n"; + } + + # either flags are already in kv store, so no need to re-broadcast, + # or we don't have valid flags, and no point broadcasting empty string + return; +} + +PVE::Cluster::broadcast_node_kv('cpuflags', $supported_cpuflags); +} + my $generate_rrd_string = sub { my ($data) = @_; @@ -97,7 +131,9 @@ sub update_node_status { my $cpuinfo = PVE::ProcFSTools::read_cpuinfo(); -my $maxcpu = $cpuinfo->{cpus}; +my $maxcpu = $cpuinfo->{cpus}; + +update_supported_cpuflags(); my $subinfo = PVE::INotify::read_file('subscription'); my $sublevel = $subinfo->{level} || ''; @@ -110,7 +146,7 @@ sub update_node_status { $netin += $netdev->{$dev}->{receive}; $netout += $netdev->{$dev}->{transmit}; } - + my $meminfo = PVE::ProcFSTools::read_meminfo(); my $dinfo = df('/', 1); # output is bytes -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 qemu-server 02/12] Add QEMU CPU flag querying helpers
* query_understood_cpu_flags returns all flags that QEMU/KVM knows about * query_supported_cpu_flags returns all flags that QEMU/KVM can use on this particular host. To get supported flags, a temporary VM is started with QEMU, so we can issue the "query-cpu-model-expansion" QMP command. This is how libvirt queries supported flags for its "host-passthrough" CPU type. query_supported_cpu_flags is thus rather slow and shouldn't be called unnecessarily. Currently only supports x86_64, because QEMU-aarch64 doesn't provide the necessary querying functions. Signed-off-by: Stefan Reiter --- query_understood_cpu_flags is currently not used, but will be very useful for the later UI part. I think it thematically fits best with this patch though. v1 -> v2: * Change order of functions and add a single, more useful comment on usage * Do s/\.|-/_/g directly in query_understood_cpu_flags, since the other format is useless anyway * Add "die" and FIXME for aarch64, since it doesn't support querying atm (still, use get_host_arch()/get_basic_machine_info() for now, so once QEMU supports it, we theoretically just have to remove the "die") * Do QMP in extra eval, so we don't die before calling vm_stop PVE/QemuServer.pm | 112 ++ 1 file changed, 112 insertions(+) diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 70ed910..20c1061 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -3531,6 +3531,118 @@ sub get_command_for_arch($) { return $cmd; } +# To use query_supported_cpu_flags and query_understood_cpu_flags to get flags +# to use in a QEMU command line (-cpu element), first array_intersect the result +# of query_supported_ with query_understood_. This is necessary because: +# +# a) query_understood_ returns flags the host cannot use and +# b) query_supported_ (rather the QMP call) doesn't actually return CPU +#flags, but CPU settings - with most of them being flags. Those settings +#(and some flags, curiously) cannot be specified as a "-cpu" argument +#however. +# +# query_supported_ needs to start a temporary VM and is therefore rather +# expensive. If you need the value returned from this, you can get it much +# cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags'). +# +sub query_supported_cpu_flags { +my $flags = []; + +my $vmid = -1; +my $pidfile = pidfile_name($vmid); + +my ($arch, $default_machine) = get_basic_machine_info(); + +# FIXME: Once this is merged, the code below should work for ARM without any +# further modifications: +# https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html +die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if + $arch eq "aarch64"; + +PVE::QemuConfig->lock_config($vmid, sub { + # We start a temporary (frozen) VM with vmid -1 to allow us to send a QMP command + my $rc = run_command([ + get_command_for_arch($arch), + '-machine', $default_machine, + '-display', 'none', + '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$vmid.qmp,server,nowait", + '-mon', 'chardev=qmp,mode=control', + '-pidfile', $pidfile, + '-S', '-daemonize' + ], noerr => 1, quiet => 0); + return if $rc; + + eval { + my $cmd_result = vm_mon_cmd_nocheck( + $vmid, + 'query-cpu-model-expansion', + type => 'full', + model => { name => 'host' } + ); + + my $props = $cmd_result->{model}->{props}; + if (%$props) { + foreach my $prop (keys %$props) { + push @$flags, $prop if "$props->{$prop}" eq '1'; + } + } + }; + my $err = $@; + + # force stop with 10 sec timeout and 'nocheck' + # always stop, even if QMP failed + vm_stop(undef, $vmid, 1, 1, 10, 0, 1); + + die $err if $err; +}); + +# QEMU returns some flags multiple times, with '_', '.' or '-' as separator +# (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...). +# We only keep those with underscores, since they match the ones from +# /proc/cpuinfo (they do the same thing, but we get rid of duplicates). +@$flags = grep { + my $replaced = (my $underscore = $_) =~ s/\.|-/_/g; + !($replaced && grep { $_ eq $underscore } @$flags) +} @$flags; + +return $flags; +} + +sub query_understood_cpu_flags { +my $flags = []; +my $flag_section = 0; + +my $arch = get_host_arch(); + +# FIXME: Once the patch mentioned in query_supported_cpu_flags is merged, +# depending on if the ARM version of query-cpu-model-expansion also returns +# non-flags, this function might become irrelevant for ARM entirely. +die "CPU Flag detection only supported on x86_64\n" + if $arch ne "x86_64"; + +run_command( + [get_command_for_arch($arch), '-cpu', 'help'], +
[pve-devel] [PATCH v2 qemu-server 04/12] Adapt CPUConfig to handle custom models
Turn CPUConfig into a SectionConfig with parsing/writing support for custom CPU models. IO is handled using cfs. The "custom" parameter provides differentiation between custom and default types, even if the name is the same ('namespacing'). Signed-off-by: Stefan Reiter --- PVE/QemuServer/CPUConfig.pm | 59 ++--- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm index c994228..3fde987 100644 --- a/PVE/QemuServer/CPUConfig.pm +++ b/PVE/QemuServer/CPUConfig.pm @@ -3,6 +3,8 @@ package PVE::QemuServer::CPUConfig; use strict; use warnings; use PVE::JSONSchema; +use PVE::Cluster qw(cfs_register_file cfs_read_file); +use base qw(PVE::SectionConfig); use base 'Exporter'; our @EXPORT_OK = qw( @@ -11,6 +13,15 @@ get_cpu_options qemu_machine_feature_enabled ); +my $default_filename = "cpu-models.conf"; +cfs_register_file($default_filename, + sub { PVE::QemuServer::CPUConfig->parse_config(@_); }, + sub { PVE::QemuServer::CPUConfig->write_config(@_); }); + +sub load_custom_model_conf { +return cfs_read_file($default_filename); +} + my $cpu_vendor_list = { # Intel CPUs 486 => 'GenuineIntel', @@ -80,11 +91,27 @@ my $cpu_flag = qr/[+-](@{[join('|', @supported_cpu_flags)]})/; our $cpu_fmt = { cputype => { - description => "Emulated CPU type.", + description => "Emulated CPU type. Can be default or custom name.", type => 'string', - enum => [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ], + format_description => 'string', default => 'kvm64', default_key => 1, + optional => 1, +}, +custom => { + description => "True if 'cputype' is a custom model, false if otherwise.", + type => 'boolean', + default => 0, + optional => 1, +}, +'reported-model' => { + description => "CPU model and vendor to report to the guest. Must be a QEMU/KVM supported model." +. " Only valid for custom CPU model definitions, default models will always report themselves to the guest OS.", + type => 'string', + enum => [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ], + default => 'kvm64', + custom_only => 1, + optional => 1, }, hidden => { description => "Do not identify as a KVM virtual machine.", @@ -102,14 +129,34 @@ our $cpu_fmt = { flags => { description => "List of additional CPU flags separated by ';'." . " Use '+FLAG' to enable, '-FLAG' to disable a flag." -. " Currently supported flags: @{[join(', ', @supported_cpu_flags)]}.", +. " Custom CPU models can specify any flag supported by" +. " QEMU/KVM, VM-specific flags must be from the following" +. " set for security reasons: @{[join(', ', @supported_cpu_flags)]}.", format_description => '+FLAG[;-FLAG...]', type => 'string', - pattern => qr/$cpu_flag(;$cpu_flag)*/, + pattern => qr/[+-][a-zA-Z0-9\-_\.]+(;[+-][a-zA-Z0-9\-_\.]+)*/, optional => 1, }, }; +# Section config settings +my $defaultData = { +# shallow copy, since SectionConfig modifies propertyList internally +propertyList => { %$cpu_fmt }, +}; + +sub private { +return $defaultData; +} + +sub options { +return { %$cpu_fmt }; +} + +sub type { +return 'cpu-model'; +} + # Print a QEMU device node for a given VM configuration for hotplugging CPUs sub print_cpu_device { my ($conf, $id) = @_; @@ -248,4 +295,8 @@ sub qemu_machine_feature_enabled { $current_minor >= $version_minor); } + +__PACKAGE__->register(); +__PACKAGE__->init(); + 1; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 qemu-server 09/12] fix #2318: allow phys-bits and host-phys-bits CPU settings
Can be specified for a particular VM or via a custom CPU model (VM takes precedence). Signed-off-by: Stefan Reiter --- PVE/QemuServer/CPUConfig.pm | 24 1 file changed, 24 insertions(+) diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm index e595a69..f0bfeee 100644 --- a/PVE/QemuServer/CPUConfig.pm +++ b/PVE/QemuServer/CPUConfig.pm @@ -137,6 +137,19 @@ my $cpu_fmt = { pattern => qr/[+-][a-zA-Z0-9\-_\.]+(;[+-][a-zA-Z0-9\-_\.]+)*/, optional => 1, }, +'phys-bits' => { + type => 'integer', + minimum => 1, + maximum => 64, + description => "The physical memory address bits that are reported to the guest OS. Should be smaller or equal to the host's.", + optional => 1, +}, +'host-phys-bits' => { + type => 'boolean', + default => 0, + description => "Whether to report the host's physical memory address bits. Overrides 'phys-bits' when set.", + optional => 1, +}, }; # $cpu_fmt describes both the CPU config passed as part of a VM config, as well @@ -445,6 +458,17 @@ sub get_cpu_options { $cpu .= resolve_cpu_flags($pve_flags, $hv_flags, $custom_cputype_flags, $vm_flags, $pve_forced_flags); +my $phys_bits = ''; +foreach my $conf ($custom_cpuconf, $cpuconf) { + next if !defined($conf); + if ($conf->{'host-phys-bits'}) { + $phys_bits = ",host-phys-bits=true"; + } elsif ($conf->{'phys-bits'}) { + $phys_bits = ",phys-bits=$conf->{'phys-bits'}"; + } +} +$cpu .= $phys_bits; + return ('-cpu', $cpu); } -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 qemu-server 12/12] cfg2cmd: fix descriptions of cfg2cmd test cases
Signed-off-by: Stefan Reiter --- Independant from the rest of the series. test/cfg2cmd/i440fx-win10-hostpci.conf | 2 +- test/cfg2cmd/q35-linux-hostpci.conf| 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/cfg2cmd/i440fx-win10-hostpci.conf b/test/cfg2cmd/i440fx-win10-hostpci.conf index 0df1378..2ab2dda 100644 --- a/test/cfg2cmd/i440fx-win10-hostpci.conf +++ b/test/cfg2cmd/i440fx-win10-hostpci.conf @@ -1,4 +1,4 @@ -# TEST: Config with q35, NUMA, hostpci passthrough, EFI & Windows +# TEST: Config with i440fx, NUMA, hostpci passthrough, EFI & Windows bios: ovmf bootdisk: scsi0 cores: 1 diff --git a/test/cfg2cmd/q35-linux-hostpci.conf b/test/cfg2cmd/q35-linux-hostpci.conf index 8fd2193..749f983 100644 --- a/test/cfg2cmd/q35-linux-hostpci.conf +++ b/test/cfg2cmd/q35-linux-hostpci.conf @@ -1,4 +1,4 @@ -# TEST: Config with q35, NUMA, hostpci passthrough, EFI & Windows +# TEST: Config with q35, NUMA, hostpci passthrough, EFI & Linux bios: ovmf bootdisk: scsi0 cores: 1 -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 qemu-server 06/12] Verify VM-specific CPU configs seperately
$cpu_fmt is being reused for custom CPUs as well as VM-specific CPU settings. The "pve-vm-cpu-conf" format is introduced to verify a config specifically for use as VM-specific settings. Signed-off-by: Stefan Reiter --- PVE/QemuServer.pm | 2 +- PVE/QemuServer/CPUConfig.pm | 68 +++-- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index a95006f..abf5578 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -505,7 +505,7 @@ EODESCR optional => 1, description => "Emulated CPU type.", type => 'string', - format => $PVE::QemuServer::CPUConfig::cpu_fmt, + format => 'pve-vm-cpu-conf', }, parent => get_standard_option('pve-snapshot-name', { optional => 1, diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm index 125b636..61bd024 100644 --- a/PVE/QemuServer/CPUConfig.pm +++ b/PVE/QemuServer/CPUConfig.pm @@ -87,9 +87,9 @@ my @supported_cpu_flags = ( 'hv-evmcs', 'aes' ); -my $cpu_flag = qr/[+-](@{[join('|', @supported_cpu_flags)]})/; +my $cpu_flag_re = qr/([+-])(@{[join('|', @supported_cpu_flags)]})/; -our $cpu_fmt = { +my $cpu_fmt = { cputype => { description => "Emulated CPU type. Can be default or custom name.", type => 'string', @@ -139,6 +139,70 @@ our $cpu_fmt = { }, }; +# $cpu_fmt describes both the CPU config passed as part of a VM config, as well +# as the definition of a custom CPU model. There are some slight differences +# though, which we catch in the custom verification function below. +sub verify_cpu_conf_basic { +my ($cpu, $noerr) = @_; + +eval { +$cpu = PVE::JSONSchema::parse_property_string($cpu_fmt, $cpu); +}; +if ($@) { +die $@ if !$noerr; +return undef; +} + +# required, but can't be made "optional => 0" since it's not included as a +# seperate property in config file +if (!$cpu->{cputype}) { + die "CPU is missing cputype\n" if !$noerr; + return undef; +} + +return $cpu; +} + +PVE::JSONSchema::register_format('pve-vm-cpu-conf', \&verify_vm_cpu_conf); +sub verify_vm_cpu_conf { +my ($cpu, $noerr) = @_; + +$cpu = verify_cpu_conf_basic($cpu, $noerr); +return undef if !$cpu; + +my $cputype = $cpu->{cputype}; + +# Model must exist +if ($cpu->{custom}) { + my $config = load_custom_model_conf(); + return $cpu if $config && defined($config->{ids}->{$cputype}); + + die "Custom cputype '$cputype' not found\n" if !$noerr; + return undef; +} else { + return $cpu if defined($cpu_vendor_list->{$cputype}); + + die "Default cputype '$cputype' not found\n" if !$noerr; + return undef; +} + +if ($cpu->{flags} && $cpu->{flags} !~ m/$cpu_flag_re(;$cpu_flag_re)*/) { + die "VM-specific CPU flags must be a subset of: @{[join(', ', @supported_cpu_flags)]}\n" + if !$noerr; + return undef; +} + +for my $prop (keys %$cpu) { + if ($cpu->{$prop}->{custom_only}) { + die "Property '$prop' not allowed in VM-specific CPU config.\n" + if !$noerr; + return undef; + } +} + +return $cpu; +} + # Section config settings my $defaultData = { # shallow copy, since SectionConfig modifies propertyList internally -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 qemu-server 11/12] cfg2cmd: add test case for custom CPU model
Requires a mock CPU-model config, which is given as a raw string to also test parsing capabilities. Signed-off-by: Stefan Reiter --- test/cfg2cmd/custom-cpu-model.conf | 8 test/run_config2command_tests.pl | 21 + 2 files changed, 29 insertions(+) create mode 100644 test/cfg2cmd/custom-cpu-model.conf diff --git a/test/cfg2cmd/custom-cpu-model.conf b/test/cfg2cmd/custom-cpu-model.conf new file mode 100644 index 000..d4db550 --- /dev/null +++ b/test/cfg2cmd/custom-cpu-model.conf @@ -0,0 +1,8 @@ +# TEST: Check if custom CPU models are resolved correctly +cores: 3 +cpu: qemu64,custom=1,flags=+virt-ssbd,host-phys-bits=true +name: customcpu +numa: 0 +ostype: win10 +smbios1: uuid=2ea3f676-dfa5-11e9-ae82-c721e12f3fcf +sockets: 1 diff --git a/test/run_config2command_tests.pl b/test/run_config2command_tests.pl index 6f2fe28..c734133 100755 --- a/test/run_config2command_tests.pl +++ b/test/run_config2command_tests.pl @@ -11,6 +11,7 @@ use Test::MockModule; use PVE::Tools qw(file_get_contents file_set_contents run_command); use PVE::QemuConfig; use PVE::QemuServer; +use PVE::QemuServer::CPUConfig; my $base_env = { storage_config => { @@ -146,6 +147,26 @@ $pve_common_tools->mock( }, ); +my $pve_cpuconfig; +$pve_cpuconfig = Test::MockModule->new('PVE::QemuServer::CPUConfig'); +$pve_cpuconfig->mock( +load_custom_model_conf => sub { + # mock custom CPU model config + return PVE::QemuServer::CPUConfig->parse_config("cpu-models.conf", +
[pve-devel] [PATCH v2 qemu-server 10/12] cfg2cmd: fix tests for new CPU flag resolving
The new flag resolving outputs flags in sorted order for consistency, adapt the test cases to not break. Only the order is changed, not which flags are present. Signed-off-by: Stefan Reiter --- test/cfg2cmd/i440fx-win10-hostpci.conf.cmd | 2 +- test/cfg2cmd/minimal-defaults.conf.cmd | 2 +- test/cfg2cmd/q35-linux-hostpci.conf.cmd| 2 +- test/cfg2cmd/q35-win10-hostpci.conf.cmd| 2 +- test/cfg2cmd/simple1.conf.cmd | 2 +- test/cfg2cmd/spice-usb3.conf.cmd | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd b/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd index ff5d635..2a9174d 100644 --- a/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd +++ b/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd @@ -15,7 +15,7 @@ -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ -vnc unix:/var/run/qemu-server/8006.vnc,password \ -no-hpet \ - -cpu 'kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,hv_spinlocks=0x1fff,hv_vapic,hv_time,hv_reset,hv_vpindex,hv_runtime,hv_relaxed,hv_synic,hv_stimer,hv_ipi,enforce' \ + -cpu 'kvm64,enforce,hv_ipi,hv_relaxed,hv_reset,hv_runtime,hv_spinlocks=0x1fff,hv_stimer,hv_synic,hv_time,hv_vapic,hv_vpindex,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep' \ -m 512 \ -object 'memory-backend-ram,id=ram-node0,size=256M' \ -numa 'node,nodeid=0,cpus=0,memdev=ram-node0' \ diff --git a/test/cfg2cmd/minimal-defaults.conf.cmd b/test/cfg2cmd/minimal-defaults.conf.cmd index 5abebe9..444050b 100644 --- a/test/cfg2cmd/minimal-defaults.conf.cmd +++ b/test/cfg2cmd/minimal-defaults.conf.cmd @@ -12,7 +12,7 @@ -nodefaults \ -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ -vnc unix:/var/run/qemu-server/8006.vnc,password \ - -cpu kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ -m 512 \ -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ diff --git a/test/cfg2cmd/q35-linux-hostpci.conf.cmd b/test/cfg2cmd/q35-linux-hostpci.conf.cmd index 21fb18b..2072295 100644 --- a/test/cfg2cmd/q35-linux-hostpci.conf.cmd +++ b/test/cfg2cmd/q35-linux-hostpci.conf.cmd @@ -14,7 +14,7 @@ -nodefaults \ -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ -vnc unix:/var/run/qemu-server/8006.vnc,password \ - -cpu kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ -m 512 \ -object 'memory-backend-ram,id=ram-node0,size=256M' \ -numa 'node,nodeid=0,cpus=0,memdev=ram-node0' \ diff --git a/test/cfg2cmd/q35-win10-hostpci.conf.cmd b/test/cfg2cmd/q35-win10-hostpci.conf.cmd index f2c08ca..81e43d4 100644 --- a/test/cfg2cmd/q35-win10-hostpci.conf.cmd +++ b/test/cfg2cmd/q35-win10-hostpci.conf.cmd @@ -15,7 +15,7 @@ -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ -vnc unix:/var/run/qemu-server/8006.vnc,password \ -no-hpet \ - -cpu 'kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,hv_spinlocks=0x1fff,hv_vapic,hv_time,hv_reset,hv_vpindex,hv_runtime,hv_relaxed,hv_synic,hv_stimer,hv_ipi,enforce' \ + -cpu 'kvm64,enforce,hv_ipi,hv_relaxed,hv_reset,hv_runtime,hv_spinlocks=0x1fff,hv_stimer,hv_synic,hv_time,hv_vapic,hv_vpindex,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep' \ -m 512 \ -object 'memory-backend-ram,id=ram-node0,size=256M' \ -numa 'node,nodeid=0,cpus=0,memdev=ram-node0' \ diff --git a/test/cfg2cmd/simple1.conf.cmd b/test/cfg2cmd/simple1.conf.cmd index b5c06cf..3485064 100644 --- a/test/cfg2cmd/simple1.conf.cmd +++ b/test/cfg2cmd/simple1.conf.cmd @@ -12,7 +12,7 @@ -nodefaults \ -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ -vnc unix:/var/run/qemu-server/8006.vnc,password \ - -cpu kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ -m 768 \ -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ diff --git a/test/cfg2cmd/spice-usb3.conf.cmd b/test/cfg2cmd/spice-usb3.conf.cmd index 680fa64..66b4e8d 100644 --- a/test/cfg2cmd/spice-usb3.conf.cmd +++ b/test/cfg2cmd/spice-usb3.conf.cmd @@ -12,7 +12,7 @@ -nodefaults \ -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ -vnc unix:/var/run/qemu-server/8006.vnc,password \ - -cpu kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ -m 768 \ -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ -- 2.20.1 ___ pv
[pve-devel] [PATCH v2 qemu-server 07/12] Add helpers to better structure CPU option handling
To avoid hardcoding even more CPU-flag related things for custom CPU models, introduce a dynamic approach to resolving flags. resolve_cpu_flags takes a list of hashes (as documented in the comment) and resolves them to a valid "-cpu" argument without duplicates. This also helps by providing a reason why specific CPU flags have been added, and thus allows for useful warning messages should a flag be overwritten by another. Signed-off-by: Stefan Reiter --- PVE/QemuServer/CPUConfig.pm | 67 + 1 file changed, 67 insertions(+) diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm index 61bd024..6f19c2c 100644 --- a/PVE/QemuServer/CPUConfig.pm +++ b/PVE/QemuServer/CPUConfig.pm @@ -289,6 +289,73 @@ sub print_cpu_device { return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0"; } +# Resolves multiple arrays of hashes representing CPU flags with metadata to a +# single string in QEMU "-cpu" compatible format. Later arrays have higher +# priority. +# +# Hashes take the following format: +# { +# aes => { +# op => "+", # defaults to "" if undefined +# reason => "to support AES acceleration", # for override warnings +# value => "" # needed for kvm=off (value: off) etc... +# }, +# ... +# } +sub resolve_cpu_flags { +my $flag_hashes = \@_; + +my $flags = {}; + +for my $hash (@$flag_hashes) { + for my $flag_name (keys %$hash) { + my $flag = $hash->{$flag_name}; + my $old_flag = $flags->{$flag_name}; + + $flag->{op} //= ""; + + if ($old_flag) { + my $value_changed = defined($flag->{value}) != defined($old_flag->{value}); + if (!$value_changed && defined($flag->{value})) { + $value_changed = $flag->{value} eq $old_flag->{value}; + } + + if ($old_flag->{op} eq $flag->{op} && !$value_changed) { + $flags->{$flag_name}->{reason} .= " & $flag->{reason}"; + next; + } + + my $old = print_cpuflag_hash($flag_name, $flags->{$flag_name}); + my $new = print_cpuflag_hash($flag_name, $flag); + warn "warning: CPU flag/setting $new overwrites $old\n"; + } + + $flags->{$flag_name} = $flag; + } +} + +my $flag_str = ''; +# sort for command line stability +for my $flag_name (sort keys %$flags) { + $flag_str .= ','; + $flag_str .= $flags->{$flag_name}->{op}; + $flag_str .= $flag_name; + $flag_str .= "=$flags->{$flag_name}->{value}" + if $flags->{$flag_name}->{value}; +} + +return $flag_str; +} + +sub print_cpuflag_hash { +my ($flag_name, $flag) = @_; +my $formatted = "'$flag->{op}$flag_name"; +$formatted .= "=$flag->{value}" if defined($flag->{value}); +$formatted .= "'"; +$formatted .= " ($flag->{reason})" if defined($flag->{reason}); +return $formatted; +} + # Calculate QEMU's '-cpu' argument from a given VM configuration sub get_cpu_options { my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 qemu-server 03/12] Add CPUConfig file and migrate some CPU helpers
The package will be used for custom CPU models as a SectionConfig, hence the name. For now we simply move some CPU related helper functions and declarations over from QemuServer to reduce clutter there. Signed-off-by: Stefan Reiter --- PVE/QemuServer.pm | 242 +- PVE/QemuServer/CPUConfig.pm | 251 PVE/QemuServer/Makefile | 1 + 3 files changed, 256 insertions(+), 238 deletions(-) create mode 100644 PVE/QemuServer/CPUConfig.pm diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 20c1061..a95006f 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -33,6 +33,7 @@ use PVE::QemuConfig; use PVE::QMPClient; use PVE::RPCEnvironment; use PVE::GuestHelpers; +use PVE::QemuServer::CPUConfig qw(qemu_machine_feature_enabled print_cpu_device get_cpu_options); use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr print_pcie_root_port); use PVE::QemuServer::Memory; use PVE::QemuServer::USB qw(parse_usb_device); @@ -116,105 +117,6 @@ mkdir $var_run_tmpdir; my $lock_dir = "/var/lock/qemu-server"; mkdir $lock_dir; -my $cpu_vendor_list = { -# Intel CPUs -486 => 'GenuineIntel', -pentium => 'GenuineIntel', -pentium2 => 'GenuineIntel', -pentium3 => 'GenuineIntel', -coreduo => 'GenuineIntel', -core2duo => 'GenuineIntel', -Conroe => 'GenuineIntel', -Penryn => 'GenuineIntel', -Nehalem => 'GenuineIntel', -'Nehalem-IBRS' => 'GenuineIntel', -Westmere => 'GenuineIntel', -'Westmere-IBRS' => 'GenuineIntel', -SandyBridge => 'GenuineIntel', -'SandyBridge-IBRS' => 'GenuineIntel', -IvyBridge => 'GenuineIntel', -'IvyBridge-IBRS' => 'GenuineIntel', -Haswell => 'GenuineIntel', -'Haswell-IBRS' => 'GenuineIntel', -'Haswell-noTSX' => 'GenuineIntel', -'Haswell-noTSX-IBRS' => 'GenuineIntel', -Broadwell => 'GenuineIntel', -'Broadwell-IBRS' => 'GenuineIntel', -'Broadwell-noTSX' => 'GenuineIntel', -'Broadwell-noTSX-IBRS' => 'GenuineIntel', -'Skylake-Client' => 'GenuineIntel', -'Skylake-Client-IBRS' => 'GenuineIntel', -'Skylake-Server' => 'GenuineIntel', -'Skylake-Server-IBRS' => 'GenuineIntel', - -# AMD CPUs -athlon => 'AuthenticAMD', -phenom => 'AuthenticAMD', -Opteron_G1 => 'AuthenticAMD', -Opteron_G2 => 'AuthenticAMD', -Opteron_G3 => 'AuthenticAMD', -Opteron_G4 => 'AuthenticAMD', -Opteron_G5 => 'AuthenticAMD', -EPYC => 'AuthenticAMD', -'EPYC-IBPB' => 'AuthenticAMD', - -# generic types, use vendor from host node -host => 'default', -kvm32 => 'default', -kvm64 => 'default', -qemu32 => 'default', -qemu64 => 'default', -max => 'default', -}; - -my @supported_cpu_flags = ( -'pcid', -'spec-ctrl', -'ibpb', -'ssbd', -'virt-ssbd', -'amd-ssbd', -'amd-no-ssb', -'pdpe1gb', -'md-clear', -'hv-tlbflush', -'hv-evmcs', -'aes' -); -my $cpu_flag = qr/[+-](@{[join('|', @supported_cpu_flags)]})/; - -my $cpu_fmt = { -cputype => { - description => "Emulated CPU type.", - type => 'string', - enum => [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ], - default => 'kvm64', - default_key => 1, -}, -hidden => { - description => "Do not identify as a KVM virtual machine.", - type => 'boolean', - optional => 1, - default => 0 -}, -'hv-vendor-id' => { - type => 'string', - pattern => qr/[a-zA-Z0-9]{1,12}/, - format_description => 'vendor-id', - description => 'The Hyper-V vendor ID. Some drivers or programs inside Windows guests need a specific ID.', - optional => 1, -}, -flags => { - description => "List of additional CPU flags separated by ';'." -. " Use '+FLAG' to enable, '-FLAG' to disable a flag." -. " Currently supported flags: @{[join(', ', @supported_cpu_flags)]}.", - format_description => '+FLAG[;-FLAG...]', - type => 'string', - pattern => qr/$cpu_flag(;$cpu_flag)*/, - optional => 1, -}, -}; - my $watchdog_fmt = { model => { default_key => 1, @@ -603,7 +505,7 @@ EODESCR optional => 1, description => "Emulated CPU type.", type => 'string', - format => $cpu_fmt, + format => $PVE::QemuServer::CPUConfig::cpu_fmt, }, parent => get_standard_option('pve-snapshot-name', { optional => 1, @@ -2133,26 +2035,6 @@ sub print_netdev_full { return $netdev; } - -sub print_cpu_device { -my ($conf, $id) = @_; - -my $kvm = $conf->{kvm} // 1; -my $cpu = $kvm ? "kvm64" : "qemu64"; -if (my $cputype = $conf->{cpu}) { - my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype) - or die "Cannot parse cpu description: $cputype\n"; - $cpu = $cpuconf->{cputype}; -} - -my $cores = $conf->{cores} || 1; - -my $current_cor
[pve-devel] [PATCH v2 qemu-server 08/12] Rework get_cpu_options and allow custom CPU models
If the "custom" property on the cpu config is set, try to load the cputype from the custom CPU model config, and set values accordingly. While at it, extract currently hardcoded values into seperate sub and add reasonings. Signed-off-by: Stefan Reiter --- It was quite interesting to dig through old commit messages/mail archives to find the actual reasons some of our hardcoded flags are included. I do feel like the "reason" field is quite useful though, both for future developers and users. PVE/QemuServer/CPUConfig.pm | 188 ++-- 1 file changed, 139 insertions(+), 49 deletions(-) diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm index 6f19c2c..e595a69 100644 --- a/PVE/QemuServer/CPUConfig.pm +++ b/PVE/QemuServer/CPUConfig.pm @@ -360,96 +360,186 @@ sub print_cpuflag_hash { sub get_cpu_options { my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_; -my $cpuFlags = []; -my $ostype = $conf->{ostype}; - -my $cpu = $kvm ? "kvm64" : "qemu64"; +my $cputype = $kvm ? "kvm64" : "qemu64"; if ($arch eq 'aarch64') { - $cpu = 'cortex-a57'; + $cputype = 'cortex-a57'; } -my $hv_vendor_id; -if (my $cputype = $conf->{cpu}) { - my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype) - or die "Cannot parse cpu description: $cputype\n"; - $cpu = $cpuconf->{cputype}; - $kvm_off = 1 if $cpuconf->{hidden}; - $hv_vendor_id = $cpuconf->{'hv-vendor-id'}; - if (defined(my $flags = $cpuconf->{flags})) { - push @$cpuFlags, split(";", $flags); +my $cpuconf = {}; +my $custom_cpuconf; +my $hv_vendor_id; +if (my $cpu_prop_str = $conf->{cpu}) { + $cpuconf = verify_vm_cpu_conf($cpu_prop_str) + or die "Cannot parse cpu description: $cpu_prop_str\n"; + + $cputype = $cpuconf->{cputype}; + if ($cpuconf->{custom}) { + my $custom_conf = load_custom_model_conf(); + $custom_cpuconf = get_model_by_name($custom_conf, $cputype) + or die "invalid custom model definition for '$cputype'\n"; + + $cputype = $custom_cpuconf->{'reported-model'}; + $kvm_off = $custom_cpuconf->{hidden}; + $hv_vendor_id = $custom_cpuconf->{'hv-vendor-id'}; } -} - -push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64'; -push @$cpuFlags , '-x2apic' - if $conf->{ostype} && $conf->{ostype} eq 'solaris'; - -push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32'; + # VM-specific settings override custom CPU config + $kvm_off = $cpuconf->{hidden} + if defined($cpuconf->{hidden}); + $hv_vendor_id = $cpuconf->{'hv-vendor-id'} + if defined($cpuconf->{'hv-vendor-id'}); +} -push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/; +my $pve_flags = get_pve_cpu_flags($conf, $kvm, $cputype, $arch, + $machine_type, $kvmver); -if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3) && $arch eq 'x86_64') { +my $hv_flags = get_hyperv_enlightenments($winversion, $machine_type, $kvmver, + $conf->{bios}, $gpu_passthrough, $hv_vendor_id) if $kvm; - push @$cpuFlags , '+kvm_pv_unhalt' if $kvm; - push @$cpuFlags , '+kvm_pv_eoi' if $kvm; +my $custom_cputype_flags = {}; +if ($custom_cpuconf && defined($custom_cpuconf->{flags})) { + foreach my $flag (split(";", $custom_cpuconf->{flags})) { + $flag =~ m/^([+-])(.*)$/; + $custom_cputype_flags->{$2} = { + op => $1, + reason => "set by custom CPU model", + } + } } -add_hyperv_enlightenments($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios}, $gpu_passthrough, $hv_vendor_id) if $kvm; - -push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64'; - -push @$cpuFlags, 'kvm=off' if $kvm_off; +my $vm_flags = {}; +if (defined(my $flags = $cpuconf->{flags})) { + foreach my $flag (split(";", $flags)) { + if ($flag =~ $cpu_flag_re) { + $vm_flags->{$2} = { + op => $1, + reason => "manually set for VM", + } + } + } +} -if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) { - push @$cpuFlags, "vendor=${cpu_vendor}" - if $cpu_vendor ne 'default'; +my $pve_forced_flags = {}; +$pve_forced_flags->{'enforce'} = { + reason => "error if requested CPU settings not available", +} if $cputype ne 'host' && $kvm && $arch eq 'x86_64'; +$pve_forced_flags->{'kvm'} = { + value => "off", + reason => "hide KVM virtualization from guest", +} if $kvm_off; + +# $cputype is the "reported-model" for custom types, so we can just look up +# the vendor in the default list +my $cpu_vendor = $cpu_vendor_list->{$c
[pve-devel] [PATCH v2 qemu-server 05/12] Add overrides and convenience functions to CPUConfig
Add two overrides to avoid writing redundant information to the config file. get_model_by_name is used to return a cpu config with default values filled out. Signed-off-by: Stefan Reiter --- PVE/QemuServer/CPUConfig.pm | 48 + 1 file changed, 48 insertions(+) diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm index 3fde987..125b636 100644 --- a/PVE/QemuServer/CPUConfig.pm +++ b/PVE/QemuServer/CPUConfig.pm @@ -157,6 +157,54 @@ sub type { return 'cpu-model'; } +sub parse_section_header { +my ($class, $line) = @_; + +my ($type, $sectionId, $errmsg, $config) = + $class->SUPER::parse_section_header($line); + +return undef if !$type; +return ($type, $sectionId, $errmsg, { + # to avoid duplicate model name in config file, parse id as cputype + cputype => $sectionId, + # models parsed from file are by definition always custom + custom => 1, +}); +} + +sub write_config { +my ($class, $filename, $cfg) = @_; + +# remove redundant properties +for my $prop (keys %{$cfg->{ids}}) { + delete $cfg->{ids}->{$prop}->{custom}; + delete $cfg->{ids}->{$prop}->{cputype}; +} + +$class->SUPER::write_config($filename, $cfg); +} + +# Use this to get a single model in the format described by $cpu_fmt. +# Returns undef for unknown $name. +sub get_model_by_name { +my ($conf, $name) = @_; + +return undef if !defined($conf->{ids}->{$name}); + +my $model = {}; +for my $property (keys %{$defaultData->{propertyList}}) { + next if $property eq 'type'; + + if (my $value = $conf->{ids}->{$name}->{$property}) { + $model->{$property} = $value; + } elsif (my $default = $defaultData->{propertyList}->{$property}->{default}) { + $model->{$property} = $default; + } +} + +return $model; +} + # Print a QEMU device node for a given VM configuration for hotplugging CPUs sub print_cpu_device { my ($conf, $id) = @_; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 guest-common 01/18] refactor pending changes related config code into AbstractConfig
also use a better naming scheme for methods: split_flagged_list -> parse_pending_delete join_flagged_list -> print_pending_delete vmconfig_delete_pending_option -> add_to_pending_delete vmconfig_undelete_pending_option -> remove_from_pending_delete vmconfig_cleanup_pending -> cleanup_pending Signed-off-by: Oguz Bektas --- PVE/AbstractConfig.pm | 68 +++ 1 file changed, 68 insertions(+) diff --git a/PVE/AbstractConfig.pm b/PVE/AbstractConfig.pm index e0d0f10..910ca86 100644 --- a/PVE/AbstractConfig.pm +++ b/PVE/AbstractConfig.pm @@ -68,6 +68,74 @@ sub write_config { PVE::Cluster::cfs_write_file($cfspath, $conf); } +# Pending changes related + +sub parse_pending_delete { +my ($class, $text) = @_; +$text ||= ''; +$text =~ s/[,;]/ /g; +$text =~ s/^\s+//; +return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) }; +} + +sub print_pending_delete { +my ($class, $how, $lst) = @_; +join $how, map { $lst->{$_} . $_ } keys %$lst; +} + +sub add_to_pending_delete { +my ($class, $conf, $key, $force) = @_; + +delete $conf->{pending}->{$key}; +my $pending_delete_hash = $class->parse_pending_delete($conf->{pending}->{delete}); +$pending_delete_hash->{$key} = $force ? '!' : ''; +$conf->{pending}->{delete} = $class->print_pending_delete(',', $pending_delete_hash); +} + +sub remove_from_pending_delete { +my ($class, $conf, $key) = @_; + +my $pending_delete_hash = $class->parse_pending_delete($conf->{pending}->{delete}); +delete $pending_delete_hash->{$key}; + +if (%$pending_delete_hash) { + $conf->{pending}->{delete} = $class->print_pending_delete(',', $pending_delete_hash); +} else { + delete $conf->{pending}->{delete}; +} +} + +sub cleanup_pending { +my ($class, $conf) = @_; + +# remove pending changes when nothing changed +my $changes; +foreach my $opt (keys %{$conf->{pending}}) { + if (defined($conf->{$opt}) && ($conf->{pending}->{$opt} eq $conf->{$opt})) { + $changes = 1; + delete $conf->{pending}->{$opt}; + } +} + +my $current_delete_hash = $class->parse_pending_delete($conf->{pending}->{delete}); +my $pending_delete_hash = {}; +while (my ($opt, $force) = each %$current_delete_hash) { + if (defined($conf->{$opt})) { + $pending_delete_hash->{$opt} = $force; + } else { + $changes = 1; + } +} + +if (%$pending_delete_hash) { + $conf->{pending}->{delete} = $class->print_pending_delete(',', $pending_delete_hash); +} else { + delete $conf->{pending}->{delete}; +} + +return $changes; +} + # Lock config file using flock, run $code with @param, unlock config file. # $timeout is the maximum time to aquire the flock sub lock_config_full { -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 qemu-server 06/18] refactor pending changes related code
most of the pending changes related code has been moved into AbstractConfig, so we have to call them as class methods from QemuConfig instead. Signed-off-by: Oguz Bektas --- PVE/API2/Qemu.pm | 14 - PVE/QemuServer.pm | 79 +-- 2 files changed, 15 insertions(+), 78 deletions(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index aa1cd16..9dc07a6 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -919,7 +919,7 @@ __PACKAGE__->register_method({ my $conf = PVE::QemuConfig->load_config($param->{vmid}); - my $pending_delete_hash = PVE::QemuServer::split_flagged_list($conf->{pending}->{delete}); + my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete}); my $res = []; @@ -1170,7 +1170,7 @@ my $update_vm_api = sub { $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']); PVE::QemuServer::vmconfig_register_unused_drive($storecfg, $vmid, $conf, PVE::QemuServer::parse_drive($opt, $val)) if $is_pending_val; - PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt, $force); + PVE::QemuConfig->add_to_pending_delete($conf, $opt, $force); PVE::QemuConfig->write_config($vmid, $conf); } elsif ($opt =~ m/^serial\d+$/) { if ($val eq 'socket') { @@ -1178,7 +1178,7 @@ my $update_vm_api = sub { } elsif ($authuser ne 'root@pam') { die "only root can delete '$opt' config for real devices\n"; } - PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt, $force); + PVE::QemuConfig->add_to_pending_delete($conf, $opt, $force); PVE::QemuConfig->write_config($vmid, $conf); } elsif ($opt =~ m/^usb\d+$/) { if ($val =~ m/spice/) { @@ -1186,10 +1186,10 @@ my $update_vm_api = sub { } elsif ($authuser ne 'root@pam') { die "only root can delete '$opt' config for real devices\n"; } - PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt, $force); + PVE::QemuConfig->add_to_pending_delete($conf, $opt, $force); PVE::QemuConfig->write_config($vmid, $conf); } else { - PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt, $force); + PVE::QemuConfig->add_to_pending_delete($conf, $opt, $force); PVE::QemuConfig->write_config($vmid, $conf); } } @@ -1230,13 +1230,13 @@ my $update_vm_api = sub { } else { $conf->{pending}->{$opt} = $param->{$opt}; } - PVE::QemuServer::vmconfig_undelete_pending_option($conf, $opt); + PVE::QemuConfig->remove_from_pending_delete($conf, $opt); PVE::QemuConfig->write_config($vmid, $conf); } # remove pending changes when nothing changed $conf = PVE::QemuConfig->load_config($vmid); # update/reload - my $changes = PVE::QemuServer::vmconfig_cleanup_pending($conf); + my $changes = PVE::QemuConfig->cleanup_pending($conf); PVE::QemuConfig->write_config($vmid, $conf) if $changes; return if !scalar(keys %{$conf->{pending}}); diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 70ed910..6c499c9 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -2345,40 +2345,6 @@ sub vm_is_volid_owner { return undef; } -sub split_flagged_list { -my $text = shift || ''; -$text =~ s/[,;]/ /g; -$text =~ s/^\s+//; -return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) }; -} - -sub join_flagged_list { -my ($how, $lst) = @_; -join $how, map { $lst->{$_} . $_ } keys %$lst; -} - -sub vmconfig_delete_pending_option { -my ($conf, $key, $force) = @_; - -delete $conf->{pending}->{$key}; -my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete}); -$pending_delete_hash->{$key} = $force ? '!' : ''; -$conf->{pending}->{delete} = join_flagged_list(',', $pending_delete_hash); -} - -sub vmconfig_undelete_pending_option { -my ($conf, $key) = @_; - -my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete}); -delete $pending_delete_hash->{$key}; - -if (%$pending_delete_hash) { - $conf->{pending}->{delete} = join_flagged_list(',', $pending_delete_hash); -} else { - delete $conf->{pending}->{delete}; -} -} - sub vmconfig_register_unused_drive { my ($storecfg, $vmid, $conf, $drive) = @_; @@ -2393,37 +2359,6 @@ sub vmconfig_register_unused_drive { } } -sub vmconfig_cleanup_pending { -my ($conf) = @_; - -# remove pending changes when nothing ch
[pve-devel] [PATCH v2 qemu-server 05/18] use load_current_config for config GET call
Signed-off-by: Oguz Bektas --- PVE/API2/Qemu.pm | 35 +-- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index 267a08e..aa1cd16 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -865,40 +865,7 @@ __PACKAGE__->register_method({ code => sub { my ($param) = @_; - my $conf = PVE::QemuConfig->load_config($param->{vmid}); - - if (my $snapname = $param->{snapshot}) { - my $snapshot = $conf->{snapshots}->{$snapname}; - die "snapshot '$snapname' does not exist\n" if !defined($snapshot); - - $snapshot->{digest} = $conf->{digest}; # keep file digest for API - - $conf = $snapshot; - } - - delete $conf->{snapshots}; - - if (!$param->{current}) { - foreach my $opt (keys %{$conf->{pending}}) { - next if $opt eq 'delete'; - my $value = $conf->{pending}->{$opt}; - next if ref($value); # just to be sure - $conf->{$opt} = $value; - } - my $pending_delete_hash = PVE::QemuServer::split_flagged_list($conf->{pending}->{delete}); - foreach my $opt (keys %$pending_delete_hash) { - delete $conf->{$opt} if $conf->{$opt}; - } - } - - delete $conf->{pending}; - - # hide cloudinit password - if ($conf->{cipassword}) { - $conf->{cipassword} = '**'; - } - - return $conf; + return PVE::QemuConfig->load_current_config($param->{vmid}, $param->{snapshot}, $param->{current}); }}); __PACKAGE__->register_method({ -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 qemu-server 07/18] use format_pending from GuestHelpers for 'qm pending' command
Signed-off-by: Oguz Bektas --- PVE/CLI/qm.pm | 28 +--- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/PVE/CLI/qm.pm b/PVE/CLI/qm.pm index 17935d0..2f1969a 100755 --- a/PVE/CLI/qm.pm +++ b/PVE/CLI/qm.pm @@ -898,33 +898,7 @@ our $cmddef = { } }], -pending => [ "PVE::API2::Qemu", 'vm_pending', ['vmid'], - { node => $nodename }, sub { - my $data = shift; - foreach my $item (sort { $a->{key} cmp $b->{key}} @$data) { - my $k = $item->{key}; - next if $k eq 'digest'; - my $v = $item->{value}; - my $p = $item->{pending}; - if ($k eq 'description') { - $v = PVE::Tools::encode_text($v) if defined($v); - $p = PVE::Tools::encode_text($p) if defined($p); - } - if (defined($v)) { - if ($item->{delete}) { - print "del $k: $v\n"; - } elsif (defined($p)) { - print "cur $k: $v\n"; - print "new $k: $p\n"; - } else { - print "cur $k: $v\n"; - } - } elsif (defined($p)) { - print "new $k: $p\n"; - } - } - }], - +pending => [ "PVE::API2::Qemu", 'vm_pending', ['vmid'], { node => $nodename }, \&PVE::GuestHelpers::format_pending ], showcmd => [ __PACKAGE__, 'showcmd', ['vmid']], status => [ __PACKAGE__, 'status', ['vmid']], -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 00/18] lxc pending changes
this series makes it possible to add/delete/revert pending changes in the backend for containers. this v2 took longer than expected, mainly because there were small bugs popping up everywhere, everytime i tried to change anything :) big thanks to fabian for the extensive review on v1, and for putting up with me :D v1 -> v2: * better refactoring into guest-common, as suggested by fabian and thomas * fixed up some bugs (probably added some too): * backup/restore * cloning * unlimited swap bug * mountpoint handling (more on that) * other stuff that i can't remember right now :D * small changes with style * in v1, mountpoints were a special-special case, since they were handled earlier in code before going into the hotplug/apply pending routines. after much discussion, they're now created/deleted in these phases instead of update_pct_config. unused disks can still be removed directly. * some other small changes around helper functions, mainly adding them support for handling $conf->{pending} pve-container: Oguz Bektas (11): add lxc/pending API path add 'pct pending' adapt CT config parser for pending changes use load_current_config for config GET call skip pending changes while cloning skip pending changes while taking backup apply pending changes during container start add revert parameter to config PUT adapt config PUT method for the new update_pct_config rework update_pct_config to write into pending section add vmconfig_hotplug_pending and vmconfig_apply_pending src/PVE/API2/LXC.pm| 89 ++ src/PVE/API2/LXC/Config.pm | 82 ++ src/PVE/CLI/pct.pm | 3 + src/PVE/LXC.pm | 21 +- src/PVE/LXC/Config.pm | 566 + src/PVE/VZDump/LXC.pm | 1 + 6 files changed, 457 insertions(+), 305 deletions(-) qemu-server: Oguz Bektas (4): overwrite load_current_config from AbstractConfig use load_current_config for config GET call refactor pending changes related code use format_pending from GuestHelpers for 'qm pending' command PVE/API2/Qemu.pm | 49 + PVE/CLI/qm.pm | 28 + PVE/QemuConfig.pm | 14 + PVE/QemuServer.pm | 79 +-- 4 files changed, 31 insertions(+), 139 deletions(-) pve-guest-common: Oguz Bektas (3): refactor pending changes related config code into AbstractConfig refactor method used by config GET calls into AbstractConfig refactor code from qm/pct 'pending' call into AbstractConfig PVE/AbstractConfig.pm | 103 ++ PVE/GuestHelpers.pm | 26 +++ 2 files changed, 129 insertions(+) -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 qemu-server 04/18] overwrite load_current_config from AbstractConfig
we overwrite the load_current_config method from AbstractConfig, in order to handle cipassword. Signed-off-by: Oguz Bektas --- PVE/QemuConfig.pm | 14 ++ 1 file changed, 14 insertions(+) diff --git a/PVE/QemuConfig.pm b/PVE/QemuConfig.pm index edbf1a7..7f229b3 100644 --- a/PVE/QemuConfig.pm +++ b/PVE/QemuConfig.pm @@ -397,6 +397,20 @@ sub __snapshot_foreach_volume { PVE::QemuServer::foreach_drive($conf, $func); } + +sub load_current_config { +my ($class, $vmid, $snapname, $current) = @_; + +my $conf = $class->SUPER::load_current_config($vmid, $snapname, $current); + +if ($conf->{cipassword}) { + $conf->{cipassword} = '**'; +} + +return $conf; +} + + # END implemented abstract methods from PVE::AbstractConfig 1; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 container 11/18] use load_current_config for config GET call
Signed-off-by: Oguz Bektas --- src/PVE/API2/LXC/Config.pm | 22 -- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/PVE/API2/LXC/Config.pm b/src/PVE/API2/LXC/Config.pm index 769fc3b..7eaef74 100644 --- a/src/PVE/API2/LXC/Config.pm +++ b/src/PVE/API2/LXC/Config.pm @@ -34,6 +34,12 @@ __PACKAGE__->register_method({ properties => { node => get_standard_option('pve-node'), vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }), + current => { + description => "Get current values (instead of pending values).", + optional => 1, + default => 0, + type => 'boolean', + }, snapshot => get_standard_option('pve-snapshot-name', { description => "Fetch config values from given snapshot.", optional => 1, @@ -62,22 +68,10 @@ __PACKAGE__->register_method({ code => sub { my ($param) = @_; - my $conf = PVE::LXC::Config->load_config($param->{vmid}); - - if (my $snapname = $param->{snapshot}) { - my $snapshot = $conf->{snapshots}->{$snapname}; - die "snapshot '$snapname' does not exist\n" if !defined($snapshot); - - # we need the digest of the file - $snapshot->{digest} = $conf->{digest}; - $conf = $snapshot; - } - - delete $conf->{snapshots}; - - return $conf; + return PVE::LXC::Config->load_current_config($param->{vmid}, $param->{snapshot}, $param->{current}) }}); + my $vm_config_perm_list = [ 'VM.Config.Disk', 'VM.Config.CPU', -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 guest-common 02/18] refactor method used by config GET calls into AbstractConfig
since this method will be both used by qemu and lxc config GET calls, it makes sense to move it into AbstractConfig. only difference is that qemu also hides the cipassword when it's set. this can be handled by having qemu overwrite the method and add the cipassword code. Signed-off-by: Oguz Bektas --- PVE/AbstractConfig.pm | 35 +++ 1 file changed, 35 insertions(+) diff --git a/PVE/AbstractConfig.pm b/PVE/AbstractConfig.pm index 910ca86..6d3f169 100644 --- a/PVE/AbstractConfig.pm +++ b/PVE/AbstractConfig.pm @@ -136,6 +136,41 @@ sub cleanup_pending { return $changes; } +sub load_current_config { +my ($class, $vmid, $snapname, $current) = @_; + +my $conf = $class->load_config($vmid); + +if ($snapname) { + my $snapshot = $conf->{snapshots}->{$snapname}; + die "snapshot '$snapname' does not exist\n" if !defined($snapshot); + + # we need the digest of the file + $snapshot->{digest} = $conf->{digest}; + $conf = $snapshot; +} + +# take pending changes in +if (!$current) { + foreach my $opt (keys %{$conf->{pending}}) { + next if $opt eq 'delete'; + my $value = $conf->{pending}->{$opt}; + next if ref($value); # just to be sure + $conf->{$opt} = $value; + } + my $pending_delete_hash = $class->parse_pending_delete($conf->{pending}->{delete}); + foreach my $opt (keys %$pending_delete_hash) { + delete $conf->{$opt} if $conf->{$opt}; + } +} + +delete $conf->{snapshots}; +delete $conf->{pending}; + +return $conf; +} + + # Lock config file using flock, run $code with @param, unlock config file. # $timeout is the maximum time to aquire the flock sub lock_config_full { -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 guest-common 03/18] refactor code from qm/pct 'pending' call into AbstractConfig
Signed-off-by: Oguz Bektas --- PVE/GuestHelpers.pm | 26 ++ 1 file changed, 26 insertions(+) diff --git a/PVE/GuestHelpers.pm b/PVE/GuestHelpers.pm index ebe2781..a16433f 100644 --- a/PVE/GuestHelpers.pm +++ b/PVE/GuestHelpers.pm @@ -60,4 +60,30 @@ sub exec_hookscript { } } +sub format_pending { +my ($data) = @_; +foreach my $item (sort { $a->{key} cmp $b->{key}} @$data) { + my $k = $item->{key}; + next if $k eq 'digest'; + my $v = $item->{value}; + my $p = $item->{pending}; + if ($k eq 'description') { + $v = PVE::Tools::encode_text($v) if defined($v); + $p = PVE::Tools::encode_text($p) if defined($p); + } + if (defined($v)) { + if ($item->{delete}) { + print "del $k: $v\n"; + } elsif (defined($p)) { + print "cur $k: $v\n"; + print "new $k: $p\n"; + } else { + print "cur $k: $v\n"; + } + } elsif (defined($p)) { + print "new $k: $p\n"; + } +} +} + 1; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 container 10/18] adapt CT config parser for pending changes
config parser can now read/write [pve:pending] section. this was named such, instead of [PENDING], after on- and offline discussion regarding namespacing the pending section and snapshots. this also adds an optional non-capturing regex group into the parser for [snap: snapname] entries which can be supported in PVE 7.0 Signed-off-by: Oguz Bektas --- src/PVE/LXC/Config.pm | 37 - 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm index 9790345..47bd4bb 100644 --- a/src/PVE/LXC/Config.pm +++ b/src/PVE/LXC/Config.pm @@ -751,6 +751,7 @@ sub parse_pct_config { my $res = { digest => Digest::SHA::sha1_hex($raw), snapshots => {}, + pending => {}, }; $filename =~ m|/lxc/(\d+).conf$| @@ -766,7 +767,14 @@ sub parse_pct_config { foreach my $line (@lines) { next if $line =~ m/^\s*$/; - if ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) { + if ($line =~ m/^\[pve:pending\]\s*$/i) { + $section = 'pending'; + $conf->{description} = $descr if $descr; + $descr = ''; + $conf = $res->{$section} = {}; + next; + } elsif ($line =~ m/^\[(?:snap:)?([a-z][a-z0-9_\-]+)\]\s*$/i) { + # extended regex for namespacing snapshots in PVE 7.0 $section = $1; $conf->{description} = $descr if $descr; $descr = ''; @@ -794,6 +802,13 @@ sub parse_pct_config { $descr .= PVE::Tools::decode_text($2); } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) { $conf->{snapstate} = $1; + } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) { + my $value = $1; + if ($section eq 'pending') { + $conf->{delete} = $value; + } else { + warn "vm $vmid - property 'delete' is only allowed in [pve:pending]\n"; + } } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(\S.*)\s*$/) { my $key = $1; my $value = $2; @@ -832,14 +847,19 @@ sub write_pct_config { } my $generate_raw_config = sub { - my ($conf) = @_; + my ($conf, $pending) = @_; my $raw = ''; # add description as comment to top of file - my $descr = $conf->{description} || ''; - foreach my $cl (split(/\n/, $descr)) { - $raw .= '#' . PVE::Tools::encode_text($cl) . "\n"; + if (defined(my $descr = $conf->{description})) { + if ($descr) { + foreach my $cl (split(/\n/, $descr)) { + $raw .= '#' . PVE::Tools::encode_text($cl) . "\n"; + } + } else { + $raw .= "#\n" if $pending; + } } foreach my $key (sort keys %$conf) { @@ -864,7 +884,14 @@ sub write_pct_config { my $raw = &$generate_raw_config($conf); +if (scalar(keys %{$conf->{pending}})){ + $raw .= "\n[pve:pending]\n"; + $raw .= &$generate_raw_config($conf->{pending}, 1); +} + foreach my $snapname (sort keys %{$conf->{snapshots}}) { + # TODO: namespace snapshots for PVE 7.0 + #$raw .= "\n[snap:$snapname]\n"; $raw .= "\n[$snapname]\n"; $raw .= &$generate_raw_config($conf->{snapshots}->{$snapname}); } -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 container 08/18] add lxc/pending API path
Signed-off-by: Oguz Bektas --- src/PVE/API2/LXC.pm | 88 + 1 file changed, 88 insertions(+) diff --git a/src/PVE/API2/LXC.pm b/src/PVE/API2/LXC.pm index 07280fb..9c040d1 100644 --- a/src/PVE/API2/LXC.pm +++ b/src/PVE/API2/LXC.pm @@ -515,6 +515,7 @@ __PACKAGE__->register_method({ my $res = [ { subdir => 'config' }, + { subdir => 'pending' }, { subdir => 'status' }, { subdir => 'vncproxy' }, { subdir => 'termproxy' }, @@ -1865,4 +1866,91 @@ __PACKAGE__->register_method({ return $task; }}); +__PACKAGE__->register_method({ +name => 'vm_pending', +path => '{vmid}/pending', +method => 'GET', +proxyto => 'node', +description => 'Get container configuration, including pending changes.', +permissions => { + check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]], +}, +parameters => { + additionalProperties => 0, + properties => { + node => get_standard_option('pve-node'), + vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }), + }, +}, +returns => { + type => "array", + items => { + type => "object", + properties => { + key => { + description => 'Configuration option name.', + type => 'string', + }, + value => { + description => 'Current value.', + type => 'string', + optional => 1, + }, + pending => { + description => 'Pending value.', + type => 'string', + optional => 1, + }, + delete => { + description => "Indicates a pending delete request if present and not 0.", + type => 'integer', + minimum => 0, + maximum => 1, + optional => 1, + }, + }, + }, +}, +code => sub { + my ($param) = @_; + + my $conf = PVE::LXC::Config->load_config($param->{vmid}); + + my $pending_delete_hash = PVE::LXC::Config->parse_pending_delete($conf->{pending}->{delete}); + + my $res = []; + + foreach my $opt (keys %$conf) { + next if ref($conf->{$opt}); + next if $opt eq 'pending'; + my $item = { key => $opt } ; + $item->{value} = $conf->{$opt} if defined($conf->{$opt}); + $item->{pending} = $conf->{pending}->{$opt} if defined($conf->{pending}->{$opt}); + $item->{delete} = ($pending_delete_hash->{$opt} ? 2 : 1) if exists $pending_delete_hash->{$opt}; + + push @$res, $item; + } + + foreach my $opt (keys %{$conf->{pending}}) { + next if $opt eq 'delete'; + next if ref($conf->{pending}->{$opt}); + next if defined($conf->{$opt}); + my $item = { key => $opt }; + $item->{pending} = $conf->{pending}->{$opt}; + + push @$res, $item; + } + + # FIXME: $force delete is not implemented for CTs + while (my ($opt, undef) = each %$pending_delete_hash) { + next if $conf->{pending}->{$opt}; + next if $conf->{$opt}; + my $item = { key => $opt, delete => 1 }; + push @$res, $item; + } + + return $res; + +}}); + 1; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 container 09/18] add 'pct pending'
same as 'qm pending', the code is shared via GuestHelpers Signed-off-by: Oguz Bektas --- src/PVE/CLI/pct.pm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PVE/CLI/pct.pm b/src/PVE/CLI/pct.pm index 35ad72f..476f44d 100755 --- a/src/PVE/CLI/pct.pm +++ b/src/PVE/CLI/pct.pm @@ -7,6 +7,7 @@ use POSIX; use Fcntl; use File::Copy 'copy'; +use PVE::GuestHelpers; use PVE::SafeSyslog; use PVE::Tools qw(extract_param); use PVE::CpuSet; @@ -821,6 +822,8 @@ our $cmddef = { } } }], + +pending => [ "PVE::API2::LXC", "vm_pending", ['vmid'], { node => $nodename }, \&PVE::GuestHelpers::format_pending ], set => [ 'PVE::API2::LXC::Config', 'update_vm', ['vmid'], { node => $nodename }], resize => [ "PVE::API2::LXC", 'resize_vm', ['vmid', 'disk', 'size'], { node => $nodename } ], -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 container 12/18] skip pending changes while cloning
Signed-off-by: Oguz Bektas --- src/PVE/API2/LXC.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PVE/API2/LXC.pm b/src/PVE/API2/LXC.pm index 9c040d1..2cb9f9d 100644 --- a/src/PVE/API2/LXC.pm +++ b/src/PVE/API2/LXC.pm @@ -1441,6 +1441,7 @@ __PACKAGE__->register_method({ # Replace the 'disk' lock with a 'create' lock. $newconf->{lock} = 'create'; + delete $newconf->{pending}; delete $newconf->{template}; if ($param->{hostname}) { $newconf->{hostname} = $param->{hostname}; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 container 15/18] add revert parameter to config PUT
Signed-off-by: Oguz Bektas --- src/PVE/API2/LXC/Config.pm | 5 + 1 file changed, 5 insertions(+) diff --git a/src/PVE/API2/LXC/Config.pm b/src/PVE/API2/LXC/Config.pm index 7eaef74..2c036f5 100644 --- a/src/PVE/API2/LXC/Config.pm +++ b/src/PVE/API2/LXC/Config.pm @@ -102,6 +102,11 @@ __PACKAGE__->register_method({ description => "A list of settings you want to delete.", optional => 1, }, + revert => { + type => 'string', format => 'pve-configid-list', + description => "Revert a pending change.", + optional => 1, + }, digest => { type => 'string', description => 'Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.', -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 container 18/18] add vmconfig_hotplug_pending and vmconfig_apply_pending
vmconfig_hotplug_pending is responsible for checking if a key/value pair in the pending section can be hotplugged, if yes; perform a generic replace, or perform specific actions for hotplugging the special cases. vmconfig_apply_pending is only supposed to be called when ct isn't live. Signed-off-by: Oguz Bektas --- src/PVE/LXC.pm| 14 +-- src/PVE/LXC/Config.pm | 199 -- 2 files changed, 203 insertions(+), 10 deletions(-) diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm index 65c41f5..f91e27d 100644 --- a/src/PVE/LXC.pm +++ b/src/PVE/LXC.pm @@ -1632,7 +1632,7 @@ sub alloc_disk { our $NEW_DISK_RE = qr/^([^:\s]+):(\d+(\.\d+)?)$/; sub create_disks { -my ($storecfg, $vmid, $settings, $conf) = @_; +my ($storecfg, $vmid, $settings, $conf, $pending) = @_; my $vollist = []; @@ -1659,10 +1659,14 @@ sub create_disks { push @$vollist, $volid; $mountpoint->{volume} = $volid; $mountpoint->{size} = $size_kb * 1024; - $conf->{$ms} = PVE::LXC::Config->print_ct_mountpoint($mountpoint, $ms eq 'rootfs'); + if ($pending) { + $conf->{pending}->{$ms} = PVE::LXC::Config->print_ct_mountpoint($mountpoint, $ms eq 'rootfs'); + } else { + $conf->{$ms} = PVE::LXC::Config->print_ct_mountpoint($mountpoint, $ms eq 'rootfs'); + } } else { -# use specified/existing volid/dir/device -$conf->{$ms} = PVE::LXC::Config->print_ct_mountpoint($mountpoint, $ms eq 'rootfs'); + # use specified/existing volid/dir/device + $conf->{$ms} = PVE::LXC::Config->print_ct_mountpoint($mountpoint, $ms eq 'rootfs'); } }); @@ -1676,7 +1680,7 @@ sub create_disks { # free allocated images on error if (my $err = $@) { destroy_disks($storecfg, $vollist); -die $err; + die $err; } return $vollist; } diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm index 14c26bc..10dfc75 100644 --- a/src/PVE/LXC/Config.pm +++ b/src/PVE/LXC/Config.pm @@ -1177,6 +1177,194 @@ sub option_exists { } # END JSON config code +my $LXC_FASTPLUG_OPTIONS= { +'description' => 1, +'onboot' => 1, +'startup' => 1, +'protection' => 1, +'hostname' => 1, +'hookscript' => 1, +'cores' => 1, +'tags' => 1, +}; + +sub vmconfig_hotplug_pending { +my ($class, $vmid, $conf, $storecfg, $selection, $errors) = @_; + +my $pid = PVE::LXC::find_lxc_pid($vmid); +my $rootdir = "/proc/$pid/root"; + +my $add_error = sub { + my ($opt, $msg) = @_; + $errors->{$opt} = "hotplug problem - $msg"; +}; + +my $changes; +foreach my $opt (keys %{$conf->{pending}}) { # add/change + next if $selection && !$selection->{$opt}; + if ($LXC_FASTPLUG_OPTIONS->{$opt}) { + $conf->{$opt} = delete $conf->{pending}->{$opt}; + $changes = 1; + } +} + +if ($changes) { + $class->write_config($vmid, $conf); +} + +# There's no separate swap size to configure, there's memory and "total" +# memory (iow. memory+swap). This means we have to change them together. +my $hotplug_memory_done; +my $hotplug_memory = sub { + my ($wanted_memory, $wanted_swap) = @_; + my $old_memory = ($conf->{memory} || $confdesc->{memory}->{default}); + my $old_swap = ($conf->{swap} || $confdesc->{swap}->{default}); + + $wanted_memory //= $old_memory; + $wanted_swap //= $old_swap; + + my $total = $wanted_memory + $wanted_swap; + my $old_total = $old_memory + $old_swap; + + if ($total > $old_total) { + PVE::LXC::write_cgroup_value("memory", $vmid, +"memory.memsw.limit_in_bytes", +int($total*1024*1024)); + PVE::LXC::write_cgroup_value("memory", $vmid, +"memory.limit_in_bytes", +int($wanted_memory*1024*1024)); + } else { + PVE::LXC::write_cgroup_value("memory", $vmid, +"memory.limit_in_bytes", +int($wanted_memory*1024*1024)); + PVE::LXC::write_cgroup_value("memory", $vmid, +"memory.memsw.limit_in_bytes", +int($total*1024*1024)); + } + $hotplug_memory_done = 1; +}; + +my $pending_delete_hash = $class->parse_pending_delete($conf->{pending}->{delete}); +# FIXME: $force deletion is not implemented for CTs +while (my ($opt, undef) = each %$pending_delete_hash) { + next if $selection && !$selection->{$opt}; + eval { + if ($LXC_FASTPLUG_OPTIONS->{$opt}) { + # pass + } elsif ($opt =~ m/^unused(\d+)$/) { +
[pve-devel] [PATCH v2 container 16/18] adapt config PUT method for the new update_pct_config
we don't need to extract 'delete' here, instead we pass it all as $param and extract 'delete', 'revert' and most other things in update_pct_config Signed-off-by: Oguz Bektas --- src/PVE/API2/LXC/Config.pm | 55 -- 1 file changed, 5 insertions(+), 50 deletions(-) diff --git a/src/PVE/API2/LXC/Config.pm b/src/PVE/API2/LXC/Config.pm index 2c036f5..46d8e2f 100644 --- a/src/PVE/API2/LXC/Config.pm +++ b/src/PVE/API2/LXC/Config.pm @@ -119,58 +119,10 @@ __PACKAGE__->register_method({ code => sub { my ($param) = @_; - my $rpcenv = PVE::RPCEnvironment::get(); - my $authuser = $rpcenv->get_user(); - my $node = extract_param($param, 'node'); my $vmid = extract_param($param, 'vmid'); - my $digest = extract_param($param, 'digest'); - die "no options specified\n" if !scalar(keys %$param); - - my $delete_str = extract_param($param, 'delete'); - my @delete = PVE::Tools::split_list($delete_str); - - PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, {}, [@delete]); - - foreach my $opt (@delete) { - raise_param_exc({ delete => "you can't use '-$opt' and -delete $opt' at the same time" }) - if defined($param->{$opt}); - - if (!PVE::LXC::Config->option_exists($opt)) { - raise_param_exc({ delete => "unknown option '$opt'" }); - } - } - - PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, $param, []); - - my $storage_cfg = cfs_read_file("storage.cfg"); - - my $repl_conf = PVE::ReplicationConfig->new(); - my $is_replicated = $repl_conf->check_for_existing_jobs($vmid, 1); - if ($is_replicated) { - PVE::LXC::Config->foreach_mountpoint_full($param, 0, sub { - my ($opt, $mountpoint) = @_; - my $volid = $mountpoint->{volume}; - return if !$volid || !($mountpoint->{replicate}//1); - if ($mountpoint->{type} eq 'volume') { - my ($storeid, $format); - if ($volid =~ $PVE::LXC::NEW_DISK_RE) { - $storeid = $1; - $format = $mountpoint->{format} || PVE::Storage::storage_default_format($storage_cfg, $storeid); - } else { - ($storeid, undef) = PVE::Storage::parse_volume_id($volid, 1); - $format = (PVE::Storage::parse_volname($storage_cfg, $volid))[6]; - } - return if PVE::Storage::storage_can_replicate($storage_cfg, $storeid, $format); - my $scfg = PVE::Storage::storage_config($storage_cfg, $storeid); - return if $scfg->{shared}; - } - die "cannot add non-replicatable volume to a replicated VM\n"; - }); - } - my $code = sub { my $conf = PVE::LXC::Config->load_config($vmid); @@ -180,10 +132,13 @@ __PACKAGE__->register_method({ my $running = PVE::LXC::check_running($vmid); - PVE::LXC::Config->update_pct_config($vmid, $conf, $running, $param, \@delete); + die "no options specified\n" if !scalar(keys %$param); + + PVE::LXC::Config->update_pct_config($vmid, $conf, $running, $param); + $conf = PVE::LXC::Config->load_config($vmid); - PVE::LXC::Config->write_config($vmid, $conf); PVE::LXC::update_lxc_config($vmid, $conf); + }; PVE::LXC::Config->lock_config($vmid, $code); -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 container 14/18] apply pending changes during container start
Signed-off-by: Oguz Bektas --- src/PVE/LXC.pm | 7 +++ 1 file changed, 7 insertions(+) diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm index 475d9be..65c41f5 100644 --- a/src/PVE/LXC.pm +++ b/src/PVE/LXC.pm @@ -1930,6 +1930,13 @@ sub userns_command { sub vm_start { my ($vmid, $conf, $skiplock) = @_; +# apply pending changes while starting +my $storecfg = PVE::Storage::config(); +if (scalar(keys %{$conf->{pending}})) { + PVE::LXC::Config->vmconfig_apply_pending($vmid, $conf, $storecfg); + $conf = PVE::LXC::Config->load_config($vmid); # update/reload +} + update_lxc_config($vmid, $conf); my $skiplock_flag_fn = "/run/lxc/skiplock-$vmid"; -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 container 13/18] skip pending changes while taking backup
Signed-off-by: Oguz Bektas --- src/PVE/VZDump/LXC.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PVE/VZDump/LXC.pm b/src/PVE/VZDump/LXC.pm index ad5ecc8..2a6449c 100644 --- a/src/PVE/VZDump/LXC.pm +++ b/src/PVE/VZDump/LXC.pm @@ -288,6 +288,7 @@ sub assemble { delete $conf->{lock}; delete $conf->{snapshots}; delete $conf->{parent}; +delete $conf->{pending}; PVE::Tools::file_set_contents("$tmpdir/etc/vzdump/pct.conf", PVE::LXC::Config::write_pct_config("/lxc/$vmid.conf", $conf)); -- 2.20.1 ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 container 17/18] rework update_pct_config to write into pending section
use vmconfig_hotplug_pending or vmconfig_apply_pending to apply the pending changes, depending on whether the CT is on- or offline. Signed-off-by: Oguz Bektas --- src/PVE/LXC/Config.pm | 334 ++ 1 file changed, 106 insertions(+), 228 deletions(-) diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm index 47bd4bb..14c26bc 100644 --- a/src/PVE/LXC/Config.pm +++ b/src/PVE/LXC/Config.pm @@ -4,11 +4,13 @@ use strict; use warnings; use PVE::AbstractConfig; +use PVE::RPCEnvironment; use PVE::Cluster qw(cfs_register_file); use PVE::GuestHelpers; use PVE::INotify; +use PVE::Exception qw(raise_param_exc); use PVE::JSONSchema qw(get_standard_option); -use PVE::Tools; +use PVE::Tools qw(extract_param); use base qw(PVE::AbstractConfig); @@ -900,267 +902,143 @@ sub write_pct_config { } sub update_pct_config { -my ($class, $vmid, $conf, $running, $param, $delete) = @_; +my ($class, $vmid, $conf, $running, $param) = @_; -my @nohotplug; +my $rpcenv = PVE::RPCEnvironment::get(); +my $authuser = $rpcenv->get_user(); -my $new_disks = 0; -my @deleted_volumes; +my $delete_str = extract_param($param, 'delete'); +my @delete = PVE::Tools::split_list($delete_str); +my $revert_str = extract_param($param, 'revert'); +my @revert = PVE::Tools::split_list($revert_str); -my $rootdir; -if ($running) { - my $pid = PVE::LXC::find_lxc_pid($vmid); - $rootdir = "/proc/$pid/root"; +PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, {}, [@delete]); + +foreach my $opt (PVE::Tools::split_list($revert_str)) { + raise_param_exc({ revert => "unknown option '$opt'" }) + if !$class->option_exists($opt); + + raise_param_exc({ delete => "you can't use '-$opt' and " . + "'-revert $opt' at the same time" }) + if defined($param->{$opt}); + + push @revert, $opt; } -my $hotplug_error = sub { - if ($running) { - push @nohotplug, @_; - return 1; - } else { - return 0; - } -}; +foreach my $opt (@revert) { + delete $conf->{pending}->{$opt}; + # FIXME: maybe check before doing this? + $class->remove_from_pending_delete($conf, $opt); # remove from deletion queue +} +$class->write_config($vmid, $conf); -if (defined($delete)) { - foreach my $opt (@$delete) { - if (!exists($conf->{$opt})) { - # silently ignore - next; - } +foreach my $opt (@delete) { + raise_param_exc({ delete => "you can't use '-$opt' and -delete $opt' at the same time" }) + if defined($param->{$opt}); - if ($opt eq 'memory' || $opt eq 'rootfs') { - die "unable to delete required option '$opt'\n"; - } elsif ($opt eq 'hostname') { - delete $conf->{$opt}; - } elsif ($opt eq 'swap') { - delete $conf->{$opt}; - PVE::LXC::write_cgroup_value("memory", $vmid, -"memory.memsw.limit_in_bytes", -1); - } elsif ($opt eq 'description' || $opt eq 'onboot' || $opt eq 'startup' || $opt eq 'hookscript') { - delete $conf->{$opt}; - } elsif ($opt eq 'nameserver' || $opt eq 'searchdomain' || -$opt eq 'tty' || $opt eq 'console' || $opt eq 'cmode') { - next if $hotplug_error->($opt); - delete $conf->{$opt}; - } elsif ($opt eq 'cores') { - delete $conf->{$opt}; # rest is handled by pvestatd - } elsif ($opt eq 'cpulimit') { - PVE::LXC::write_cgroup_value("cpu", $vmid, "cpu.cfs_quota_us", -1); - delete $conf->{$opt}; - } elsif ($opt eq 'cpuunits') { - PVE::LXC::write_cgroup_value("cpu", $vmid, "cpu.shares", $confdesc->{cpuunits}->{default}); - delete $conf->{$opt}; - } elsif ($opt =~ m/^net(\d)$/) { - delete $conf->{$opt}; - next if !$running; - my $netid = $1; - PVE::Network::veth_delete("veth${vmid}i$netid"); - } elsif ($opt eq 'protection') { - delete $conf->{$opt}; - } elsif ($opt =~ m/^unused(\d+)$/) { - next if $hotplug_error->($opt); - PVE::LXC::Config->check_protection($conf, "can't remove CT $vmid drive '$opt'"); - push @deleted_volumes, $conf->{$opt}; - delete $conf->{$opt}; - } elsif ($opt =~ m/^mp(\d+)$/) { - next if $hotplug_error->($opt); - PVE::LXC::Config->check_protection($conf, "can't remove CT $vmid drive '$opt'"); - my $mp = PVE::LXC::Config->parse_ct_mountpoint($conf->{$opt}); - delete $conf->{$opt}; - if ($mp->{type} eq 'volume') { - PVE::LXC::Co
Re: [pve-devel] [PATCH pve-zsync] Allow detecting a syncing instance of a job
On 9/30/19 12:55 PM, Fabian Ebner wrote: > Before, the check whether a syncing instance of the same job is already > present > was inside the locked section. This caused cron to continuously spawn new > instances of pve-zsync on syncs (or rather groups of syncs) taking longer > than 15 minutes, see [0] in the forum. This patch introduces a new locked > section for checking the current status and a new 'waiting' status. > The 'waiting' status is needed to mark jobs which are currently waiting > for the lock for syncing. So if job A is syncing and job B is waiting for > the lock then all new instances of job B will see that one instance is > already scheduled to sync. > > [0]: > https://forum.proxmox.com/threads/pve-zsync-bug-spawns-endless-cron-processes.58087/ > > Signed-off-by: Fabian Ebner > --- > pve-zsync | 25 - > 1 file changed, 20 insertions(+), 5 deletions(-) > Looks OK, a small style nit and proposal for eventual refactoring in-line > diff --git a/pve-zsync b/pve-zsync > index 425ffa2..90c1bb3 100755 > --- a/pve-zsync > +++ b/pve-zsync > @@ -19,6 +19,7 @@ my $PVE_DIR = "/etc/pve/local"; > my $QEMU_CONF = "${PVE_DIR}/qemu-server"; > my $LXC_CONF = "${PVE_DIR}/lxc"; > my $LOCKFILE = "$CONFIG_PATH/${PROGNAME}.lock"; > +my $LOCKFILE_STATUS_CHECK = "$CONFIG_PATH/${PROGNAME}_status_check.lock"; > my $PROG_PATH = "$PATH/${PROGNAME}"; > my $INTERVAL = 15; > my $DEBUG; > @@ -578,20 +579,34 @@ sub destroy_job { > sub sync { > my ($param) = @_; > > +my $lock_status_check_fh = IO::File->new("> $LOCKFILE_STATUS_CHECK"); > +die "Can't open Lock File: $LOCKFILE_STATUS_CHECK $!\n" if > !$lock_status_check_fh; > +lock($lock_status_check_fh); Above pattern is repeated quite a few times in this file, maybe we could replace it by something like: sub locked { my ($lock_fn, $code) = @_; my $lock_fh = File... flock($lock_fh, LOCK_EX) || die ...; my $res = eval { $code->() }; my $err = $@; flock($fh, LOCK_UN) || warn ...; # always unlock die "$err" if $err; close($lock_fh); # or maybe cache this one and keep around? not sure though return $res; } Then we'd have explicit locked segments where we know for sure that unlocking is always done. But as said, that's some refactoring that could be great nothing important. > + > +my $job; > +eval { > + $job = get_job($param); > +}; Above could be also written as one-liner without losing expressiveness: my $job = eval { get_job($param) }; This uses the fact that eval (and most blocks in general) in perl implicitly return the result of the last statement, if no explicit return is (in all branches). I know you just used a pattern already existent in this file, but such a "cleanup" could be OK to even to then, IMO. Not sure, depending if you want to refactor a bit here you could send a v2 else I could apply this and just fixup those "eval assignment" places here, whatever you prefer. > + > +if ($job && defined($job->{state}) && ($job->{state} eq "syncing" || > $job->{state} eq "waiting")) { > + unlock($lock_status_check_fh); > + die "Job --source $param->{source} --name $param->{name} is already > scheduled to sync\n"; > +} > + > +$job->{state} = "waiting"; > +update_state($job); > +unlock($lock_status_check_fh); > + > my $lock_fh = IO::File->new("> $LOCKFILE"); > die "Can't open Lock File: $LOCKFILE $!\n" if !$lock_fh; > lock($lock_fh); > > +#job might've changed while we waited for the lock, but we can be sure > it's not syncing > my $date = get_date(); > -my $job; > eval { > $job = get_job($param); > }; > > -if ($job && defined($job->{state}) && $job->{state} eq "syncing") { > - die "Job --source $param->{source} --name $param->{name} is syncing at > the moment"; > -} > - > my $dest = parse_target($param->{dest}); > my $source = parse_target($param->{source}); > > ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] applied: [PATCH qemu-server] qemu 4.0 : add Cascadelake-Server && KnightsMill cpu models
On 9/30/19 11:43 AM, Alexandre Derumier wrote: > Signed-off-by: Alexandre Derumier > --- > PVE/QemuServer.pm | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm > index 70ed910..8376260 100644 > --- a/PVE/QemuServer.pm > +++ b/PVE/QemuServer.pm > @@ -146,6 +146,9 @@ my $cpu_vendor_list = { > 'Skylake-Client-IBRS' => 'GenuineIntel', > 'Skylake-Server' => 'GenuineIntel', > 'Skylake-Server-IBRS' => 'GenuineIntel', > +'Cascadelake-Server' => 'GenuineIntel', > +KnightsMill => 'GenuineIntel', > + > > # AMD CPUs > athlon => 'AuthenticAMD', > applied, thanks! ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] applied: [PATCH manager] ui: qemubiosedit: add gettext to efi disk hint
On 9/30/19 11:42 AM, Aaron Lauterer wrote: > Signed-off-by: Aaron Lauterer > --- > > Put the hint in one line because AFAIU our tooling cannot handle > multiline gettext calls. > applied, and yes that's the case. > www/manager6/qemu/QemuBiosEdit.js | 3 +-- > 1 file changed, 1 insertion(+), 2 deletions(-) > > diff --git a/www/manager6/qemu/QemuBiosEdit.js > b/www/manager6/qemu/QemuBiosEdit.js > index 7283df74..54c0271d 100644 > --- a/www/manager6/qemu/QemuBiosEdit.js > +++ b/www/manager6/qemu/QemuBiosEdit.js > @@ -9,8 +9,7 @@ Ext.define('PVE.qemu.BiosEdit', { > var EFIHint = Ext.createWidget({ > xtype: 'displayfield', //submitValue is false, so we don't get > submitted > userCls: 'pve-hint', > - value: 'You need to add an EFI disk for storing the ' + > - 'EFI settings. See the online help for details.', > + value: gettext('You need to add an EFI disk for storing the EFI > settings. See the online help for details.'), > hidden: true > }); > > ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] applied: [PATCH pve-manager] cpumodel: qemu 4.0: add Skylake-Server, Cascadelake-Server, KnightsMill
On 9/30/19 11:47 AM, Alexandre Derumier wrote: > Signed-off-by: Alexandre Derumier > --- > www/manager6/form/CPUModelSelector.js | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/www/manager6/form/CPUModelSelector.js > b/www/manager6/form/CPUModelSelector.js > index 9eb5b0e9..505d27c8 100644 > --- a/www/manager6/form/CPUModelSelector.js > +++ b/www/manager6/form/CPUModelSelector.js > @@ -26,6 +26,9 @@ Ext.define('PVE.form.CPUModelSelector', { > ['Broadwell', 'Broadwell'], > ['Broadwell-noTSX','Broadwell-noTSX'], > ['Skylake-Client','Skylake-Client'], > + ['Skylake-Server','Skylake-Server'], > + ['Cascadelake-Server','Cascadelake-Server'], > + ['KnightsMill','KnightsMill'], > ['Opteron_G1', 'Opteron_G1'], > ['Opteron_G2', 'Opteron_G2'], > ['Opteron_G3', 'Opteron_G3'], > applied, thanks ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] applied: [PATCH v2 ha-manager 01/12] Make parameters for LRM resource commands more flexible
On 9/30/19 9:22 AM, Fabian Ebner wrote: > This will allow for new parameters beside 'target' to be used. > This is in preparation to allow for a 'timeout' parameter for a new 'stop' > command. > > Signed-off-by: Fabian Ebner > --- > src/PVE/HA/LRM.pm | 14 +++--- > 1 file changed, 7 insertions(+), 7 deletions(-) > applied, thanks! ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
Re: [pve-devel] [PATCH v2 ha-manager 02/12] Move code updating resource config from API2::HA::Resources to HA::Config
On 9/30/19 9:22 AM, Fabian Ebner wrote: > This makes it easier to update the resource configuration from within the > CRM/LRM stack, > which is needed for the new 'stop' command. > > Signed-off-by: Fabian Ebner > --- > src/PVE/API2/HA/Resources.pm | 34 + > src/PVE/HA/Config.pm | 37 > 2 files changed, 38 insertions(+), 33 deletions(-) > > diff --git a/src/PVE/API2/HA/Resources.pm b/src/PVE/API2/HA/Resources.pm > index 22d7f28..2b62ee8 100644 > --- a/src/PVE/API2/HA/Resources.pm > +++ b/src/PVE/API2/HA/Resources.pm > @@ -237,39 +237,7 @@ __PACKAGE__->register_method ({ > > check_service_state($sid, $param->{state}); > > - PVE::HA::Config::lock_ha_domain( > - sub { > - > - my $cfg = PVE::HA::Config::read_resources_config(); > - > - PVE::SectionConfig::assert_if_modified($cfg, $digest); > - > - my $scfg = $cfg->{ids}->{$sid} || > - die "no such resource '$sid'\n"; > - > - my $plugin = PVE::HA::Resources->lookup($scfg->{type}); > - my $opts = $plugin->check_config($sid, $param, 0, 1); > - > - foreach my $k (%$opts) { > - $scfg->{$k} = $opts->{$k}; > - } > - > - if ($delete) { > - my $options = $plugin->private()->{options}->{$type}; > - foreach my $k (PVE::Tools::split_list($delete)) { > - my $d = $options->{$k} || > - die "no such option '$k'\n"; > - die "unable to delete required option '$k'\n" > - if !$d->{optional}; > - die "unable to delete fixed option '$k'\n" > - if $d->{fixed}; > - delete $scfg->{$k}; > - } > - } > - > - PVE::HA::Config::write_resources_config($cfg) > - > - }, "update resource failed"); > + PVE::HA::Config::update_resources_config($digest, $delete, $sid, > $param); > > return undef; > }}); > diff --git a/src/PVE/HA/Config.pm b/src/PVE/HA/Config.pm > index ead1ee2..e800154 100644 > --- a/src/PVE/HA/Config.pm > +++ b/src/PVE/HA/Config.pm > @@ -125,6 +125,43 @@ sub read_and_check_resources_config { > return $conf; > } > > +sub update_resources_config { > +my ($digest, $delete, $sid, $param) = @_; Hmm, I do not like the order of arguments, IMO it's better to have optional and less likely ones at the end, so that they can just be omitted allowing to write foo("bar"); vs- foo(undef, undef, "bar"); I'd propose my ($sid, $param, $delete, $digest) = @_; The $digest is only for the API, the CRM does not cares as it just enforces a state from a locked context and does no "read-change-update" cycle where other changes from other API users could be overwritten. $delete is also something the API will rather use, in your in-service usage of this method you have both set to "0" anyway. Sorry, this could've been said on v1 already, missed it. > + > +lock_ha_domain( > + sub { > + my $cfg = read_resources_config(); > + ($sid, my $type, my $name) = parse_sid($sid); > + > + PVE::SectionConfig::assert_if_modified($cfg, $digest); > + > + my $scfg = $cfg->{ids}->{$sid} || > + die "no such resource '$sid'\n"; > + > + my $plugin = PVE::HA::Resources->lookup($scfg->{type}); > + my $opts = $plugin->check_config($sid, $param, 0, 1); > + > + foreach my $k (%$opts) { > + $scfg->{$k} = $opts->{$k}; > + } > + > + if ($delete) { > + my $options = $plugin->private()->{options}->{$type}; > + foreach my $k (PVE::Tools::split_list($delete)) { > + my $d = $options->{$k} || > + die "no such option '$k'\n"; > + die "unable to delete required option '$k'\n" > + if !$d->{optional}; > + die "unable to delete fixed option '$k'\n" > + if $d->{fixed}; > + delete $scfg->{$k}; > + } > + } > + > + write_resources_config($cfg); > + }, "update resources config failed"); > +} > + > sub parse_sid { > my ($sid) = @_; > > ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
Re: [pve-devel] [PATCH v2 ha-manager 03/12] Add update_service_config to HA environment interface
On 9/30/19 9:22 AM, Fabian Ebner wrote: > Signed-off-by: Fabian Ebner > --- > src/PVE/HA/Env.pm | 6 ++ > src/PVE/HA/Env/PVE2.pm | 6 ++ > src/PVE/HA/Sim/Env.pm | 6 ++ > 3 files changed, 18 insertions(+) > > diff --git a/src/PVE/HA/Env.pm b/src/PVE/HA/Env.pm > index bb37486..7acd7c5 100644 > --- a/src/PVE/HA/Env.pm > +++ b/src/PVE/HA/Env.pm > @@ -87,6 +87,12 @@ sub read_service_config { > return $self->{plug}->read_service_config(); > } > > +sub update_service_config { > +my ($self, $digest, $delete, $sid, $param) = @_; see reply to patch 02/12 regarding parameter order; here I'd even omit $digest completely, it cannot really matter here anyway, or? > + > +return $self->{plug}->update_service_config($digest, $delete, $sid, > $param); > +} > + > sub parse_sid { > my ($self, $sid) = @_; > > diff --git a/src/PVE/HA/Env/PVE2.pm b/src/PVE/HA/Env/PVE2.pm > index 796acd9..1e92687 100644 > --- a/src/PVE/HA/Env/PVE2.pm > +++ b/src/PVE/HA/Env/PVE2.pm > @@ -120,6 +120,12 @@ sub read_service_config { > return PVE::HA::Config::read_and_check_resources_config(); > } > > +sub update_service_config { > +my ($self, $digest, $delete, $sid, $param) = @_; > + > +return PVE::HA::Config::update_resources_config($digest, $delete, $sid, > $param); > +} > + > sub parse_sid { > my ($self, $sid) = @_; > > diff --git a/src/PVE/HA/Sim/Env.pm b/src/PVE/HA/Sim/Env.pm > index 22e13e6..f400365 100644 > --- a/src/PVE/HA/Sim/Env.pm > +++ b/src/PVE/HA/Sim/Env.pm > @@ -203,6 +203,12 @@ sub read_service_config { > return $self->{hardware}->read_service_config(); > } > > +sub update_service_config { > +my ($self, $digest, $delete, $sid, $param) = @_; > + > +return $self->{hardware}->update_service_config($digest, $delete, $sid, > $param); > +} > + > sub parse_sid { > my ($self, $sid) = @_; > > ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
Re: [pve-devel] [PATCH v2 ha-manager 04/12] Implement update_service_config for simulation
On 9/30/19 9:22 AM, Fabian Ebner wrote: > Signed-off-by: Fabian Ebner > --- > src/PVE/HA/Sim/Hardware.pm | 16 > 1 file changed, 16 insertions(+) > > diff --git a/src/PVE/HA/Sim/Hardware.pm b/src/PVE/HA/Sim/Hardware.pm > index 8bd5cbd..d2c0ec0 100644 > --- a/src/PVE/HA/Sim/Hardware.pm > +++ b/src/PVE/HA/Sim/Hardware.pm > @@ -109,6 +109,22 @@ sub read_service_config { > return $conf; > } > > +sub update_service_config { > +my ($self, $digest, $delete, $sid, $param) = @_; > + > +die "not implemented" if ($digest || $delete); and not required if we agree with my points from 02/12 and 03/12 replies :) (at least the digest one) > + > +my $conf = $self->read_service_config(); > + > +my $sconf = $conf->{$sid} || die "no such resource '$sid'\n"; > + > +foreach my $k (%$param) { > + $sconf->{$k} = $param->{$k}; > +} > + > +$self->write_service_config($conf); > +} > + > sub write_service_config { > my ($self, $conf) = @_; > > ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
Re: [pve-devel] [PATCH v2 ha-manager 06/12] Use timeout for shutdown in LRM
On 9/30/19 9:22 AM, Fabian Ebner wrote: > Signed-off-by: Fabian Ebner > --- > src/PVE/HA/LRM.pm | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/src/PVE/HA/LRM.pm b/src/PVE/HA/LRM.pm > index 3b4a572..e5eee94 100644 > --- a/src/PVE/HA/LRM.pm > +++ b/src/PVE/HA/LRM.pm > @@ -535,7 +535,7 @@ sub manage_resources { > my $req_state = $sd->{state}; > next if !defined($req_state); > next if $req_state eq 'freeze'; > - $self->queue_resource_command($sid, $sd->{uid}, $req_state, {'target' > => $sd->{target}}); > + $self->queue_resource_command($sid, $sd->{uid}, $req_state, {'target' > => $sd->{target}, 'timeout' => $sd->{timeout}}); > } > > return $self->run_workers(); > @@ -776,7 +776,7 @@ sub exec_resource_agent { > > $haenv->log("info", "stopping service $sid"); > > - $plugin->shutdown($haenv, $id); > + $plugin->shutdown($haenv, $id, $params->{timeout}); > > $running = $plugin->check_running($haenv, $id); > > I'd squash this into 05/12, does not has much use as a standalone patch, I think 05 + 06 combined are single logical change. ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
Re: [pve-devel] [PATCH v2 ha-manager 07/12] Add stop command to the API
On 9/30/19 9:22 AM, Fabian Ebner wrote: > Signed-off-by: Fabian Ebner > --- > src/PVE/API2/HA/Resources.pm | 37 > src/PVE/CLI/ha_manager.pm| 2 ++ > 2 files changed, 39 insertions(+) besides the nit^Wfact that the commit subject should read "Add stop command to the API and CLI", not sure if this is required? Couldn't we just have a common helper somewhere and then the qm stop or pct stop just calls that (indirectly?). Just need to rethink concepts for this one, code itself looks OK. > > diff --git a/src/PVE/API2/HA/Resources.pm b/src/PVE/API2/HA/Resources.pm > index 2b62ee8..ecc5f0c 100644 > --- a/src/PVE/API2/HA/Resources.pm > +++ b/src/PVE/API2/HA/Resources.pm > @@ -353,4 +353,41 @@ __PACKAGE__->register_method ({ > return undef; > }}); > > +__PACKAGE__->register_method ({ > +name => 'stop', > +protected => 1, > +path => '{sid}/stop', > +method => 'POST', > +description => "Request the service to be stopped.", > +permissions => { > + check => ['perm', '/', [ 'Sys.Console' ]], > +}, > +parameters => { > + additionalProperties => 0, > + properties => { > + sid => get_standard_option('pve-ha-resource-or-vm-id', > + { completion => > \&PVE::HA::Tools::complete_sid }), > + timeout => { > + description => "Timeout in seconds. If set to 0 a hard stop > will be performed.", > + type => 'integer', > + minimum => 0, > + optional => 1, > + }, > + }, > +}, > +returns => { type => 'null' }, > +code => sub { > + my ($param) = @_; > + > + my ($sid, $type, $name) = > PVE::HA::Config::parse_sid(extract_param($param, 'sid')); > + > + PVE::HA::Config::service_is_ha_managed($sid); > + > + check_service_state($sid); > + > + PVE::HA::Config::queue_crm_commands("stop $sid $param->{timeout}"); > + > + return undef; > +}}); > + > 1; > diff --git a/src/PVE/CLI/ha_manager.pm b/src/PVE/CLI/ha_manager.pm > index 5ce4c30..c9d4e7f 100644 > --- a/src/PVE/CLI/ha_manager.pm > +++ b/src/PVE/CLI/ha_manager.pm > @@ -114,6 +114,8 @@ our $cmddef = { > migrate => [ "PVE::API2::HA::Resources", 'migrate', ['sid', 'node'] ], > relocate => [ "PVE::API2::HA::Resources", 'relocate', ['sid', 'node'] ], > > +stop => [ "PVE::API2::HA::Resources", 'stop', ['sid', 'timeout'] ], > + > }; > > 1; > ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] applied: [PATCH v2 ha-manager 08/12] Rename target to param in simulation
On 9/30/19 9:22 AM, Fabian Ebner wrote: > In preparation to introduce a stop command with a timeout parameter. > > Signed-off-by: Fabian Ebner > --- > src/PVE/HA/Sim/Hardware.pm | 18 +- > 1 file changed, 9 insertions(+), 9 deletions(-) > applied ___ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel