Re: [pve-devel] [PATCH manager] pve5to6: Add warning for some Gluster versions

2019-09-02 Thread Fabian Grünbichler
On August 28, 2019 1:25 pm, Dominic Jäger wrote:
> After Fabian had sent his patch [0] we actually thought that this patch 
> for pve5to6 would be obsolete. Upgrades as well as fresh installs worked 
> flawlessly in my tests. Consequently, I removed the hint from the 
> upgrade documentation [1] and marked the bug [2] as fixed. Before 
> writing you this, I tested everything again and, unfortunately, 
> something (or maybe multiple things) seems to be broken now.

upstream split the packages up now, but did not bother to fix the 
package releationships with versioned provides/replaces/..

the end result is that you need to either uninstall and reinstall 
gluster completely (not possible since we have a dependency via 
pve-qemu) or do the upgrade with

-o Dpkg::Options::="--force-overwrite"

added to the apt upgrade command to ignore the breakage, at least until 
gluster upstream has actually fixed packages available..

https://lists.gluster.org/pipermail/gluster-users/2019-August/036941.html

___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] applied: [RFC container] mountpoints: create parent dirs with correct owner

2019-09-02 Thread Fabian Grünbichler
On August 26, 2019 1:30 pm, Thomas Lamprecht wrote:
> On 24.07.19 13:37, Fabian Grünbichler wrote:
>> otherwise unprivileged containers might end up with directories that
>> they cannot modify since they are owned by the user root in the host
>> namespace, instead of root inside the container.
>> 
>> note: the problematic behaviour is only exhibited when an intermediate
>> directory needs to be created, e.g. a mountpoint /test/mp gets mounted,
>> and /test does not yet exist.
>> 
>> Signed-off-by: Fabian Grünbichler 
>> ---
>> Notes:
>> requires fchownat support in PVE::Tools - see other patch and bump
>> build-depends + depends accordingly after applying!
>> 
>> I am not sure whether this is 100% correct w.r.t. error edge cases, 
>> since we
>> potentially die after mkdirat without calling fchownat. it is for sure 
>> better
>> than the status quo though ;)
>> 
>> thank you Dietmar for noticing the buggy behaviour!
>> 
>>  src/PVE/LXC.pm| 27 ---
>>  src/PVE/VZDump/LXC.pm |  7 +--
>>  src/lxc-pve-prestart-hook |  4 +++-
>>  3 files changed, 24 insertions(+), 14 deletions(-)
>> 
> 
> 
> applied, thanks!
> 
> For existing CTs, where problematic directories outside the CT GID/UID range 
> got
> already created, we could add a "repair-ids" command, which would reset 
> UIDs/GIDs
> from (specified) paths to a CT (root) ID again, if they where outside the CTs
> range, e.g.:
> 
> # pct repair-file-permissions  [] [--repair-with-id ]
> 
> Which could roughly follow those rules:
> * only "repair" files with IDs outside of the CTs file range, e.g., "0" from 
> PVE
>   host POV
> * only check at given path, if set
> * maybe add a "no-recursive" flag to really only do a single file?
> 
> With that at least a possibility would be there to allow people fixing the
> directory tree permissions so that CT-root can change/delete/... them again.
> Just as an idea.
> 

given that there were no complaints so far and we found this internally, 
I think we don't need to provide such a command. a simple pct mount + 
chown with mapped numerical uid/gid should work if anyone ever asks for 
it..

___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH qemu-server] fix #1934: add qemu fw_cfg variables via 'tags'

2019-09-02 Thread Fabian Grünbichler
On August 23, 2019 2:03 pm, Dominik Csapak wrote:
> this add the 'tags' property to vms, which has the format:

why 'tags'? seems rather generic for what it does ;)

> 
> key=value(;key=value)*
> 
> each value will be set as
> 
> -fw_cfg 'name=opt/com.proxmox/$key,string=$value'
> (qemu recommends using a unique rfqdn)
> 
> this way, users can tag the vm with that information available inside
> e.g. under linux the value can be read under
> 
> /sys/firmware/qemu_fw_cfg/by_name/opt/com.proxmox./$key/raw
> 
> see the file docs/specs/fw_cfg.txt in the qemu repository for more
> details

if we introduce this, wouldn't it also make sense to allow to pass in 
snippet files via this interface (via file=$path instead of string=$value)?

> 
> maybe we can also use this in the future to show/set in the gui
> e.g. some grouping/ordering etc.
> 
> Signed-off-by: Dominik Csapak 
> ---
>  PVE/QemuServer.pm | 37 +
>  1 file changed, 37 insertions(+)
> 
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 9f5bf56..d55a1ae 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -232,6 +232,29 @@ my $watchdog_fmt = {
>  };
>  PVE::JSONSchema::register_format('pve-qm-watchdog', $watchdog_fmt);
>  
> +PVE::JSONSchema::register_format('pve-qm-tags', \&verify_tag_format);
> +sub verify_tag_format {
> +my ($tagstring, $noerr) = @_;
> +
> +if (!$tagstring) {
> + return '';
> +}
> +
> +# forbid all characters not in range 0x20-0x7E
> +for my $tag (split(';', $tagstring)) {
> + my ($key, $value) = ($tag =~ m/^(.*)=(.*)$/);
> + if ($key =~ m/[\x00-\x1F\x7F-\xFF]/) {
> + die "invalid character in tag key\n" if !$noerr;
> + return undef;
> + }
> + if ($value =~ m/[\x00-\x1F\x7F-\xFF]/) {
> + die "invalid character in tag value\n" if !$noerr;
> + return undef;
> + }
> +}
> +
> +return $tagstring;
> +}
>  my $agent_fmt = {
>  enabled => {
>   description => "Enable/disable Qemu GuestAgent.",
> @@ -672,6 +695,13 @@ EODESCR
>   description => "Configure a audio device, useful in combination with 
> QXL/Spice.",
>   optional => 1
>  },
> +tags => {
> + description => "Specify key/value pairs to be added to qemu fw_cfg.",
> + type => 'string',
> + maxLength => 4096,
> + format => 'pve-qm-tags',
> + optional => 1,
> +},
>  };
>  
>  my $cicustom_fmt = {
> @@ -4152,6 +4182,13 @@ sub config_to_command {
>   push @$cmd, '-loadstate', $statepath;
>  }
>  
> +if ($conf->{tags}) {
> + for my $tag (split(';', $conf->{tags})) {
> + my ($key, $value) = ($tag =~ m/^(.*)=(.*)$/);
> + push @$cmd, '-fw_cfg', "name=opt/com.proxmox/$key,string=$value";
> + }
> +}
> +
>  # add custom args
>  if ($conf->{args}) {
>   my $aa = PVE::Tools::split_args($conf->{args});
> -- 
> 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


Re: [pve-devel] Gitlab-ci

2019-09-02 Thread Fabian Grünbichler
On August 27, 2019 11:24 am, Alexandre DERUMIER wrote:
> Hi,
> 
> I think 1 benefit of gitlab,github,... is the tracking of merge request.

IMHO this is a big downside of Github and Gitlab - cleanly checking out 
an older iteration of a PR/MR is very cumbersome (and wasn't even really 
possible for the longest time). The review comments reference (and even 
link to!) code that is no longer available directly, and it gets 
confusing quickly. The only thing that's really nice is the direct 
integration into various CI tools, also for in-progress change requests.

with mail, v1 and v2 are simply two mail threads, including any review 
comments. this is much simpler to keep around, checking the archive, 
etc.

> (To not lost some patches series send months ago).
> 
> For code review it great too. (make comments directly in the merge)

see above. I hate the review interface with a passion :-P see [1] for 
example - some inline comments are included in the discussion, but the 
full review with all comments is 404[2], even though it is linked from 
[1].

I am also following sourcehut's progress - it might be able to bridge 
the gap between both worlds (plain email + nice looking web interface).

> I'm curious, do you use some kind of email scripts, special email client, to 
> manage current workflow ?
> (Sometime I'm lost myself with my patches ;)

most of the actively reviewing people use either (neo)mutt or some 
variant of notmuch, but there are some not-yet converted thunderbird 
users as well ;)

1: https://github.com/corosync/corosync/pull/450
2: 
https://github.com/corosync/corosync/pull/450/files/68e7b4cbe3a4687bb6168500d3275d5969b9b9c0

___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH qemu-server] fix #1934: add qemu fw_cfg variables via 'tags'

2019-09-02 Thread Fabian Grünbichler
On September 2, 2019 2:27 pm, Thomas Lamprecht wrote:
> On 9/2/19 2:14 PM, Fabian Grünbichler wrote:
>> On August 23, 2019 2:03 pm, Dominik Csapak wrote:
>>> this add the 'tags' property to vms, which has the format:
>> 
>> why 'tags'? seems rather generic for what it does ;)
> 
> Second, tags is a NAK from me. Maybe just "fw_cfg" (or a variation), the 
> Webinterface
> can show a full name and link to docs anyway (if it'd be added there, 
> someday), and for
> the CLI we have the CLI help, man pages and the fact that it's named the same 
> as the QEMU
> option, which helps a lot to associated both together (even if the sematic 
> how values are
> passed differs, which is IMO totally fine).
> 
>>>
>>> key=value(;key=value)*
>>>
>>> each value will be set as
>>>
>>> -fw_cfg 'name=opt/com.proxmox/$key,string=$value'
>>> (qemu recommends using a unique rfqdn)
>>>
>>> this way, users can tag the vm with that information available inside
>>> e.g. under linux the value can be read under
>>>
>>> /sys/firmware/qemu_fw_cfg/by_name/opt/com.proxmox./$key/raw
>>>
>>> see the file docs/specs/fw_cfg.txt in the qemu repository for more
>>> details
>> 
>> if we introduce this, wouldn't it also make sense to allow to pass in 
>> snippet files via this interface (via file=$path instead of string=$value)?
> 
> How do you want to differentiate between? Would need a special syntax to
> detect that "file" is not meant to be a key for fw_cfg but a hint for PVE..

yes, obviously that would require a different syntax (or maybe even an 
indexed property string? I don't know how many such values users would 
want to set for a single VM..)

> 
>> 
>>>
>>> maybe we can also use this in the future to show/set in the gui
>>> e.g. some grouping/ordering etc.
>>>
>>> Signed-off-by: Dominik Csapak 
>>> ---
>>>  PVE/QemuServer.pm | 37 +
>>>  1 file changed, 37 insertions(+)
>>>
>>> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
>>> index 9f5bf56..d55a1ae 100644
>>> --- a/PVE/QemuServer.pm
>>> +++ b/PVE/QemuServer.pm
>>> @@ -232,6 +232,29 @@ my $watchdog_fmt = {
>>>  };
>>>  PVE::JSONSchema::register_format('pve-qm-watchdog', $watchdog_fmt);
>>>  
>>> +PVE::JSONSchema::register_format('pve-qm-tags', \&verify_tag_format);
>>> +sub verify_tag_format {
>>> +my ($tagstring, $noerr) = @_;
>>> +
>>> +if (!$tagstring) {
>>> +   return '';
>>> +}
>>> +
>>> +# forbid all characters not in range 0x20-0x7E
>>> +for my $tag (split(';', $tagstring)) {
>>> +   my ($key, $value) = ($tag =~ m/^(.*)=(.*)$/);
>>> +   if ($key =~ m/[\x00-\x1F\x7F-\xFF]/) {
>>> +   die "invalid character in tag key\n" if !$noerr;
>>> +   return undef;
>>> +   }
>>> +   if ($value =~ m/[\x00-\x1F\x7F-\xFF]/) {
>>> +   die "invalid character in tag value\n" if !$noerr;
>>> +   return undef;
>>> +   }
>>> +}
>>> +
>>> +return $tagstring;
>>> +}
>>>  my $agent_fmt = {
>>>  enabled => {
>>> description => "Enable/disable Qemu GuestAgent.",
>>> @@ -672,6 +695,13 @@ EODESCR
>>> description => "Configure a audio device, useful in combination with 
>>> QXL/Spice.",
>>> optional => 1
>>>  },
>>> +tags => {
>>> +   description => "Specify key/value pairs to be added to qemu fw_cfg.",
>>> +   type => 'string',
>>> +   maxLength => 4096,
>>> +   format => 'pve-qm-tags',
>>> +   optional => 1,
>>> +},
>>>  };
>>>  
>>>  my $cicustom_fmt = {
>>> @@ -4152,6 +4182,13 @@ sub config_to_command {
>>> push @$cmd, '-loadstate', $statepath;
>>>  }
>>>  
>>> +if ($conf->{tags}) {
>>> +   for my $tag (split(';', $conf->{tags})) {
>>> +   my ($key, $value) = ($tag =~ m/^(.*)=(.*)$/);
> 
> what do I do when I need a ";" in a value or a "=" in a key?
> 
>>> +   push @$cmd, '-fw_cfg', "name=opt/com.proxmox/$key,string=$value";
>>> +   }
>>> +}
>>> +
>>>  # add custom args
>>>  if ($conf->{args}) {
>>> my $aa = PVE::Tools::split_args($conf->{args});
>>> -- 
>>> 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 qemu-server] fix #1934: add qemu fw_cfg variables via 'tags'

2019-09-04 Thread Fabian Grünbichler
On September 4, 2019 8:49 am, Dominik Csapak wrote:
> On 9/2/19 2:14 PM, Fabian Grünbichler wrote:
>> On August 23, 2019 2:03 pm, Dominik Csapak wrote:
>>> this add the 'tags' property to vms, which has the format:
>> 
>> why 'tags'? seems rather generic for what it does ;)
> 
> because the request in the bugreport was a more general one
> (users wanted to simply set some tags for the vm
> which are not in the description)
> 
> i just wanted to also use them besides simply having them in
> the config ;)

to me that sounds like rather unexpected behaviour. while there is some 
overlap between "tagging guest for categorization" and "exposing 
key-value pairs to guest", there are plenty of cases where the 
information from the former should not be exposed to the guest (e.g., an 
admin tagging annoying users with unflattering tag values ;)), and 
vice-versa, where having everything put into fw_cfg displayed as 
categorization tags is inconvenient/cluttering as well.

I am not opposed to a general 'tagging' feature at all (even if just for 
search/filtering and display purposes), but I'd keep it distinct from 
the fw_cfg stuff.

___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [RFC qemu-server] rewrite description for vm_config

2019-09-05 Thread Fabian Grünbichler
On September 4, 2019 3:59 pm, Oguz Bektas wrote:
> the description doesn't match the default behaviour, which is to replace
> the current values with pending ones in the returned config, unless the
> 'current' option is passed.
> 
> Signed-off-by: Oguz Bektas 
> ---
> 
> i tried to come up with a reasonable description, but sending it as RFC
> just in case someone else comes up with something better
> 
>  PVE/API2/Qemu.pm | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
> index b30931d..36487ee 100644
> --- a/PVE/API2/Qemu.pm
> +++ b/PVE/API2/Qemu.pm
> @@ -827,7 +827,8 @@ __PACKAGE__->register_method({
>  path => '{vmid}/config',
>  method => 'GET',
>  proxyto => 'node',
> -description => "Get current virtual machine configuration. This does not 
> include pending configuration changes (see 'pending' API).",
> +description => "Get virtual machine configuration. If the 'current' 
> option is" .
> + " not passed, pending changes will replace the current 
> ones.",

besides style, this is also incorrect since you can pass '0' for 
'current' ;)

Get virtual machine configuration. If 'current' is set, any pending 
configuration changes will not be included in the returned value. 
Otherwise, the returned configuration values will represent the state 
with all pending changes applied.

A bit verbose, but matching what it does. Alternatively, just

Get virtual machine configuration. See 'pending' API for current and 
pending configuration retrieval.

and leave the rest to the parameter description?

current -> "Get current values only (ignoring pending changes)."

>  permissions => {
>   check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]],
>  },
> -- 
> 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


Re: [pve-devel] [PATCH v3 guest-common 1/2] fix #1291: implement remove_vmid_from_backup_jobs

2019-09-05 Thread Fabian Grünbichler
On September 4, 2019 4:41 pm, Thomas Lamprecht wrote:
> On 01.07.19 15:43, Christian Ebner wrote:
>> remove_vmid_from_backup_jobs updates the vzdump.cron backup jobs,
>> excluding the given vmid.
>> 
>> Signed-off-by: Christian Ebner 
>> ---
>>  PVE/VZDump/Plugin.pm | 46 
>>  1 file changed, 46 insertions(+)
>> 
>> diff --git a/PVE/VZDump/Plugin.pm b/PVE/VZDump/Plugin.pm
>> index 9933ef6..f415242 100644
>> --- a/PVE/VZDump/Plugin.pm
>> +++ b/PVE/VZDump/Plugin.pm
>> @@ -7,6 +7,8 @@ use POSIX qw(strftime);
>>  
>>  use PVE::Tools;
>>  use PVE::SafeSyslog;
>> +use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
>> +use PVE::API2::Backup;
>^
> above won't fly, that's a module from pve-manager and thus would create a 
> cyclic
> build dependency.. And I'd rather reduce than increase them ;)
> 
> The use is for the vzdump cron parser/writer which are cfs_registered in that
> file.. So either we move that out to a module here (or even higher up) or do
> something else, avoiding use of modules which are lower in the dependency 
> chain.
> 

we want to use it from pve-container and qemu-server, so the only sane 
choice is to move the cfs_register part to guest-common IMHO. polluting 
pve-common or pve-cluster (or pve-access-control) is even worse, and 
there's nothing else that fits the bill that we can access from 
pve-container and qemu-server unless I am missing something..

___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] applied: [PATCH common] add postinst hook to fix /etc/aliases whitespace error

2019-09-05 Thread Fabian Grünbichler
thanks to all three involved people ;)

On September 3, 2019 1:06 pm, Thomas Lamprecht wrote:
> This was wrongly shipped by our ISO since quite a bit (AFAICT, at
> least 4.x), so fix it up in a versioned postinst snippet.
> 
> Do so by usind sed with the following pattern:
>  # sed -E -i -e 's/^www:(\w)/www: \1/' /etc/aliases
> proposed by Musee Ullah[0]. It even catches a bit more than exactly
> our misstep, may help if one copied this line, or added some other
> addresses to this specific aliases entry.
> 
> Do this here, in pve-common, as it makes it sligthly simpler to roll
> the change out to both, PVE and PMG.
> 
> [0]: https://pve.proxmox.com/pipermail/pve-user/2019-September/170998.html
> 
> Reported-by: Uwe Sauter 
> Signed-off-by: Thomas Lamprecht 
> ---
> 
> One could even add to the proposed solution to make it more general:
>  # sed -E -i -e 's/^([^\s:]+):(\w)/\1: \2/' /etc/aliases
> 
> but I think that's not in our responsibility..
> Open for different place to add this, but shared between PMG and PVE
> /is/ really nice, IMO.
> 
>  debian/postinst | 20 
>  1 file changed, 20 insertions(+)
>  create mode 100644 debian/postinst
> 
> diff --git a/debian/postinst b/debian/postinst
> new file mode 100644
> index 000..5a19c69
> --- /dev/null
> +++ b/debian/postinst
> @@ -0,0 +1,20 @@
> +#!/bin/sh
> +
> +set -e
> +
> +#DEBHELPER#
> +
> +case "$1" in
> +  configure)
> +if test -n "$2"; then
> +
> +# TODO: remove once PVE 7.0 is released
> +if dpkg --compare-versions "$2" 'lt' '6.0-5'; then
> +sed -E -i -e 's/^www:(\w)/www: \1/' /etc/aliases
> +   fi
> +fi
> +;;
> +
> +esac
> +
> +exit 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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH ha-manager 0/4] Add inital HW based fencing

2019-09-06 Thread Fabian Grünbichler
On March 27, 2019 5:42 pm, Thomas Lamprecht wrote:
> Actually this'd be v8, but it's to old and to unreviewed for anybody do
> remember anyway, so best seen as new series.
> 
> Thomas Lamprecht (4):
>   allow LRM lock stealing for fenced nodes
>   allow use of external fencing devices
>   send also email on hardware fence failure
>   add some infos about HW fencing to README

first off, sorry for the long delay..

low-level nits and questions as replies to individual patches, some 
stuff I noticed while testing, mostly regarding the already merged 
Fence/FenceConfig code:

1) missing 'use FenceConfig;' in PVE::HA::Config.pm

2) as discussed off-list, it would be great if the fork could be moved 
into exec_fence_agent to get rid of the test/ha env distinction in 
Fence.pm (possibly as follow-up, since it does not change the 
semantics/functionality)

3) the simulator does not support fencing_mode 'both' (since it just 
decides beside on whether a fence config exists)

4) I wonder whether there is a use-case for an actual 'both' mode (since 
IMHO the current 'both' mode is more like an 'either' mode, we are just 
waiting for hardware or regular fencing to go through, not both ;)):

something like a hardware fence device that is optional and helpful, but 
alone is not enough to ensure that the node is actually fully fenced.

e.g., fence the network of the node via switch (to prevent further 
client access), but we still need to wait for the regular fencing to go 
through since all nodes have some non-network shared storage,
so the not-yet-stopped services on the fenced node can still write to 
the shared disks until the node is fully fenced.

or some other hacky use cases, like marking OSDs as down & out via 
fencing, but that is more abuse case than use case ;)

possible this could also be done via fence.cfg, by marking certain 
devices as 'not enough to consider fenced'? obviously with fencing_mode 
hardware you'd need at least one proper device ;)

5) the config parser/writer pair is broken:
- writer: does not re-quote the node args
- parser: both [args] are not actually optional (like the README says)

(the writer is not yet used anywhere)

$ cat /etc/pve/ha/fence.cfg

device pve_nina:1 fence_pve 'ip=192.168.15.38' 'username=fäöµ€' 
'password=12"345'
connect pve_nina:1 node=node1 plug=500 x
connect pve_nina:1 node=node2 'username=fäöµ€' 'password=12"345'

$ perl -e  'use strict; use warnings; use Data::Dumper; use PVE::Cluster; use 
PVE::HA::FenceConfig; use PVE::HA::Config; PVE::Cluster::cfs_update(); my $cfg 
= PVE::HA::Config::read_fence_config(); print Dumper($cfg), "\n"; 
PVE::HA::Config::write_fence_config($cfg);'
$VAR1 = {
  'pve_nina' => {
'priority' => 0,
'sub_devs' => {
  '1' => {
'node_args' => {
  'node2' => [
'username=fäöµ€',
'password=12"345'
  ],
  'node1' => [
'plug=500',
'x'
  ]
},
'args' => [
  'ip=192.168.15.38',
  'username=fäöµ€',
  'password=12"345'
],
'agent' => 'fence_pve'
  }
}
  }
};

quotes from node arguments were dropped by the writer:

$ cat /etc/pve/ha/fence.cfg

device pve_nina:1 fence_pve 'ip=192.168.15.38' 'username=fäöµ€' 
'password=12"345'
connect pve_nina:1 node=node1 plug=500 x
connect pve_nina:1 node=node2 username=fäöµ€ password=12"345

$ perl -e  'use strict; use warnings; use Data::Dumper; use PVE::Cluster; use 
PVE::HA::FenceConfig; use PVE::HA::Config; PVE::Cluster::cfs_update(); my $cfg 
= PVE::HA::Config::read_fence_config(); print Dumper($cfg), "\n"; 
PVE::HA::Config::write_fence_config($cfg);'
$VAR1 = {
  'pve_nina' => {
'sub_devs' => {
  '1' => {
'agent' => 'fence_pve',
'node_args' => {
  'node2' => [],
  'node1' => [
'plug=500',
'x'
  ]
},
'args' => [
  'ip=192.168.15.38',
  'username=fäöµ€',
  'password=12"345'
]
  }
},
'priority' => 0
  }
};

which makes the parser fail since the input is not properly quoted, 
dropping the args altogether!?

$ cat /etc/pve/ha/fence.cfg

device pve_nina:1 fence_pve 'ip=192.168.15.38' 'username=fäöµ€' 
'password=12"345'
connect pve_nina:1 node=node1 plug=500 x
connect pve_nina:1 node=node2 

$ perl -e  'use strict; use warnings; use Data::Dumper; use PVE::Cluster; use 
PVE::HA::FenceConfig; use PVE::HA::Config; PVE::Cluster::cfs_update(); my $cfg 
= PVE::HA::Config::read_fence_config(); print Dumper($cfg), "\n"; 
PVE::HA::Config::write_fence_config($cfg);'
/etc/pve/ha/fence.cfg ignore line 4: connect pve_nina:1 node=node2
$VAR1 = {
  'pve_nina' => {
'priority' => 0,
'sub_devs' => {
  '1' => {
'args' => [
  'ip=192.168.15.38',
  'username=fäöµ€',
  'password=12"345'
],
'node_args' => {
  'node1' => [
'plug=500',
'x'
  ]
},
   

Re: [pve-devel] [PATCH ha-manager 4/4] add some infos about HW fencing to README

2019-09-06 Thread Fabian Grünbichler
On March 27, 2019 5:42 pm, Thomas Lamprecht wrote:

missing S-O-B

missing information about the fencing mode semantics? there's just one 
sentence in 'man datacenter.cfg', see patch #2/cover letter comments.

looks fine for git-level readme, would need more grammaer/style cleanup 
for reference docs IMHO.

one nit inline, otherwise

Acked-by: Fabian Grünbichler 

> ---
>  README | 110 +
>  1 file changed, 110 insertions(+)
> 
> diff --git a/README b/README
> index 1c5177f..dbf8d6a 100644
> --- a/README
> +++ b/README
> @@ -72,6 +72,116 @@ works using reliable HW fence devices.
>  
>  Above 'self fencing' algorithm does not work if you use this option!
>  
> +== Hardware Fencing ==
> +
> +This is for the users who want to use external fence devices.
> +
> +While they may have some advantages like:
> +
> +- possible faster recovery as its normally faster than the lock timeout
> +
> +- soft watchdog can (!) be less reliable
> +
> +- maybe someone does not want to reset but rather cut the machine off for
> +  investigation
> +
> +But also can introduce some disadvantages, like:
> +
> +- added complexity
> +
> +- depends on external device (which can also fail)
> +
> +=== Fence Agents Supported ===
> +
> +We package the fence-agents collection from ClusterLabs:
> +https://github.com/ClusterLabs/fence-agents

nit: no longer true (atm?)

> +apt install fence-agents
> +
> +This has a wide variety of supported fence agents and should cover all needs.
> +
> +If you must use special hardware you can write your own agent, simply follow
> +the specs from the ClusterLabs agent so that your and their agents are 
> interface
> +compatible.
> +
> +At least they have to support the following parameters:
> +- node
> +- plug
> +- action
> +
> +
> +=== Fence Device Configuration ===
> +
> +We use the configuration schema from dlm.conf (see man dlm.conf),
> +this allows us to use a quite easily and simple configuration schema
> +while not restricting an user, as complex setups are still possible.
> +
> +The basic format looks like:
> +
> +  device  dev_name agent [args]
> +  connect dev_name node=nodeid [args]
> +  connect dev_name node=nodeid [args]
> +  connect dev_name node=nodeid [args]
> +
> +Example:
> +
> +  # simple devices
> +  device first_dev fence_pve ip="192.168.XX.XX" password="12345" action=off
> +  connect first_dev node=node1 plug=100
> +  connect first_dev node=node2 plug=101
> +  connect first_dev node=node3 plug=102
> +
> +But the schema is able to do more, e.g., parallel devices or even multiple
> +devices can be configured per node. They will be executed from top to bottom
> +until the first fence device (set) succeeds.
> +
> +NOTE: use the longopts where possible, e.g.: use username=foo instead of 
> l=foo
> +  if a option has only a short option and its boolean then you may use 
> it.
> +
> +=== Internal Configuration Representation ===
> +
> +We use an hash with a structure like this:
> +
> +#my $test_fence_device = {
> +#foo_apc => { # <-- device name
> +#priority => 0,
> +#sub_devs => {
> +#1 => { # two parallel devices
> +#agent => "fence_apc",
> +#args => ['ip=192.168.1.50', 'username=fencing', 
> 'password=12345', 'x', 'o=off'],
> +#node_args => {
> +#uno => [n=1', 's=1'],
> +#due => [n=2', 's=2'],
> +#tre => [n=3', 's=1'],
> +#},
> +#},
> +#2 => {
> +#agent => "fence_apc",
> +#args => ['ip=192.168.1.51', 'username=fencing', 
> 'password="12345 asd"', 'x', 'o=off'],
> +#node_args => {
> +#uno => [n=1', 's=1'],
> +#due => [n=2', 's=2'],
> +#tre => [n=3', 's=1'],
> +#},
> +#},
> +#}
> +#},
> +#bar_device => { # second fence device
> +#priority => 1,
> +#sub_devs => {
> +#1 => {
> +#agent => "fence_pve",
> +#args => ['ip=192.168.1.18', 'password="12345 asd"', 'o=off'],
> +#node_args => {
> +#uno => [n=100', 's=1'],
> +#due => [n=101', 's=1'],
> +#tre => [n=102', 's=1'],
> +#},
> +#},
> +#}
> +#},
> +#};
> +
> +
>  == Testing requirements ==
>  
>  We want to be able to simulate HA cluster, using a GUI. This makes it easier
> -- 
> 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


Re: [pve-devel] [PATCH ha-manager 3/4] send also email on hardware fence failure

2019-09-06 Thread Fabian Grünbichler
On March 27, 2019 5:42 pm, Thomas Lamprecht wrote:
> We introduced sending an email when Fencing fails/succeeds in
> general some time ago, send now also an email if a HW fence
> fails

missing S-O-B

> ---
>  src/PVE/HA/NodeStatus.pm | 7 ---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/src/PVE/HA/NodeStatus.pm b/src/PVE/HA/NodeStatus.pm
> index ca13f2f..c4d147c 100644
> --- a/src/PVE/HA/NodeStatus.pm
> +++ b/src/PVE/HA/NodeStatus.pm
> @@ -2,6 +2,7 @@ package PVE::HA::NodeStatus;
>  
>  use strict;
>  use warnings;
> +
>  use PVE::HA::Fence;
>  
>  use JSON;
> @@ -204,7 +205,6 @@ EOF
>  $haenv->sendmail($mail_subject, $mail_text);
>  };
>  
> -
>  # start fencing
>  sub fence_node {
>  my ($self, $node) = @_;
> @@ -230,8 +230,9 @@ sub fence_node {
>  
>   # bad fence.cfg or no devices and only hardware fencing configured
>   if ($hw_fence_success < 0 && $fencing_mode eq 'hardware') {
> - $haenv->log('err', "Fencing of node '$node' failed and needs " .
> - "manual intervention!");
> + my $msg = "Fencing of node '$node' failed and needs manual 
> intervention!";
> + $haenv->log('err', $msg);
> + &$send_fence_state_email($self, 'FAILED', $msg, $node);

seems like a good idea in general, but see patch #2 - this part gets 
called over and over again if hardware fencing fails? e.g.,

./ha-tester.pl test-hw-fence1 --nodiff | grep emai
emai160node1/crm: FENCE: Try to fence node 'node3'
emai160node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai160node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai180node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai200node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai220node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai240node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai260node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai280node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai300node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai320node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai340node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai360node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai380node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai400node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai420node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai440node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai460node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai480node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai500node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai520node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai540node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai560node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai580node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai600node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai620node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai640node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai660node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai680node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!
emai700node1/crm: FAILED: Fencing of node 'node3' failed and needs 
manual intervention!

if I hardcode $hw_success to -1

or is this just an artifact of some simulator limitation?

>   return 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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH ha-manager 2/4] allow use of external fencing devices

2019-09-06 Thread Fabian Grünbichler
On March 27, 2019 5:42 pm, Thomas Lamprecht wrote:
> A node now can be fenced with the use of external hardware fence
> devices.
> Those device can be configured at /etc/pve/ha/fence.cfg
> also the fencing option in the datacenter configuration file must
> be set to either 'hardware' or 'both', else configured devices
> will *not* be used.
> 
> If hardware is selected as mode a valid device config *must* be
> made, the fencing will not be marked as successful even if the CRM
> could theoretical acquire the lock from the failed node!
> This is done as some setups may require a HW fence agent to cut the
> node off and where a watchdog which resets the node may be
> dangerous.

this is worded a big confusingly, but the gist is:
mode => hardware means the fence device must be configured correctly and 
work for fencing to succeed, mode => both means a fallback to regular 
CRM fencing (which means that 'both' is more like 
'fallback_to_watchdog' or 'either') ?

> 
> We always *must* acquire the log before we can mark the failed node
> as fenced and place it into the 'unknown' state and recover its
> services.
> 
> The CRM bails out in case of an lost manager lock event where
> $manager->cleanup() gets called.
> There we kill all remaining open fence processes, if any,
> and reset the fence status.
> 
> The currents masters manager class processes the running fencing
> jobs, this means picking up finished fence workers and evaluating
> their result.
> 
> Now regressions test with faked virtual HW fence devices are also
> possible.
> The current virtual devices succeed always, this will be changed
> in a future patch to allow testing of more (dangerous) corner cases.
> 
> Device can be configured in the testdir/fence.cfg file and follow
> the exactly same format as the real ones (see man dlm.conf)

some nits and questions inline

missing S-O-B
> ---
>  src/PVE/HA/Manager.pm   |   4 +-
>  src/PVE/HA/NodeStatus.pm|  54 +++-
>  src/test/test-hw-fence1/README  |   1 +
>  src/test/test-hw-fence1/cmdlist |   4 +
>  src/test/test-hw-fence1/fence.cfg   |   6 ++
>  src/test/test-hw-fence1/hardware_status |   5 ++
>  src/test/test-hw-fence1/log.expect  |  53 
>  src/test/test-hw-fence1/manager_status  |   1 +
>  src/test/test-hw-fence1/service_config  |   5 ++
>  src/test/test-hw-fence2/README  |   3 +
>  src/test/test-hw-fence2/cmdlist |   5 ++
>  src/test/test-hw-fence2/fence.cfg   |   8 ++
>  src/test/test-hw-fence2/hardware_status |   7 ++
>  src/test/test-hw-fence2/log.expect  | 110 
>  src/test/test-hw-fence2/manager_status  |   1 +
>  src/test/test-hw-fence2/service_config  |  10 +++
>  src/test/test-hw-fence3/README  |   5 ++
>  src/test/test-hw-fence3/cmdlist |   4 +
>  src/test/test-hw-fence3/fence.cfg   |  17 
>  src/test/test-hw-fence3/hardware_status |   5 ++
>  src/test/test-hw-fence3/log.expect  |  57 
>  src/test/test-hw-fence3/manager_status  |   1 +
>  src/test/test-hw-fence3/service_config  |   5 ++
>  23 files changed, 369 insertions(+), 2 deletions(-)
>  create mode 100644 src/test/test-hw-fence1/README
>  create mode 100644 src/test/test-hw-fence1/cmdlist
>  create mode 100644 src/test/test-hw-fence1/fence.cfg
>  create mode 100644 src/test/test-hw-fence1/hardware_status
>  create mode 100644 src/test/test-hw-fence1/log.expect
>  create mode 100644 src/test/test-hw-fence1/manager_status
>  create mode 100644 src/test/test-hw-fence1/service_config
>  create mode 100644 src/test/test-hw-fence2/README
>  create mode 100644 src/test/test-hw-fence2/cmdlist
>  create mode 100644 src/test/test-hw-fence2/fence.cfg
>  create mode 100644 src/test/test-hw-fence2/hardware_status
>  create mode 100644 src/test/test-hw-fence2/log.expect
>  create mode 100644 src/test/test-hw-fence2/manager_status
>  create mode 100644 src/test/test-hw-fence2/service_config
>  create mode 100644 src/test/test-hw-fence3/README
>  create mode 100644 src/test/test-hw-fence3/cmdlist
>  create mode 100644 src/test/test-hw-fence3/fence.cfg
>  create mode 100644 src/test/test-hw-fence3/hardware_status
>  create mode 100644 src/test/test-hw-fence3/log.expect
>  create mode 100644 src/test/test-hw-fence3/manager_status
>  create mode 100644 src/test/test-hw-fence3/service_config
> 
> diff --git a/src/PVE/HA/Manager.pm b/src/PVE/HA/Manager.pm
> index a6c9b8e..177dfc2 100644
> --- a/src/PVE/HA/Manager.pm
> +++ b/src/PVE/HA/Manager.pm
> @@ -7,6 +7,7 @@ use Digest::MD5 qw(md5_base64);
>  use PVE::Tools;
>  use PVE::HA::Tools ':exit_codes';
>  use PVE::HA::NodeStatus;
> +use PVE::HA::Fence;
>  
>  sub new {
>  my ($this, $haenv) = @_;
> @@ -32,7 +33,8 @@ sub new {
>  sub cleanup {
>  my ($self) = @_;
>  
> -# todo: ?
> +# reset pending fence jobs and node states
> +$self->{ns}->cleanup();
>  }
>  
>  sub flush_master_status {
> diff --git a/src/PVE/HA/NodeStatus.pm b

Re: [pve-devel] [PATCH ha-manager 1/4] allow LRM lock stealing for fenced nodes

2019-09-06 Thread Fabian Grünbichler
On March 27, 2019 5:42 pm, Thomas Lamprecht wrote:
> We are only allowed to recover (=steal) a service when we have its
> LRMs lock, as this guarantees us that even if said LRM comes up
> again during the steal operation the LRM cannot start the services
> when the service config still belongs to it for a short time.
> 
> This is important, else we have a possible race for the resource
> which can result in a service started on the old (restarted) node
> and the node where the service was recovered too, which is really
> bad!

two very long sentences ;)

In order to recover (=steal) a service from a fenced node, we need to 
own its LRM's lock. Otherwise, the fenced node could start the service 
during the short timespan where it still owns the service config file. 

This requirement prevents a race between the stealing node and the 
fenced node - we never want to start a service on two nodes!

small nits inline, otherwise

Acked-by: Fabian Grünbichler 
> ---
>  src/PVE/HA/Env.pm  |  4 ++--
>  src/PVE/HA/Env/PVE2.pm |  4 ++--
>  src/PVE/HA/Sim/Env.pm  | 16 ++--
>  3 files changed, 14 insertions(+), 10 deletions(-)
> 
> diff --git a/src/PVE/HA/Env.pm b/src/PVE/HA/Env.pm
> index bb37486..6b76496 100644
> --- a/src/PVE/HA/Env.pm
> +++ b/src/PVE/HA/Env.pm
> @@ -171,9 +171,9 @@ sub get_ha_agent_lock {
>  # this should only get called if the nodes LRM gracefully shuts down with
>  # all services already cleanly stopped!
>  sub release_ha_agent_lock {
> -my ($self) = @_;
> +my ($self, $node) = @_;
>  
> -return $self->{plug}->release_ha_agent_lock();
> +return $self->{plug}->release_ha_agent_lock($node);
>  }
>  
>  # return true when cluster is quorate
> diff --git a/src/PVE/HA/Env/PVE2.pm b/src/PVE/HA/Env/PVE2.pm
> index 796acd9..4428ed4 100644
> --- a/src/PVE/HA/Env/PVE2.pm
> +++ b/src/PVE/HA/Env/PVE2.pm
> @@ -309,9 +309,9 @@ sub get_ha_agent_lock {
>  # this should only get called if the nodes LRM gracefully shuts down with
>  # all services already cleanly stopped!

nit: this comment is now no longer true? we also call it after HW fencing, 
which is possibly at the other end of the forceful vs graceful spectrum ;)

nit: I'd actually prefer splitting the release and steal into two separate 
subs, to make it obvious what is happening also at first glance at the 
call site(s). they are short and trivial enough that the duplication
should be harmless, but they can of course also be wrappers around the 
code below.

>  sub release_ha_agent_lock {
> -my ($self) = @_;
> +my ($self, $node) = @_;
>  
> -my $node = $self->nodename();
> +$node = $node || $self->nodename();
>  
>  return rmdir("$lockdir/ha_agent_${node}_lock");
>  }
> diff --git a/src/PVE/HA/Sim/Env.pm b/src/PVE/HA/Sim/Env.pm
> index 22e13e6..171e486 100644
> --- a/src/PVE/HA/Sim/Env.pm
> +++ b/src/PVE/HA/Sim/Env.pm
> @@ -83,13 +83,17 @@ sub sim_get_lock {
>   if (my $d = $data->{$lock_name}) {
>   my $tdiff = $ctime - $d->{time};
>  
> + my $manager_node = $data->{'ha_manager_lock'}->{node} || '';
> +
> + $res = 0;
>   if ($tdiff > $self->{lock_timeout}) {
>   $res = 1;
> - } elsif (($tdiff <= $self->{lock_timeout}) && ($d->{node} eq 
> $nodename)) {
> - delete $data->{$lock_name};
> - $res = 1;
>   } else {
> - $res = 0;
> + # if we aren't manager we may unlock only *our* lock
> + if ($d->{node} eq $nodename || $manager_node eq $nodename) {
> + delete $data->{$lock_name};
> + $res = 1;
> + }
>   }
>   }
>  
> @@ -342,9 +346,9 @@ sub get_ha_agent_lock {
>  # this should only get called if the nodes LRM gracefully shuts down with
>  # all services already cleanly stopped!
>  sub release_ha_agent_lock {
> -my ($self) = @_;
> +my ($self, $node) = @_;
>  
> -my $node = $self->nodename();
> +$node = $node || $self->nodename();
>  
>  my $lock = $self->get_ha_agent_lock_name($node);
>  return $self->sim_get_lock($lock, 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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH qemu 1/7] Trigger pve-api-updates on update

2019-09-06 Thread Fabian Grünbichler
On September 2, 2019 4:27 pm, Stefan Reiter wrote:
> A QEMU update can change supported CPU flags, thus we need to restart
> API services (especially pvestatd) to refresh their cached values.

given the recent discussion about this exact change, we could also use 
PVE::QemuServer::kvm_user_version() to decide whether we want to reload 
the CPU flag information. it's one additional stat for each pvestatd 
update cycle, but given all the other stuff we do there, it's probably 
not that expensive ;)

> Signed-off-by: Stefan Reiter 
> ---
>  debian/triggers | 1 +
>  1 file changed, 1 insertion(+)
>  create mode 100644 debian/triggers
> 
> diff --git a/debian/triggers b/debian/triggers
> new file mode 100644
> index 000..59dd688
> --- /dev/null
> +++ b/debian/triggers
> @@ -0,0 +1 @@
> +activate-noawait pve-api-updates
> -- 
> 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


Re: [pve-devel] [PATCH manager 2/7] Broadcast supported CPU flags

2019-09-06 Thread Fabian Grünbichler
On September 2, 2019 4:27 pm, Stefan Reiter wrote:
> pvestatd will read supported CPU flags once on startup (since these
> never change during runtime, and QEMU updates trigger a service
> restart), then broadcasts them as a key-value pair to the cluster.
> 
> Signed-off-by: Stefan Reiter 
> ---
> 
> Changes from RFC:
> 
> * Cache joined value
> * Add eval around QEMU query
> * Detect value regression (e.g. "better" value available in cluster kv) and
>   handle accordingly
> 
> 
>  PVE/Service/pvestatd.pm | 28 ++--
>  1 file changed, 26 insertions(+), 2 deletions(-)
> 
> diff --git a/PVE/Service/pvestatd.pm b/PVE/Service/pvestatd.pm
> index e138b2e8..84258daf 100755
> --- a/PVE/Service/pvestatd.pm
> +++ b/PVE/Service/pvestatd.pm
> @@ -47,12 +47,15 @@ my $cmdline = [$0, @ARGV];
>  my %daemon_options = (restart_on_error => 5, stop_wait_time => 5);
>  my $daemon = __PACKAGE__->new('pvestatd', $cmdline, %daemon_options);
>  
> +my $supported_cpuflags;
> +
>  sub init {
>  my ($self) = @_;
>  
>  $opt_debug = $self->{debug};
>  
>  PVE::Cluster::cfs_update();
> +update_supported_cpuflags();

but this only happens once, not on every status update cycle like all 
the other update_foo subs? if we go the "cache based on 
kvm_user_version" route, then this could actually move to update_status

>  }
>  
>  sub shutdown {
> @@ -72,6 +75,25 @@ sub hup {
>  $restart_request = 1;
>  }
>  
> +sub update_supported_cpuflags {

at least if this is reworked:

1.) get kvm_user_version
2.) check if cached kvm_user_version is different
3.) yes -> query_supported_cpu_flags, cache results + kvm_user_version
4.) yes -> handle regressions
5.) broadcast supported flags

> +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 '') {
> + $supported_cpuflags = $prev_cpuflags;
> + warn "CPU flag detection failed, using old values\n";
> + } else {
> + $supported_cpuflags = '';
> + warn "CPU flag detection failed and no previous values found\n";
> + }
> +}
> +}
> +
>  my $generate_rrd_string = sub {
>  my ($data) = @_;
>  
> @@ -91,7 +113,9 @@ sub update_node_status {
>  
>  my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
>  
> -my $maxcpu = $cpuinfo->{cpus}; 
> +my $maxcpu = $cpuinfo->{cpus};
> +
> +PVE::Cluster::broadcast_node_kv('cpuflags', $supported_cpuflags);

this can then be replaced with a call to update_supported_cpuflags

>  
>  my $subinfo = PVE::INotify::read_file('subscription');
>  my $sublevel = $subinfo->{level} || '';
> @@ -104,7 +128,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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH qemu-server 3/7] Add QEMU CPU flag querying helpers

2019-09-06 Thread Fabian Grünbichler
On September 2, 2019 4:27 pm, Stefan Reiter wrote:
> * 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.
> 
> Signed-off-by: Stefan Reiter 
> ---
> 
> Changes from RFC:
> 
> * Clearer regexes
> * Use existing QMP infrastructure
> * Add locking for temporary VM start
> * Add comments
> 
> 
>  PVE/QemuServer.pm | 84 +++
>  1 file changed, 84 insertions(+)
> 
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 8c519b5..97fa955 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -3500,6 +3500,90 @@ sub get_command_for_arch($) {
>  return $cmd;
>  }
>  
> +# The format of the flags returned here uses dashes '-' as seperators,

nit: s/seperator/separator/a

> +# this is neither the default for 'query_supported_cpu_flags' below, nor for
> +# /proc/cpuinfo.
> +#
> +# To compare (or array_intersect) flags, it's a good idea to convert them all
> +# to a common format first (e.g. map s/\.|-/_/g).
> +sub query_understood_cpu_flags {

not used anywhere in this series? also, confusingly, this returns less 
values then the other helper (maybe because of some aliases?), and it's 
not a strict subset :-/

I guess this is in preparation of exposing it via the API? some sort of 
comment how _understood and _supported interact/are supposed to interact 
would be nice. either as comment or part of the commit message

> +my $flags = [];
> +my $flag_section = 0;
> +
> +run_command(
> + [get_command_for_arch('x86_64'), '-cpu', 'help'],

why not get_host_arch()?

> + noerr => 1,
> + quiet => 1,
> + outfunc => sub {
> + my ($line) = @_;
> +
> + if ($flag_section) {
> + return if $line =~ m/^\s*$/;
> + $line =~ s/^\s*|\s*$//g;
> + push @$flags, split(/\s+/, $line);
> + } elsif ($line =~ m/^\s*Recognized CPUID flags:\s*$/) {
> + $flag_section = 1;
> + }
> + }
> +);
> +
> +return $flags;
> +}
> +
> +# This function 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
> +# pvestatd using PVE::Cluster::get_node_kv('cpuflags').

s/pvestatd/pmxcfs/

pvestatd is just the one putting it there ;)

> +#
> +# See also note to query_understood_cpu_flags above.
> +sub query_supported_cpu_flags {
> +my $flags = [];
> +
> +my $vmid = -1;
> +my $pidfile = pidfile_name($vmid);
> +
> +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('x86_64'),

again, why not get_host_arch()?

> + '-cpu', 'kvm64',
> + '-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 => 1);
> + return if $rc;
> +
> + 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';
> + }
> + }
> +
> + # force stop with 10 sec timeout and 'nocheck'
> + vm_stop(undef, $vmid, 1, 1, 10, 0, 1);
> +});
> +
> +# QEMU returns some flags multiple times, with '_', '.' or '-' as 
> seperator
> +# (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 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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH qemu-server 4/7] Add CustomCPUConfig for storing/parsing custom CPU models

2019-09-09 Thread Fabian Grünbichler
On September 2, 2019 4:27 pm, Stefan Reiter wrote:
> Inherits from SectionConfig to provide base parsing infrastructure.
> 
> Use with helper functions:
> * config_from_file gives bless'd config
> * get_model_by_name returns a "formatted" hash for a single CPU model
> * config_to_file writes changes back
> 
> File reads are cached in a local hash.

high-level:

use cfs_register/write/read_file please (it's our mechanism for handling 
config files on pmxcfs after all ;))

is there a reason you need a class-like interface here? we usually use 
that if we want to have multiple implementations of a certain interface 
with a common shared code base, but that is not the case here..

> 
> Signed-off-by: Stefan Reiter 
> ---
> 
> This will definitely require some sort of versioning mechanism, otherwise CPU
> definitions could be changed after starting a VM, thus breaking live-migration
> by starting the migration-target with different parameters.
> 
> Hints, ideas, recommendations?

versioning is one possibility (cumbersome with SectionConfig though).

another would be to retrieve the CPU model from the running Qemu 
instance, and convert that back to a '-cpu ...' string for starting the 
target instance. if nothing hot-pluggable can change the generated -cpu 
string, we could also record that somewhere (or take it from 
/proc/$pid/cmdline) and override the target instance with that.

>  PVE/QemuServer/CustomCPUConfig.pm | 129 ++
>  PVE/QemuServer/Makefile   |   1 +
>  2 files changed, 130 insertions(+)
>  create mode 100644 PVE/QemuServer/CustomCPUConfig.pm
> 
> diff --git a/PVE/QemuServer/CustomCPUConfig.pm 
> b/PVE/QemuServer/CustomCPUConfig.pm
> new file mode 100644
> index 000..87ba9e6
> --- /dev/null
> +++ b/PVE/QemuServer/CustomCPUConfig.pm
> @@ -0,0 +1,129 @@
> +package PVE::QemuServer::CustomCPUConfig;
> +
> +use strict;
> +use warnings;
> +use PVE::Tools qw(file_get_contents file_set_contents);
> +
> +use base qw(PVE::SectionConfig);
> +
> +my $defaultData = {
> +propertyList => {
> + basemodel => {
> + description => "Emulated CPU type to inherit defaults from.",
> + type => 'string',
> + format_description => 'string',
> + default => 'kvm64',

should have the same pattern/format as QemuServer's $cpu_fmt->{cputype}.
in other words, it probably makes sense to extract and re-use that ;)

> + },
> + flags => {
> + description => "List of additional CPU flags separated by ';'."
> +  . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
> +  . " Supports all flags supported by QEMU/KVM.",
> + format_description => '+FLAG[;-FLAG...]',
> + type => 'string',
> + pattern => qr/[+-][a-zA-Z0-9\-_\.]+(;[+-][a-zA-Z0-9\-_\.]+)*/,

same here (different description, please just use a single definition 
for both instances)

> + optional => 1,
> + },
> + 'phys-bits' => {
> + type => 'integer',
> + minimum => 1,
> + maximum => 64,
> + optional => 1,
> + description => "The physical memory bits that are reported to the 
> guest OS. Must be smaller or equal to the host.",

this one might make sense to also allow in the regular, per-VM 'cpu' 
option (and then we could again re-use the definition)

> + },
> + 'host-phys-bits' => {
> + type => 'boolean',
> + default => 0,
> + description => "Whether to report the host's physical memory bits. 
> Overrides 'phys-bits' when set.",
> + },

same

> + vendor => {
> + type => 'string',
> + enum => [qw(default AuthenticAMD GenuineIntel)],
> + default => 'default',
> + description => "The CPU vendor to report. 'default' uses the 
> host's.",
> + },
> +}

this probably only makes sense for the custom types. the default value 
means that you never inherit the vendor from your basemodel - is that 
intended?

there are two more from the regular one that we might want to include in 
custom ones as well:

hidden
hv-vendor-id

I am not sure whether just moving some format definitions, or moving 
all/most CPU related stuff to a new module (e.g., 
QemuServer/CPUConfig.pm instead of QemuServer/CustomCPUConfig.pm) is 
more clean / feasible. the latter probably would require moving some 
helpers from QemuServer.pm to another new module as well, as they'd be 
used by the CPU module and QemuServer.pm

I think we all agree that QemuServer.pm is way too big, so a patch 
(series) that adds new features and reduces that bloat would be more 
than welcome :D but if you think it's too much for this series, we can 
also do it as a follow-up since it's mostly about moving code and format 
definitions.

> +};
> +
> +sub private {
> +return $defaultData;
> +}
> +
> +sub options {
> +return {
> + basemodel => { optional => 1 },
> + flags => { optional => 1 },
> + 'phys-bits' => { optional => 1 },
> +

Re: [pve-devel] [PATCH qemu-server 6/7] Handle CPU flags defined in custom CPU type

2019-09-09 Thread Fabian Grünbichler
On September 2, 2019 4:27 pm, Stefan Reiter wrote:
> Special care is taken not to overwrite any special flags, or ones
> manually set on the VM by the user. We warn if a flag is overruled.

hmm. I am unsure whether I like that behaviour or not. it's a bit 
strange that VM specific flags get applied earlier, and then we skip 
those from the models instead of just switching the order around.

maybe we need some other intermediate data structure, or some helper 
methods?

the following seems more logical to me:

1.) add flags from custom model
2.) add flags from VM config
3.) (selectively) add auto-generated flags (based on other settings, OS, ..)

at each step we want to remove conflicting flags from before (this would 
be where a different datastructure or a helper would come into play). 
maybe some of the auto-generated flags should not override explicitly 
set ones, but be skipped instead (at least for explicit negative 
flags, to allow opt-out).

> 
> Signed-off-by: Stefan Reiter 
> ---
>  PVE/QemuServer.pm | 26 +-
>  1 file changed, 25 insertions(+), 1 deletion(-)
> 
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 417bea8..7cc1674 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -3597,6 +3597,7 @@ sub get_cpu_options {
>  }
>  my $hv_vendor_id;
>  my $custom_cpu_config;
> +my @vm_specific_flags;
>  if (my $cputype = $conf->{cpu}) {
>   my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype)
>   or die "Cannot parse cpu description: $cputype\n";
> @@ -3624,7 +3625,8 @@ sub get_cpu_options {
>   $hv_vendor_id = $cpuconf->{'hv-vendor-id'};
>  
>   if (defined(my $flags = $cpuconf->{flags})) {
> - push @$cpuFlags, split(";", $flags);
> + @vm_specific_flags = split(";", $flags);
> + push @$cpuFlags, @vm_specific_flags;
>   }
>  }
>  
> @@ -3649,6 +3651,28 @@ sub get_cpu_options {
>  
>  push @$cpuFlags, 'kvm=off' if $kvm_off;
>  
> +if (defined($custom_cpu_config) && defined($custom_cpu_config->{flags})) 
> {
> + my @custom_flags = split(/;/, $custom_cpu_config->{flags});
> + foreach my $flag (@custom_flags) {
> + # find index of $flag in $cpuFlags while ignoring prefix [+-=]
> + $flag =~ m/^[+-=]?(.*)$/;
> + my $match_flag = $1;
> + my @match_index = grep { $cpuFlags->[$_] =~ m/[+-=]?\Q$match_flag/ }
> + 0..scalar(@$cpuFlags)-1;
> +
> + if (@match_index) {
> + my $other_flag = $cpuFlags->[$match_index[0]];
> + # warn only if prefix differs and flag is not vm specific
> + warn "warning: custom CPU model flag '$flag' overruled by 
> '$other_flag' due to either default handling of basemodel or selected OS.\n"

I don't understand that message, so probably users won't either ;) but I 
think the messages would be more clear if we apply the auto-generated 
flags last:

"unsetting flag '$other_flag', not compatible with " (OS foo, CPU bar, 
...)
"not setting flag '$flag', explicit '$other_flag' found." (explicit 
opt-out for auto-generated flags via VM or CPU model config)

> + if (substr $other_flag, 0, 1) ne (substr $flag, 0, 1) &&
> + (!@vm_specific_flags ||
> + !grep(m/[+-=]?\Q$match_flag/, @vm_specific_flags));
> + } else {
> + push(@$cpuFlags, $flag);
> + }
> + }
> +}
> +
>  if (defined($custom_cpu_config) && (my $custom_vendor = 
> $custom_cpu_config->{vendor})) {
>   push @$cpuFlags, "vendor=${custom_vendor}"
>   if $custom_vendor ne 'default';
> -- 
> 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


Re: [pve-devel] [PATCH qemu-server 5/7] Support custom CPU types in get_cpu_options

2019-09-09 Thread Fabian Grünbichler
On September 2, 2019 4:27 pm, Stefan Reiter wrote:
> Supports custom basemodels (model shown to QEMU, i.e. must be a default

nit: s/shown/known/ ?

high-level: if we allow basing custom models on other custom models, 
wouldn't we need to compute an effective model first, and then use that?

e.g., if I define the following:

cpu-model: leaf
  basemodel: intermediate
  vendor: intel
  flags: +aes,+pcid
  host-phys-bits: 1

cpu-model: intermediate1
  vendor: amd
  basemodel: intermediate2
  flags: -aes;-ssbd
  phys-bits: 32

cpu-model: intermediate2
  vendor: amd
  basemodel: phenom
  flags: +ssbd;+md-clear
  phys-bits: 48

I'd expect the end result to be:

vendor: intel
flags: phenom +aes +pcid -ssbd +md-clear
phys-bits: host (overriding the one from intermediate)

(ignore that those flags don't make much sense ;))

this patch (series) only looks at the leaf and the last basemodel in the 
chain, and ignores everything inbetween. vendor also can't be 
'inherited' from basemodel, because it is always set.

we can either go full-blown 'inherit properties across multiple 
basemodels', or we limit ourselves to 'basemodel must be a regular cpu 
model'. the former is of course more flexible (allowing stuff like 
re-using a custom model and just adding one flag, without duplication), 
but the latter is a lot more simple (one additional level to check 
instead of recursive walk, loop and conflict detection, no nested 
versioning needed, etc.pp.). something inbetween like the current patch 
does is probably confusing.

> model), vendors and (host-)phys-bits for VMs with large amounts of RAM
> (see bug #2318).
> 
> Signed-off-by: Stefan Reiter 
> ---
>  PVE/QemuServer.pm | 32 +++-
>  1 file changed, 31 insertions(+), 1 deletion(-)
> 
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 97fa955..417bea8 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -37,6 +37,7 @@ use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr);
>  use PVE::QemuServer::Memory;
>  use PVE::QemuServer::USB qw(parse_usb_device);
>  use PVE::QemuServer::Cloudinit;
> +use PVE::QemuServer::CustomCPUConfig;
>  use PVE::SysFSTools;
>  use PVE::Systemd;
>  use Time::HiRes qw(gettimeofday);
> @@ -3595,10 +3596,30 @@ sub get_cpu_options {
>   $cpu = 'cortex-a57';
>  }
>  my $hv_vendor_id;
> +my $custom_cpu_config;
>  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};
> +
> + if (!defined($cpu_vendor_list->{$cpu})) {
> + # not a default CPU model, read config and see if $cpu is name of
> + # a custom model
> + my $cpu_models = 
> PVE::QemuServer::CustomCPUConfig::config_from_file();
> + if ($cpu_models && ($custom_cpu_config = 
> $cpu_models->get_model_by_name($cpu))) {
> + $cpu = $custom_cpu_config->{basemodel};
> +
> + # 'basemodel' could be custom as well
> + while (!defined($cpu_vendor_list->{$cpu})) {
> + my $custom_base = $cpu_models->get_model_by_name($cpu);
> + die "unknown CPU basemodel: $cpu\n" if !$custom_base;
> + $cpu = $custom_base->{basemodel};
> + }

possible endless loop

> + } else {
> + die "unknown CPU model (neither default nor custom): $cpu\n";
> + }
> + }
> +
>   $kvm_off = 1 if $cpuconf->{hidden};
>   $hv_vendor_id = $cpuconf->{'hv-vendor-id'};
>  
> @@ -3628,13 +3649,22 @@ sub get_cpu_options {
>  
>  push @$cpuFlags, 'kvm=off' if $kvm_off;
>  
> -if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
> +if (defined($custom_cpu_config) && (my $custom_vendor = 
> $custom_cpu_config->{vendor})) {
> + push @$cpuFlags, "vendor=${custom_vendor}"
> + if $custom_vendor ne 'default';
> +} elsif (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
>   push @$cpuFlags, "vendor=${cpu_vendor}"
>   if $cpu_vendor ne 'default';
>  } elsif ($arch ne 'aarch64') {
>   die "internal error"; # should not happen
>  }
>  
> +$cpu .= ",host-phys-bits=true"
> + if defined($custom_cpu_config) && 
> $custom_cpu_config->{'host-phys-bits'};
> +$cpu .= ",phys-bits=$custom_cpu_config->{'phys-bits'}"
> + if defined($custom_cpu_config) && $custom_cpu_config->{'phys-bits'}
> + && !$custom_cpu_config->{'host-phys-bits'};
> +
>  $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
>  
>  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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH qemu-server 7/7] Allow custom CPU types in API

2019-09-09 Thread Fabian Grünbichler
On September 2, 2019 4:27 pm, Stefan Reiter wrote:
> Custom CPU types can be specified via the API, but to prevent arbitrary
> ones we have to manually check if the given model exists (as default or
> custom).
> 
> Signed-off-by: Stefan Reiter 
> ---
>  PVE/QemuServer.pm | 31 +--
>  1 file changed, 29 insertions(+), 2 deletions(-)
> 
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 7cc1674..5bdd729 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -187,7 +187,8 @@ my $cpu_fmt = {
>  cputype => {
>   description => "Emulated CPU type.",
>   type => 'string',
> - enum => [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
> + format_description => 'string',
> + pattern => qr/[0-9a-zA-Z\-_]+/,

this removes information from our API schema dumps (e.g., API viewer, 
'man qm', ...). we could at least put it into format_description with 
some additional sentence referencing custom types)

>   default => 'kvm64',
>   default_key => 1,
>  },
> @@ -215,6 +216,32 @@ my $cpu_fmt = {
>  },
>  };
>  
> +# we need to verify the "cpu" property of the VM config manually, since a
> +# syntactially valid, but non-existant CPU model might be given
> +PVE::JSONSchema::register_format('pve-cpu-conf', \&verify_cpu);
> +sub verify_cpu {
> +my ($cpu, $noerr) = @_;
> +
> +my $conf;
> +eval {
> + $conf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cpu);
> +};
> +if ($@) {
> + die $@ if !$noerr;
> + return undef;
> +}
> +
> +my $cputype = $conf->{cputype};
> +
> +return $cpu if defined($cpu_vendor_list->{$cputype});
> +
> +my $cpu_models = PVE::QemuServer::CustomCPUConfig::config_from_file();
> +return $cpu if $cpu_models && $cpu_models->get_model_by_name($cputype);

and here I just realized something that affects the whole patch series - 
we probably need to namespace the custom cpu models somehow when 
referencing them in the config. otherwise a future QEMU version might 
add an additional CPU model that conflicts with a defined custom one.

we can either add a flag to 'cpu', just prefix the names in the VM 
config, or prefix the names both in the VM config and in the CPU model 
config. all approaches have pros and cons - maybe there is some other 
clever way to avoid this problem?

> +
> +die "cputype '$cputype' not found\n" if !$noerr;
> +return undef;
> +}
> +
>  my $watchdog_fmt = {
>  model => {
>   default_key => 1,
> @@ -587,7 +614,7 @@ EODESCR
>   optional => 1,
>   description => "Emulated CPU type.",
>   type => 'string',
> - format => $cpu_fmt,
> + format => 'pve-cpu-conf',
>  },
>  parent => get_standard_option('pve-snapshot-name', {
>   optional => 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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH 0/7] Add basics for custom CPU models

2019-09-09 Thread Fabian Grünbichler
On September 2, 2019 4:27 pm, Stefan Reiter wrote:
> 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.
> 
> [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
> basemodel kvm64

some more detailed feedback on individual patches, here a summary of open
questions from my side:
- nested models, or just custom models derived from qemu-provided base model
- namespacing of custom models? where, how, ...?
- versioning/live-migration

and some things for the 'future' part:
- permissions? who can create a custom model?
- is there a security risk associated with any of the flags (besides 
  making the VM itself easier to attack)? do we want to have some global 
  whitelist of flags that we have closely looked at and deemed 
  unproblematic?
- do we want to make the whole CRUD of models root/admin only (probably 
  need to, unless we want to create permission paths for CPU models?)

I like the direction this is going, although a lot of the magic will be 
in how to make it straight-forward to generate a new model using the 
available information, which is not yet part of this series ;)

> 
> 
> qemu: Stefan Reiter (1):
>   Trigger pve-api-updates on update
> 
>  debian/triggers | 1 +
>  1 file changed, 1 insertion(+)
>  create mode 100644 debian/triggers
> 
> manager: Stefan Reiter (1):
>   Broadcast supported CPU flags
> 
>  PVE/Service/pvestatd.pm | 28 ++--
>  1 file changed, 26 insertions(+), 2 deletions(-)
> 
> qemu-server: Stefan Reiter (5):
>   Add QEMU CPU flag querying helpers
>   Add CustomCPUConfig for storing/parsing custom CPU models
>   Support custom CPU types in get_cpu_options
>   Handle CPU flags defined in custom CPU type
>   Allow custom CPU types in API
> 
>  PVE/QemuServer.pm | 173 +-
>  PVE/QemuServer/CustomCPUConfig.pm | 129 ++
>  PVE/QemuServer/Makefile   |   1 +
>  3 files changed, 299 insertions(+), 4 deletions(-)
>  create mode 100644 PVE/QemuServer/CustomCPUConfig.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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH qemu-server 3/7] Add QEMU CPU flag querying helpers

2019-09-09 Thread Fabian Grünbichler
On September 9, 2019 2:56 pm, Stefan Reiter wrote:
> On 9/6/19 1:42 PM, Fabian Grünbichler wrote:
>>> +# this is neither the default for 'query_supported_cpu_flags' below, nor 
>>> for
>>> +# /proc/cpuinfo.
>>> +#
>>> +# To compare (or array_intersect) flags, it's a good idea to convert them 
>>> all
>>> +# to a common format first (e.g. map s/\.|-/_/g).
>>> +sub query_understood_cpu_flags {
>> 
>> not used anywhere in this series? also, confusingly, this returns less
>> values then the other helper (maybe because of some aliases?), and it's
>> not a strict subset :-/
>>
> 
> Yes, this is for exposing via the API (for the GUI to create/edit custom 
> models I have in mind). I just thought it fits with this patch well, 
> since the comments refer to each other.
> 
> Also, query_understood_cpu_flags returns 188 flags for me, while 
> query_supported_cpu_flags only returns 104...

yes, a double check confirms this - seems I had the output files mixed 
up.. sorry for the noise

> 
> The discrepancies generally arise because
> a) query_understood_cpu_flags returns flags the host cannot use and
> b) query_supported_cpu_flags (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.

that makes sense - and would make a good starting point for an 
informative comment ;)

> 
> The intersection of those provides only flags that can be passed to 
> "-cpu" without issues in my testing. Since query_understood_cpu_flags is 
> not host specific though, it doesn't need broadcasting.

___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH container] fix issue where ttys aren't correctly set after restore

2019-09-10 Thread Fabian Grünbichler
NAK, see inline

On September 10, 2019 3:27 pm, Oguz Bektas wrote:
> restore from unpriv to priv causes a problem with the log-in, since the
> /etc/securetty file isn't modified after a restore to reflect the change
> (/dev/lxc/tty1 and so on).
> 
> template_fixup is normally called in post_create_hook, but we have no 
> $password
> or $ssh_keys to call the hook with during restore. instead we call 
> template_fixup by
> itself to fix the ttys on some distributions.
> 
> Signed-off-by: Oguz Bektas 
> ---
>  src/PVE/API2/LXC.pm | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/src/PVE/API2/LXC.pm b/src/PVE/API2/LXC.pm
> index 26c4f88..738556b 100644
> --- a/src/PVE/API2/LXC.pm
> +++ b/src/PVE/API2/LXC.pm
> @@ -413,10 +413,11 @@ __PACKAGE__->register_method({
>   $bwlimit = PVE::Storage::get_bandwidth_limit('restore', 
> [keys %used_storages], $bwlimit);
>   PVE::LXC::Create::restore_archive($archive, $rootdir, 
> $conf, $ignore_unpack_errors, $bwlimit);
>  
> + my $lxc_setup = PVE::LXC::Setup->new($conf, $rootdir); # 
> detect OS

this makes decisions based on $conf (e.g., explicit 'ostype: unmanaged')

>   if ($restore) {
>   PVE::LXC::Create::restore_configuration($vmid, 
> $rootdir, $conf, !$is_root, $unique, $skip_fw_config_restore);

when restoring, the full $conf is only available here.

> + $lxc_setup->template_fixup($conf);
>   } else {
> - my $lxc_setup = PVE::LXC::Setup->new($conf, $rootdir); 
> # detect OS
>   PVE::LXC::Config->write_config($vmid, $conf); # safe 
> config (after OS detection)
>   $lxc_setup->post_create_hook($password, $ssh_keys);
>   }
> -- 
> 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


Re: [pve-devel] [PATCH guest-common 1/2] move pending changes related functions into AbstractConfig

2019-09-11 Thread Fabian Grünbichler
meta: please send v2 together with v2 of pve-container (and future) patches.

On September 4, 2019 6:00 pm, Oguz Bektas wrote:
> some functions from Qemu w.r.t. pending changes can be moved to
> AbstractConfig, in order to make them available for both QemuConfig and
> LXC::Config.
> 
> Signed-off-by: Oguz Bektas 
> ---
>  PVE/AbstractConfig.pm | 79 +++
>  1 file changed, 79 insertions(+)
> 
> diff --git a/PVE/AbstractConfig.pm b/PVE/AbstractConfig.pm
> index e0d0f10..18522b9 100644
> --- a/PVE/AbstractConfig.pm
> +++ b/PVE/AbstractConfig.pm
> @@ -68,6 +68,85 @@ sub write_config {
>  PVE::Cluster::cfs_write_file($cfspath, $conf);
>  }
>  
> +## Pending changes related
> +
> +sub split_flagged_list {
> +my ($class, $text) = @_;
> +$text ||= '';
> +$text =~ s/[,;]/ /g;
> +$text =~ s/^\s+//;
> +return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
> +}
> +
> +sub join_flagged_list {
> +my ($class, $how, $lst) = @_;
> +join $how, map { $lst->{$_} . $_ } keys %$lst;
> +}

these two are really only used for the pending delete hash, so instead 
of just moving them with this strange naming scheme, why not simplify 
and rename them to

parse_pending_delete($class, $raw)
print_pending_delete($class, $pending_delete_hash)

we need versioned breaks/depends anyway.. while we are at it, instead of 
$hash->{foo} being either '!' or '' (which is just how the $force 
property is encoded in the 'flagged list', but not a good representation 
in a perl hash), it would be nicer to have
$hash->{foo}->{force} being 0/1 IMHO.

> +
> +sub vmconfig_delete_pending_option {
> +my ($class, $conf, $key, $force) = @_;
> +
> +delete $conf->{pending}->{$key};
> +my $pending_delete_hash = 
> $class->split_flagged_list($conf->{pending}->{delete});
> +$pending_delete_hash->{$key} = $force ? '!' : '';
> +$conf->{pending}->{delete} = $class->join_flagged_list(',', 
> $pending_delete_hash);
> +}
> +
> +sub vmconfig_undelete_pending_option {
> +my ($class, $conf, $key) = @_;
> +
> +my $pending_delete_hash = 
> $class->split_flagged_list($conf->{pending}->{delete});
> +delete $pending_delete_hash->{$key};
> +
> +if (%$pending_delete_hash) {
> + $conf->{pending}->{delete} = $class->join_flagged_list(',', 
> $pending_delete_hash);
> +} else {
> + delete $conf->{pending}->{delete};
> +}
> +}

ugh, those two are also not very well named. not your fault, but IMHO 
also an opportunity to think about a better name if we refactor this. 
there are only 9 existing callers after all..

they don't delete or undelete a pending option (whatever that would 
actually do ;)), they queue an option for deletion via the pending 
delete hash/list..

add_to_pending_delete
remove_from_pending_delete

? better proposals welcome, like always ;)

> +
> +sub vmconfig_cleanup_pending {

I'd drop the 'vmconfig_' from the name here

> +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->split_flagged_list($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->join_flagged_list(',', 
> $pending_delete_hash);
> +} else {
> + delete $conf->{pending}->{delete};
> +}
> +
> +return $changes;
> +}
> +
> +sub vmconfig_hotplug_pending {

same - although I am not sure whether I'd not opt for this sub to stay 
in QemuServer.pm altogether

the interdependency between QemuServer and QemuConfig is already way too 
messy for my taste, and moving this more than doubles the calls from 
QemuConfig to QemuServer:

old:
QemuServer->QemuConfig: 70 (these are fine!)
QemuConfig->QemuServer: 29 (these are only there because we did not want 
to move 60% of QemuServer.pm including the $confdesc to QemuConfig)

new:
QemuServer->QemuConfig: 59 (-11)
QemuConfig->QemuServer: 69 (+40)

the -11 are actually all load/write_config..

moving this sub also adds another module dependency cycle:

QemuServer->QemuConfig->QemuServer::CloudInit->QemuServer

> +my ($class, $vmid, $conf, $storecfg, $selection, $errors) = @_;
> +die "implement me - abstract method\n";
> +}
> +
> +sub vmconfig_apply_pending {

same (name if moved, but maybe not move at all?)

> +my ($class, $vmid, $conf, $storecfg) = @_;
> +die "implement me - abstract method\n";
> +}
> +
> +
>  # Lock config file using flock, run $code with @param, unlock conf

Re: [pve-devel] [PATCH container 2/9] adapt config GET call for taking pending changes

2019-09-11 Thread Fabian Grünbichler
On September 5, 2019 4:11 pm, Oguz Bektas wrote:
> the default behaviour is the same as in Qemu, so without the 'current'
> flag set, current values will be replaced with their respective pending
> counterparts.
> 
> Signed-off-by: Oguz Bektas 
> ---
>  src/PVE/API2/LXC/Config.pm | 23 +++
>  1 file changed, 23 insertions(+)
> 
> diff --git a/src/PVE/API2/LXC/Config.pm b/src/PVE/API2/LXC/Config.pm
> index 769fc3b..6e67186 100644
> --- a/src/PVE/API2/LXC/Config.pm
> +++ b/src/PVE/API2/LXC/Config.pm
> @@ -53,6 +53,12 @@ __PACKAGE__->register_method({
>   items => { type => 'array', items => { type => 'string' }},
>   optional => 1,
>   },
> + current => {
> + description => "Get current values (instead of pending 
> values).",
> + optional => 1,
> + default => 0,
> + type => 'boolean',
> + },

did you test this? the new parameter is in the return property instead 
of the parameters property..

>   digest => {
>   type => 'string',
>   description => 'SHA1 digest of configuration file. This can be 
> used to prevent concurrent modifications.',
> @@ -73,11 +79,28 @@ __PACKAGE__->register_method({
>   $conf = $snapshot;
>   }
>  
> + # take pending changes in
> + 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::LXC::Config->split_flagged_list($conf->{pending}->{delete});
> + foreach my $opt (keys %$pending_delete_hash) {
> + delete $conf->{$opt} if $conf->{$opt};
> + }
> + }
> +
> +
>   delete $conf->{snapshots};
> + delete $conf->{pending};

the whole thing is now identical (modulo comments and line ordering) to 
the same Qemu API path, except that Qemu also masks the 'cipassword' 
option if it is set.

we could instead move the whole 'delete snapshots, conditionally apply 
or delete pending changes' into a new AbstractConfig method 
(e.g., load_current_config($apply_pending)), or add two parameters to 
load_config to get this reduced config instead of the full one.

diff --git a/config_ct b/config_vm
index 04dbfe6..7372ba3 100644
--- a/config_ct
+++ b/config_vm
@@ -1,18 +1,19 @@
 code => sub {
my ($param) = @_;
 
-   my $conf = PVE::LXC::Config->load_config($param->{vmid});
+   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);
 
-   # we need the digest of the file
-   $snapshot->{digest} = $conf->{digest};
+   $snapshot->{digest} = $conf->{digest}; # keep file digest for API
+
$conf = $snapshot;
}
 
-   # take pending changes in
+   delete $conf->{snapshots};
+
if (!$param->{current}) {
foreach my $opt (keys %{$conf->{pending}}) {
next if $opt eq 'delete';
@@ -20,15 +21,18 @@
next if ref($value); # just to be sure
$conf->{$opt} = $value;
}
-   my $pending_delete_hash = 
PVE::LXC::Config->split_flagged_list($conf->{pending}->{delete});
+   my $pending_delete_hash = 
PVE::QemuConfig->split_flagged_list($conf->{pending}->{delete});
foreach my $opt (keys %$pending_delete_hash) {
delete $conf->{$opt} if $conf->{$opt};
}
}
 
-
-   delete $conf->{snapshots};
delete $conf->{pending};
 
+   # hide cloudinit password
+   if ($conf->{cipassword}) {
+   $conf->{cipassword} = '**';
+   }
+
return $conf;
 }});

>  
>   return $conf;
>  }});
>  
> +
>  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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH container 1/9] add pending section to lxc config parser/writer

2019-09-11 Thread Fabian Grünbichler
NAK, this breaks existing configs with a snapshot called pending (which 
is an allowed snapshot name, and not such an uncommon word that we can 
confidently say that noone would be affected). we could do _PENDING_ or 
__PENDING__ (similar to what we do with __base__ and __replicate__ and 
__migration__ storage snapshots).

in general, this would align the VM and CT config parser/writer pairs 
more closely, so it's a step in the right direction.

On September 5, 2019 4:11 pm, Oguz Bektas wrote:
> allow parsing and writing of the pending changes section in CTID.conf
> files.
> 
> Signed-off-by: Oguz Bektas 
> ---
>  src/PVE/LXC/Config.pm | 35 ++-
>  1 file changed, 30 insertions(+), 5 deletions(-)
> 
> diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm
> index 9790345..08b958f 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,13 @@ 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/^\[PENDING\]\s*$/i) {
> + $section = 'pending';
> + $conf->{description} = $descr if $descr;
> + $descr = '';
> + $conf = $res->{$section} = {};
> + next;
> + } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
>   $section = $1;
>   $conf->{description} = $descr if $descr;
>   $descr = '';
> @@ -794,6 +801,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 
> [PENDING]\n";

you copied this without the typo, but did not fix it in the original ;)

> + }
>   } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(\S.*)\s*$/) {
>   my $key = $1;
>   my $value = $2;
> @@ -832,14 +846,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 +883,13 @@ sub write_pct_config {
>  
>  my $raw = &$generate_raw_config($conf);
>  
> +if (scalar(keys %{$conf->{pending}})){
> + $raw .= "\n[PENDING]\n";
> + $raw .= &$generate_raw_config($conf->{pending}, 1);
> +}
> +
>  foreach my $snapname (sort keys %{$conf->{snapshots}}) {
> + die "internal error" if $snapname eq 'pending';
>   $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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH container 3/9] adapt config PUT to use 'revert' and 'force' parameters

2019-09-11 Thread Fabian Grünbichler
the commit message is misleading - this just adds two parameters, but no 
code that handles them? the code/change that adds handling only comes in 
patch #8. either merge these two, or put this one after the other 
please.

On September 5, 2019 4:11 pm, Oguz Bektas wrote:
> Signed-off-by: Oguz Bektas 
> ---
>  src/PVE/API2/LXC/Config.pm | 13 +
>  1 file changed, 13 insertions(+)
> 
> diff --git a/src/PVE/API2/LXC/Config.pm b/src/PVE/API2/LXC/Config.pm
> index 6e67186..405a079 100644
> --- a/src/PVE/API2/LXC/Config.pm
> +++ b/src/PVE/API2/LXC/Config.pm
> @@ -20,6 +20,8 @@ use PVE::JSONSchema qw(get_standard_option);
>  
>  use base qw(PVE::RESTHandler);
>  
> +my $opt_force_description = "Force physical removal. Without this, we simply 
> remove the disk from the config file and create an additional configuration 
> entry called 'unused[n]', which contains the volume ID. Unlink of unused[n] 
> always results in physical removal.";
> +
>  __PACKAGE__->register_method({
>  name => 'vm_config',
>  path => '',
> @@ -131,6 +133,17 @@ __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,
> + },
> + force => {
> + type => 'boolean',
> + description => $opt_force_description,
> + optional => 1,
> + requires => 'delete',
> + },
>   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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH container 5/9] add 'pending' API method to LXC

2019-09-11 Thread Fabian Grünbichler
On September 5, 2019 4:11 pm, Oguz Bektas wrote:
> analog to Qemu, it returns an array of elements, which shows the
> current value, pending value, and delete requests.

and again, this is completely identical to the Qemu API path (modulo 
comments, one superfluous next statement) except for the cipassword 
handling.

we could just move this into AbstractConfig, and let Qemu cleanup the 
cipassword after calling the shared code.

> 
> 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 9ddaf58..b885e90 100644
> --- a/src/PVE/API2/LXC.pm
> +++ b/src/PVE/API2/LXC.pm
> @@ -513,6 +513,7 @@ __PACKAGE__->register_method({
>  
>   my $res = [
>   { subdir => 'config' },
> + { subdir => 'pending' },
>   { subdir => 'status' },
>   { subdir => 'vncproxy' },
>   { subdir => 'termproxy' },
> @@ -1863,4 +1864,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. " .
> + "The value 2 indicates a force-delete request.",
> + type => 'integer',
> + minimum => 0,
> + maximum => 2,
> + optional => 1,
> + },
> + },
> + },
> +},
> +code => sub {
> + my ($param) = @_;
> +
> + my $conf = PVE::LXC::Config->load_config($param->{vmid});
> +
> + my $pending_delete_hash = 
> PVE::LXC::Config->split_flagged_list($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;
> + }
> +
> + while (my ($opt, $force) = each %$pending_delete_hash) {
> + next if $conf->{pending}->{$opt};
> + next if $conf->{$opt};
> + my $item = { key => $opt, delete => ($force ? 2 : 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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH container 6/9] add 'pct pending' command

2019-09-11 Thread Fabian Grünbichler
On September 5, 2019 4:11 pm, Oguz Bektas wrote:
> analog to 'qm pending', it shows a list of keys and values defined in
> configuration.

copied verbatim from qm.pm, maybe we could move this code to 
GuestHelpers.pm (format_pending)?

> 
> cur: current change
> new: pending change
> del: pending delete
> 
> Signed-off-by: Oguz Bektas 
> ---
>  src/PVE/CLI/pct.pm | 27 +++
>  1 file changed, 27 insertions(+)
> 
> diff --git a/src/PVE/CLI/pct.pm b/src/PVE/CLI/pct.pm
> index 35ad72f..78cb406 100755
> --- a/src/PVE/CLI/pct.pm
> +++ b/src/PVE/CLI/pct.pm
> @@ -821,6 +821,33 @@ our $cmddef = {
>   }
>   }
>   }],
> +
> +pending => [ "PVE::API2::LXC", "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";
> + }
> + }
> + }],
>  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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH container 7/9] add vmconfig_hotplug_pending and vmconfig_apply_pending

2019-09-11 Thread Fabian Grünbichler
On September 5, 2019 4:11 pm, Oguz Bektas wrote:
> vmconfig_hotplug_pending is responsible for checking if a key in the
> pending section is hotpluggable, if yes; perform a generic config value
> replace or perform specific actions if a special case.
> 
> vmconfig_apply_pending is only supposed to be called when ct isn't live.
> 
> Signed-off-by: Oguz Bektas 
> ---
>  src/PVE/LXC/Config.pm | 186 +-
>  1 file changed, 184 insertions(+), 2 deletions(-)
> 
> diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm
> index 08b958f..26c694f 100644
> --- a/src/PVE/LXC/Config.pm
> +++ b/src/PVE/LXC/Config.pm
> @@ -7,11 +7,13 @@ use PVE::AbstractConfig;
>  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);
>  
> +my $confdesc;

see other comment - I'd prefer not making vmconfig_hotplug_pending and 
vmconfig_apply_pending methods in AbstractConfig, which means they can 
be moved below the existing $confdesc.

>  my $nodename = PVE::INotify::nodename();
>  my $lock_handles =  {};
>  my $lockdir = "/run/lock/lxc";
> @@ -76,6 +78,186 @@ sub has_feature {
>  return $err ? 0 : 1;
>  }
>  
> +my $LXC_FASTPLUG_OPTIONS= {
> +'description' => 1,
> +'onboot' => 1,
> +'startup' => 1,
> +'protection' => 1,
> +'hostname' => 1,

hostname is reflected inside the container though? you'd need a trip 
through Setup.pm or something to actually hotplug it..

> +'hookscript' => 1,
> +'cores' => 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
> +if ($LXC_FASTPLUG_OPTIONS->{$opt}) {
> +$conf->{$opt} = delete $conf->{pending}->{$opt};
> +$changes = 1;
> +}

ignores $selection?

> +}
> +
> +if ($changes) {
> + $class->write_config($vmid, $conf);
> +$conf = $class->load_config($vmid); # update/reload

should not be needed, this needs to be called while holding an flock 
anyway..

> +}
> +
> +my $pending_delete_hash = 
> $class->split_flagged_list($conf->{pending}->{delete});
> +while (my ($opt, $force) = each %$pending_delete_hash) {
> + next if $selection && !$selection->{$opt};
> + eval {
> + if ($LXC_FASTPLUG_OPTIONS->{$opt}) {
> + # pass
> + } elsif ($opt eq 'swap') { # TODO FIXME: unlimited swap instead of 
> no swap

wouldn't this just be able to re-use the hotplug_memory code from below?

> + PVE::LXC::write_cgroup_value("memory", $vmid,
> +  "memory.memsw.limit_in_bytes", -1);
> + } elsif ($opt eq 'cpulimit') {
> + PVE::LXC::write_cgroup_value("cpu", $vmid, "cpu.cfs_quota_us", 
> -1);
> + } elsif ($opt eq 'cpuunits') {
> + PVE::LXC::write_cgroup_value("cpu", $vmid, "cpu.shared", 
> $confdesc->{cpuunits}->{default});
> + } elsif ($opt =~ m/^net(\d)$/) {
> + my $netid = $1;
> + PVE::Network::veth_delete("veth${vmid}i$netid");
> + } else {
> + die "skip\n"; # skip non-hotpluggable opts
> + }
> + };
> + if (my $err = $@) {
> + $add_error->($opt, $err) if $err ne "skip\n";
> + } else {
> + delete $conf->{$opt};
> + $class->vmconfig_undelete_pending_option($conf, $opt);
> + $class->write_config($vmid, $conf);
> + $conf = $class->load_config($vmid); # update/reload

reload shouldn't be needed

> + }
> +}
> +
> +# 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} || 512);
> + my $old_swap = ($conf->{swap} || 0);

$confdesc says swap also defaults to 512? which one is wrong?

why not use the defaults here, instead of hard-coding them?

> +
> + $wanted_memory //= $old_memory;
> + $wanted_swap //= $old_swap;
> +
> + my $total = $wanted_memory + $wanted_swap;
> + my $old_total = $old_memory + $old_swap;
> +
> +

superfluous blank line

> + if ($total > $old_total) {

does this fail if the order is wrong? if so, wouldn't it be better to 
read the current value instead of guessing it based on $conf? still 
racy, but that can probably not be avoided..

> + PVE::LXC::write_cgroup_

Re: [pve-devel] [PATCH container 9/9] apply pending changes when container is started

2019-09-11 Thread Fabian Grünbichler
On September 5, 2019 4:11 pm, Oguz Bektas wrote:
> 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..9dd5bc9 100644
> --- a/src/PVE/LXC.pm
> +++ b/src/PVE/LXC.pm
> @@ -1939,6 +1939,13 @@ sub vm_start {
>   close($fh);
>  }
>  
> +# 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
> +}
> +

this should probably happen before the call to update_lxc_config a few 
lines above..

>  my $cmd = ['systemctl', 'start', "pve-container\@$vmid"];
>  
>  PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start', 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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH container 0/9] lxc pending changes

2019-09-11 Thread Fabian Grünbichler
On September 5, 2019 4:11 pm, Oguz Bektas wrote:
> this series makes it possible to add/revert/delete pending changes in
> the backend.
> 
> it depends on my previous patch for pve-guest-common, for enabling
> inheritance of pending changes related methods into PVE::LXC::Config

thanks for these patches! this functionality is a long-time overdue..

detailed comments/questions on individual patches (it's a lot, but I am 
also on vacation next week so you have plenty of time to prepare a v2 ;)).

the big picture already looks mostly good (there are some refactoring 
choices that I would do differently), but with such functionality the 
devil is always in the details/edge cases.

please test your v2 thoroughly, in particular regarding

- mountpoint handling
- backup/restore
- custom lxc.foo options
- clones
- migration
- various ways to restart containers (from within, stop/start, 
  systemctl, ..)

also, please think about which parts can be unit-tested and write tests for 
them!

if you find stuff about the interface or semantics from Qemu that is 
sub-optimal / unclear, don't just copy it, but try to understand and 
improve it.. duplicate or very similar code is already bad enough, 
two or three forks of BAD code is even worse ;) I haven't checked for 
everything whether particular lines are originally from you, or based on 
qemu-server - some / a lot of my comments might apply to qemu-server's 
implementation as well..

> 
> some notes or to-be-fixed-soon-after-review points:
> [1]. gui patches are coming soon
> [2]. right now pending changes are applied __only__ at vm_start.
> [3]. --delete $opt --force is not implemented (is in schema, but has no 
> effect atm)

unless you plan to implement this in this series, I'd drop it from the 
schema/API at least.

> [4]. clones will __keep__ pending changes in config (for now)
> [5]. there are a couple TODO/FIXME's inside, since they were extra
> features or unrelated bugs (which i think should be fixed in separate
> commits later since they don't directly affect pending changes functionality)

for small, well-understood stuff it often makes sense to fix it in 
separate commits up front. who knows when the next person takes a 
closer look at that particular code - a fix done now is done, a FIXME 
added now might be ignored forever.

> 
> comments:
> 
> [2]: i thought it was best to keep it like this for the first version,
> until we decide what's the best way to go about it.
> 
> [3]: it seemed quite tricky to implement live force-delete of mounpoints
> because of a few reasons, like unmount not being allowed or mp being on
> network storage etc.
> 
> [4]: will fix this in v2 after the first review
> 
> [5]: one bug, where if swap option is deleted while ct is running,
> memory.memsw.limit_in_bytes is set to infinite instead of zero. the
> other one is the --force implementation.

backup is also missing pending changes skipping. some more stuff in the 
review itself..

> Oguz Bektas (9):
>   add pending section to lxc config parser/writer
>   adapt config GET call for taking pending changes
>   adapt config PUT to use 'revert' and 'force' parameters
>   remove trailing whitespace
>   add 'pending' API method to LXC
>   add 'pct pending' command
>   add vmconfig_hotplug_pending and vmconfig_apply_pending
>   rework update_pct_config to write and apply pending changes
>   apply pending changes when container is started
> 
>  src/PVE/API2/LXC.pm|  90 +-
>  src/PVE/API2/LXC/Config.pm |  88 +++---
>  src/PVE/CLI/pct.pm |  27 ++
>  src/PVE/LXC.pm |   7 +
>  src/PVE/LXC/Config.pm  | 549 -
>  5 files changed, 520 insertions(+), 241 deletions(-)
> 
> -- 
> 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


Re: [pve-devel] [PATCH container 8/9] rework update_pct_config to write and apply pending changes

2019-09-11 Thread Fabian Grünbichler
On September 5, 2019 4:11 pm, Oguz Bektas wrote:
> use vmconfig_hotplug_pending (when ct up) and vmconfig_apply_pending
> (when ct down) to apply or write pending changes.
> 
> Signed-off-by: Oguz Bektas 
> ---
>  src/PVE/API2/LXC/Config.pm |  52 +-
>  src/PVE/LXC/Config.pm  | 328 +
>  2 files changed, 147 insertions(+), 233 deletions(-)
> 
> diff --git a/src/PVE/API2/LXC/Config.pm b/src/PVE/API2/LXC/Config.pm
> index 405a079..a31ddd5 100644
> --- a/src/PVE/API2/LXC/Config.pm
> +++ b/src/PVE/API2/LXC/Config.pm
> @@ -156,58 +156,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);
> @@ -217,10 +169,8 @@ __PACKAGE__->register_method({
>  
>   my $running = PVE::LXC::check_running($vmid);
>  
> - PVE::LXC::Config->update_pct_config($vmid, $conf, $running, $param, 
> \@delete);
> + PVE::LXC::Config->update_pct_config($vmid, $conf, $running, $param);
>  
> - PVE::LXC::Config->write_config($vmid, $conf);
> - PVE::LXC::update_lxc_config($vmid, $conf);

this call to update_lxc_config gets dropped without any comment - is it 
not longer needed? was the removal accidental?

>   };
>  
>   PVE::LXC::Config->lock_config($vmid, $code);
> diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm
> index 26c694f..6bec9b7 100644
> --- a/src/PVE/LXC/Config.pm
> +++ b/src/PVE/LXC/Config.pm
> @@ -1080,129 +1080,132 @@ 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();

missing use statement for PVE::RPCEnvironment

> +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 = {};

why this completely different handling of revert and delete?

> +my $force = extract_param($param, 'force');
>  
> -my $rootdir;
> -if ($running) {
> - my $pid = PVE::LXC::find_lxc_pid($vmid);
> - $rootdir = "/proc/$pid/root";
> +die "no options specified\n" if !$delete_str && !$revert_str && 
> !scalar(keys %$param);

this also gets called for container creation/restore, which triggers 
this die in case of an in-place restore.

> +
> +PVE::LXC::check_ct_

Re: [pve-devel] [PATCH container 1/9] add pending section to lxc config parser/writer

2019-09-12 Thread Fabian Grünbichler
On September 11, 2019 2:02 pm, Thomas Lamprecht wrote:
> On 11.09.19 09:39, Fabian Grünbichler wrote:
>> NAK, this breaks existing configs with a snapshot called pending (which 
>> is an allowed snapshot name, and not such an uncommon word that we can 
>> confidently say that noone would be affected). we could do _PENDING_ or 
> 
> naming it pending for VMs was possible and broke things in obvious ways,
> nevertheless we never had a single report about it, AFAICT, even after
> pending being released ~4.5 years ago. So while yes, the chance is there
> I'd guess that's highly unlikely - not that that really helps us.
> 
>> __PENDING__ (similar to what we do with __base__ and __replicate__ and 
>> __migration__ storage snapshots).
> 
> confuses things more, IMO, the other two are special snapshots, this is
> completely something different, so mixing those two into having a similar
> syntax may make people think that "__PENDING__" is a pending snapshot.
> 
> IMO, the snapshots should have been prefixed with a marker from the
> beginning, but as the time machine isn't there yet and retro actively
> re-writing snapshot sections as "[snap:]" or the like isn't a to
> easy task, I'd maybe rather add a prefix for non-snapshot sections with
> a snapshot incompatible syntax. [_special:PENDING] or the like.
> 
> Another possible way could be to really to the 
> [snap:] for snapshots, rewriting old ones once the config is written
> out for other changes anyway, and for names where we are not sure like
> "pending" check if's there's a "snaptime" property in the section?
> As else it cannot be a valid snapshot made through the API.

we had a bit of offline discussion yesterday about this, IMHO 
namespacing the sections would be the best way to go forward.

either special: or pve: for stuff like 'pending', snap: or snapshot: for 
snapshots. since we don't allow ':' in section names currently, this 
could be done fairly backwards-compatible (plain 'pending' would be 
handled differently for qemu-server and pve-container).. vzdump filters 
both pending and snapshots from the stored config, replication is 
frequent enough, so we don't really have to worry about long-term 
compat, just for one release cycle.. the hash representation can stay 
liek it is, so no big code changes needed either, besides the par 
ser/writer and qemu-server's vzdump (which has its own filtering config 
reader).

___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [PATCH ceph] build: use dgit for download target

2019-09-12 Thread Fabian Grünbichler
since it has all the necessary wrapping to download and verify dscs from
arbitraty repositories, without being affected by the system's APT state
and configuration.

Signed-off-by: Fabian Grünbichler 
---
 Makefile | 13 +++--
 upstream-key.asc | 29 +
 2 files changed, 36 insertions(+), 6 deletions(-)
 create mode 100644 upstream-key.asc

diff --git a/Makefile b/Makefile
index f885c1283..0219426df 100644
--- a/Makefile
+++ b/Makefile
@@ -99,15 +99,16 @@ ${DSC}: ${BUILDSRC}
cd ${BUILDSRC}; dpkg-buildpackage -S -uc -us -d -nc
@echo ${DSC}
 
+# NOTE: always downloads latest version!
 .PHONY: download
 download:
-   # FIXME: better verification (download dsc and use dscverify with 
ceph.com release key?)
-   dget --allow-unauthenticated --download-only 
'https://download.ceph.com/debian-nautilus/pool/main/c/ceph/ceph_${VER}.orig.tar.gz'
rm -rf ${SRCDIR}.tmp ${SRCDIR}
-   mkdir ${SRCDIR}.tmp
-   tar -C ${SRCDIR}.tmp --strip-components=1 -xf ceph_${VER}.orig.tar.gz
-   # needed because boost and zstd builds fail otherwise
-   find ${SRCDIR}.tmp -type f -name ".gitignore" -delete
+   dgit -cdgit-distro.ceph.archive-query=aptget: 
-cdgit-distro.ceph.mirror=http://download.ceph.com/debian-nautilus 
-cdgit-distro.ceph.git-check=false 
--apt-get:--option=Dir::Etc::Trusted=${CURDIR}/upstream-key.asc -d ceph clone 
ceph xenial ./${SRCDIR}.tmp
+   @echo "WARNING"
+   @echo "Check output above for verification errors!"
+   @echo "WARNING"
+   rm -rf ${SRCDIR}.tmp/.git
+   find ${SRCDIR}.tmp/ -type f -name '.gitignore' -delete
mv ${SRCDIR}.tmp/debian/changelog ${SRCDIR}.tmp/changelog.upstream
mv ${SRCDIR}.tmp ${SRCDIR}
 
diff --git a/upstream-key.asc b/upstream-key.asc
new file mode 100644
index 0..d2961c52e
--- /dev/null
+++ b/upstream-key.asc
@@ -0,0 +1,29 @@
+-BEGIN PGP PUBLIC KEY BLOCK-
+Version: GnuPG v1
+
+mQINBFX4hgkBEADLqn6O+UFp+ZuwccNldwvh5PzEwKUPlXKPLjQfXlQRig1flpCH
+E0HJ5wgGlCtYd3Ol9f9+qU24kDNzfbs5bud58BeE7zFaZ4s0JMOMuVm7p8JhsvkU
+C/Lo/7NFh25e4kgJpjvnwua7c2YrA44ggRb1QT19ueOZLK5wCQ1mR+0GdrcHRCLr
+7Sdw1d7aLxMT+5nvqfzsmbDullsWOD6RnMdcqhOxZZvpay8OeuK+yb8FVQ4sOIzB
+FiNi5cNOFFHg+8dZQoDrK3BpwNxYdGHsYIwU9u6DWWqXybBnB9jd2pve9PlzQUbO
+eHEa4Z+jPqxY829f4ldaql7ig8e6BaInTfs2wPnHJ+606g2UH86QUmrVAjVzlLCm
+nqoGymoAPGA4ObHu9X3kO8viMBId9FzooVqR8a9En7ZE0Dm9O7puzXR7A1f5sHoz
+JdYHnr32I+B8iOixhDUtxIY4GA8biGATNaPd8XR2Ca1hPuZRVuIiGG9HDqUEtXhV
+fY5qjTjaThIVKtYgEkWMT+Wet3DPPiWT3ftNOE907e6EWEBCHgsEuuZnAbku1GgD
+LBH4/a/yo9bNvGZKRaTUM/1TXhM5XgVKjd07B4cChgKypAVHvef3HKfCG2U/DkyA
+LjteHt/V807MtSlQyYaXUTGtDCrQPSlMK5TjmqUnDwy6Qdq8dtWN3DtBWQARAQAB
+tCpDZXBoLmNvbSAocmVsZWFzZSBrZXkpIDxzZWN1cml0eUBjZXBoLmNvbT6JAjgE
+EwECACIFAlX4hgkCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEOhKwsBG
+DzmUXdIQAI8YPcZMBWdv489q8CzxlfRIRZ3Gv/G/8CH+EOExcmkVZ89mVHngCdAP
+DOYCl8twWXC1lwJuLDBtkUOHXNuR5+Jcl5zFOUyldq1Hv8u03vjnGT7lLJkJoqpG
+l9QD8nBqRvBU7EM+CU7kP8+09b+088pULil+8x46PwgXkvOQwfVKSOr740Q4J4nm
+/nUOyTNtToYntmt2fAVWDTIuyPpAqA6jcqSOC7Xoz9cYxkVWnYMLBUySXmSS0uxl
+3p+wK0lMG0my/gb+alke5PAQjcE5dtXYzCn+8Lj0uSfCk8Gy0ZOK2oiUjaCGYN6D
+u72qDRFBnR3jaoFqi03bGBIMnglGuAPyBZiI7LJgzuT9xumjKTJW3kN4YJxMNYu1
+FzmIyFZpyvZ7930vB2UpCOiIaRdZiX4Z6ZN2frD3a/vBxBNqiNh/BO+Dex+PDfI4
+TqwF8zlcjt4XZ2teQ8nNMR/D8oiYTUW8hwR4laEmDy7ASxe0p5aijmUApWq5UTsF
++s/QbwugccU0iR5orksM5u9MZH4J/mFGKzOltfGXNLYI6D5Mtwrnyi0BsF5eY0u6
+vkdivtdqrq2DXY+ftuqLOQ7b+t1RctbcMHGPptlxFuN9ufP5TiTWSpfqDwmHCLsT
+k2vFiMwcHdLpQ1IH8ORVRgPPsiBnBOJ/kIiXG2SxPUTjjEGOVgeA
+=/Tod
+-END PGP PUBLIC KEY BLOCK-
-- 
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 container] don't duplicate lxc.idmap entries during restore

2019-09-25 Thread Fabian Grünbichler
On September 24, 2019 4:04 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 
> ---
>  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..4add540 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;

why not $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


Re: [pve-devel] [PATCH v2 container] don't duplicate lxc.idmap entries during restore

2019-09-25 Thread Fabian Grünbichler
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


Re: [pve-devel] libknet1 update don't restart corosync

2019-09-27 Thread Fabian Grünbichler
On September 27, 2019 8:53 am, Alexandre DERUMIER wrote:
> Hi,
> 
> I have noticed that when you upgrade libknet1 (and fix the crash of corosync),
> 
> corosync is not auto restarted.

yes, just like any other library except libc6 in Debian. there is 
tooling to handle this in general ('needrestart' is the most widespread 
one), but they require some tuning to not restart services that need to 
keep running, avoid false positives, etc.pp.

> Maybe should we bump the corosync package too to force a restart ?

would be one possibility. the other would be to add a trigger from knet 
to corosync, if we want to always have this behaviour for that set of 
packages.

___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH ha-manager 09/13] Add crm command 'stop'

2019-09-27 Thread Fabian Grünbichler
one comment inline

On September 26, 2019 1:38 pm, Fabian Ebner wrote:
> 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 0b90de4..768baa7 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");
>   }
> @@ -562,10 +570,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) {
> @@ -575,9 +583,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') {
> @@ -639,10 +650,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) {
> @@ -651,9 +662,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'});

this uses the methods introduced in patch #2/3, but is missing the 
locking that the other call site (and the other read/modify/write blocks 
for that config file) have.

either move the locking to PVE::HA::Config::update_resources_config in 
#2, or add locking here, or re-evaluate whether there is an approach 
that can skip modifying the config file ;). there are other calls to 
lock_ha_domain in the CRM command handling flow, so it's probably not 
that bad to have another few instances here..

>   } 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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH kernel] backport new FPU register copy helpers

2019-09-27 Thread Fabian Grünbichler
small nit inline, otherwise

Acked-by: Fabian Grünbichler 

On September 27, 2019 12:49 pm, Thomas Lamprecht wrote:
> This allows us to fix the ZFS SIMD patch for 5.0 kernel way easier,
> as we can use the same code path as used for 5.2 and newer kernels
> there.
> 
> The helper itself do not do anything, just exposes them for modules
> to use.
> 
> Signed-off-by: Thomas Lamprecht 
> ---
>  ...kport-copy_kernel_to_XYZ_err-helpers.patch | 102 ++
>  1 file changed, 102 insertions(+)
>  create mode 100644 
> patches/kernel/0007-x86-fpu-backport-copy_kernel_to_XYZ_err-helpers.patch
> 
> diff --git 
> a/patches/kernel/0007-x86-fpu-backport-copy_kernel_to_XYZ_err-helpers.patch 
> b/patches/kernel/0007-x86-fpu-backport-copy_kernel_to_XYZ_err-helpers.patch
> new file mode 100644
> index ..94fc630a0ca9
> --- /dev/null
> +++ 
> b/patches/kernel/0007-x86-fpu-backport-copy_kernel_to_XYZ_err-helpers.patch
> @@ -0,0 +1,102 @@
> +From  Mon Sep 17 00:00:00 2001
> +From: Sebastian Andrzej Siewior 

I'd move this down below, and put your name here ;)

> +Date: Wed, 3 Apr 2019 18:41:50 +0200
> +Subject: [PATCH] x86/fpu: backport copy_kernel_to_XYZ_err helpers
> +MIME-Version: 1.0
> +Content-Type: text/plain; charset=UTF-8
> +Content-Transfer-Encoding: 8bit
> +
> +partial cherry-pick from upstream 5.2 "86/fpu: Restore from kernel
> +memory on the 64-bit path too"
> +commit 926b21f37b072ae4c117052de45a975c6d468fec
> +
> +Namely, only backport the added helpers, none of the semantic changes.
> +
> +relevant parts of the original commit message:
> +> In order to avoid that mess, copy the FPU state from userland, validate
> +> it and then load it. The copy_kernel_…() helpers are basically just
> +> like the old helpers except that they operate on kernel memory and the
> +> fault handler just sets the error value and the caller handles it.

(as discussed offline, there is definitely still an issue with upstream 
ZFS code here, as there is no error handling there whatsoever? but that 
is something to continue on GH I guess.)

> +
> +Link: https://lkml.kernel.org/r/20190403164156.19645-22-bige...@linutronix.de
> +(partial cherry picked from commit 926b21f37b072ae4c117052de45a975c6d468fec)
> +Signed-off-by: Thomas Lamprecht 
> +---
> + arch/x86/include/asm/fpu/internal.h | 43 +
> + 1 file changed, 43 insertions(+)
> +
> +diff --git a/arch/x86/include/asm/fpu/internal.h 
> b/arch/x86/include/asm/fpu/internal.h
> +index fa2c93cb42a2..f3193ab0a2fb 100644
> +--- a/arch/x86/include/asm/fpu/internal.h
>  b/arch/x86/include/asm/fpu/internal.h
> +@@ -122,6 +122,21 @@ extern void fpstate_sanitize_xstate(struct fpu *fpu);
> + err;\
> + })
> + 
> ++#define kernel_insn_err(insn, output, input...) 
> \
> ++({  \
> ++int err;\
> ++asm volatile("1:" #insn "\n\t"  \
> ++ "2:\n" \
> ++ ".section .fixup,\"ax\"\n" \
> ++ "3:  movl $-1,%[err]\n"\
> ++ "jmp  2b\n"\
> ++ ".previous\n"  \
> ++ _ASM_EXTABLE(1b, 3b)   \
> ++ : [err] "=r" (err), output \
> ++ : "0"(0), input);  \
> ++err;\
> ++})
> ++
> + #define kernel_insn(insn, output, input...) \
> + asm volatile("1:" #insn "\n\t"  \
> +  "2:\n" \
> +@@ -158,6 +173,14 @@ static inline void copy_kernel_to_fxregs(struct 
> fxregs_state *fx)
> + }
> + }
> + 
> ++static inline int copy_kernel_to_fxregs_err(struct fxregs_state *fx)
> ++{
> ++if (IS_ENABLED(CONFIG_X86_32))
> ++return kernel_insn_err(fxrstor %[fx], "=m" (*fx), [fx] "m" 
> (*fx));
> ++else
> ++return kernel_insn_err(fxrstorq %[fx], "=m" (*fx), [fx] "m" 
> (*fx));
> ++}
> ++
> + static inline int copy_user_to_fxregs(struct fxregs_sta

Re: [pve-devel] [PATCH zfsonlinux] [SIMD]: FPU register save/restore is also required on 5.0 kernels

2019-09-27 Thread Fabian Grünbichler
Acked-by: Fabian Grünbichler 

On September 27, 2019 12:49 pm, Thomas Lamprecht wrote:
> Do a very minimal fix, effectively just making the code path for 5.0
> to 5.1 and 5.2 to 5.3 the same one, which can be done by backporting
> the new copy_kernel helpers into the kernel, as the existing ones are
> indirectly exported as GPL symbol
> 
> Signed-off-by: Thomas Lamprecht 
> ---
>  ...r-save-restore-is-also-required-on-5.patch | 57 +++
>  debian/patches/series |  1 +
>  2 files changed, 58 insertions(+)
>  create mode 100644 
> debian/patches/0010-SIMD-FPU-register-save-restore-is-also-required-on-5.patch
> 
> diff --git 
> a/debian/patches/0010-SIMD-FPU-register-save-restore-is-also-required-on-5.patch
>  
> b/debian/patches/0010-SIMD-FPU-register-save-restore-is-also-required-on-5.patch
> new file mode 100644
> index 000..87c8af1
> --- /dev/null
> +++ 
> b/debian/patches/0010-SIMD-FPU-register-save-restore-is-also-required-on-5.patch
> @@ -0,0 +1,57 @@
> +From  Mon Sep 17 00:00:00 2001
> +From: Thomas Lamprecht 
> +Date: Wed, 25 Sep 2019 10:48:48 +0200
> +Subject: [PATCH] [SIMD]: FPU register save/restore is also required on 5.0
> + kernels
> +
> +NOTE: the kernel needs to have the copy_kernel_to_xregs_err,
> +copy_kernel_to_fxregs_err and copy_kernel_to_fregs_err funcitons
> +backported for this to work.
> +
> +Signed-off-by: Thomas Lamprecht 
> +---
> + include/linux/simd_x86.h | 11 +--
> + 1 file changed, 1 insertion(+), 10 deletions(-)
> +
> +diff --git a/include/linux/simd_x86.h b/include/linux/simd_x86.h
> +index 5f243e0cc..aac63d964 100644
> +--- a/include/linux/simd_x86.h
>  b/include/linux/simd_x86.h
> +@@ -179,7 +179,6 @@ kfpu_begin(void)
> + preempt_disable();
> + local_irq_disable();
> + 
> +-#if defined(HAVE_KERNEL_TIF_NEED_FPU_LOAD)
> + /*
> +  * The current FPU registers need to be preserved by kfpu_begin()
> +  * and restored by kfpu_end().  This is required because we can
> +@@ -188,20 +187,13 @@ kfpu_begin(void)
> +  * context switch.
> +  */
> + copy_fpregs_to_fpstate(¤t->thread.fpu);
> +-#elif defined(HAVE_KERNEL_FPU_INITIALIZED)
> +-/*
> +- * There is no need to preserve and restore the FPU registers.
> +- * They will always be restored from the task's stored FPU state
> +- * when switching contexts.
> +- */
> ++
> + WARN_ON_ONCE(current->thread.fpu.initialized == 0);
> +-#endif
> + }
> + 
> + static inline void
> + kfpu_end(void)
> + {
> +-#if defined(HAVE_KERNEL_TIF_NEED_FPU_LOAD)
> + union fpregs_state *state = ¤t->thread.fpu.state;
> + int error;
> + 
> +@@ -213,7 +205,6 @@ kfpu_end(void)
> + error = copy_kernel_to_fregs_err(&state->fsave);
> + }
> + WARN_ON_ONCE(error);
> +-#endif
> + 
> + local_irq_enable();
> + preempt_enable();
> diff --git a/debian/patches/series b/debian/patches/series
> index 9b0d7fb..c65e410 100644
> --- a/debian/patches/series
> +++ b/debian/patches/series
> @@ -7,3 +7,4 @@
>  0007-Fix-race-in-parallel-mount-s-thread-dispatching-algo.patch
>  0008-Linux-5.0-compat-SIMD-compatibility.patch
>  0009-Fix-CONFIG_X86_DEBUG_FPU-build-failure.patch
> +0010-SIMD-FPU-register-save-restore-is-also-required-on-5.patch
> -- 
> 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] applied: [PATCH RESEND container] restore lxc.* entries once

2019-09-30 Thread Fabian Grünbichler
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


Re: [pve-devel] [PATCH pve-zsync] Allow detecting a syncing instance of a job

2019-10-01 Thread Fabian Grünbichler
On September 30, 2019 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(-)
> 
> 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);

I don't think we need a (new) lock here - it would only protect against 
other processes entering sync(), but they could at worst do the same 
change (again)? update_state() already has locking to prevent races 
around the modification itself, and this new lock does not protect 
against other read-modify-write cycles (like destroy_job, enable_job, 
disable_job, but also init which just does write ;)).

if we introduce a new lock, it should be to guard all state r-m-w cycles 
  against races with eachother (e.g., by implementing Thomas locked() 
  suggestion, and pulling the lock from update_state there and updating 
  all call sites). the other locks (sync, update_cron) can also re-use 
  this locked mechanism, by passing in some lock identifier/filename 
  (you can also have wrappers around locked, e.g. lock_state, lock_cron 
  and lock_sync).

> +
>  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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH storage] Use bigger timeouts for zfs operations

2019-10-01 Thread Fabian Grünbichler
On October 1, 2019 12:17 pm, Fabian Ebner wrote:
> Seems like 'zfs destroy' can take longer than 5 seconds, see [0].
> I changed the timeout to 15 seconds and also changed the default
> timeout to 10 instead of 5 seconds, to be on the safe side
> for other commands like 'zfs create'.
> 
> [0]: 
> https://forum.proxmox.com/threads/timeout-beim-l%C3%B6schen-des-entfernen-replikats-bei-entfernung-der-replikation.58467/

NAK, we have a 30s timeout for synchronous API requests that call this, 
and they might do more than 2 zfs_requests. we'd rather timeout and have 
time to do error handling, than finish successfully sometimes, and die 
without cleanup other times.

the real solution for this is to convert the remaining synchronous API 
calls that trigger storage operations to async ones, and switch the GUI 
over to use the new variants. we had previous discussions about this 
issue already. to implement it really nice, we'd need to things:
- tasks with structured return value (to implement async content listing 
  and similar operations, and make conversion of sync to async API calls 
  easier)
- light-weight / ephemeral tasks (not included in regular task 
  lists/log, cleaned up after final poll / 1 day after finishing / ...)

in case of the mentioned report, please investigate whether this call in 
'pvesr' context is wrongly treated as sync API call (i.e., is_worker 
should maybe return true for pvesr calls?)
> 
> Signed-off-by: Fabian Ebner 
> ---
>  PVE/Storage/ZFSPoolPlugin.pm | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/PVE/Storage/ZFSPoolPlugin.pm b/PVE/Storage/ZFSPoolPlugin.pm
> index f66b277..3ce06be 100644
> --- a/PVE/Storage/ZFSPoolPlugin.pm
> +++ b/PVE/Storage/ZFSPoolPlugin.pm
> @@ -182,7 +182,7 @@ sub zfs_request {
>  my $msg = '';
>  my $output = sub { $msg .= "$_[0]\n" };
>  
> -$timeout = PVE::RPCEnvironment->is_worker() ? 60*60 : 5 if !$timeout;
> +$timeout = PVE::RPCEnvironment->is_worker() ? 60*60 : 10 if !$timeout;
>  
>  run_command($cmd, errmsg => "zfs error", outfunc => $output, timeout => 
> $timeout);
>  
> @@ -346,7 +346,7 @@ sub zfs_delete_zvol {
>  
>  for (my $i = 0; $i < 6; $i++) {
>  
> - eval { $class->zfs_request($scfg, undef, 'destroy', '-r', 
> "$scfg->{pool}/$zvol"); };
> + eval { $class->zfs_request($scfg, 15, 'destroy', '-r', 
> "$scfg->{pool}/$zvol"); };
>   if ($err = $@) {
>   if ($err =~ m/^zfs error:(.*): dataset is busy.*/) {
>   sleep(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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH v2 guest-common 01/18] refactor pending changes related config code into AbstractConfig

2019-10-02 Thread Fabian Grünbichler
On September 30, 2019 2:44 pm, Oguz Bektas wrote:
> 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) = @_;

conventionally, $text is called $data in our parse_ subs

> +$text ||= '';
> +$text =~ s/[,;]/ /g;
> +$text =~ s/^\s+//;
> +return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };

like I said in v1 of this part, why not use the opportunity to give this 
a sane perl representation?

e.g.,

{
  'opt1' => { 'force' => 0 },
  'opt2' => { 'force' => 1 },
  'opt3' => { 'force' => 0 },
}

then you could still iterate over all pending deletions, and where you 
need that info, you can check if $pending_delete_hash->{$opt}->{force}?

right now, if you accidentally do

if ($pending_delete_hash->{$opt}) 

instead of

if (defined($pending_delete_hash->{$opt}))
or
if (exists($pending_delete_hash->{$opt}))

you probably do the opposite of what you want ;) there is only a single 
such caller atm, and that one is correct, but it's very easy to get 
wrong IMHO.

> +}
> +
> +sub print_pending_delete {
> +my ($class, $how, $lst) = @_;
> +join $how, map { $lst->{$_} . $_ } keys %$lst;

we always want to join with ',', so why make it configurable? also, this 
ain't no l(i)st anymore ;) if we change the $pending_delete_hash 
structure, this obviously needs to be adapted to encode the 
'forcefulness' correctly.

> +}
> +
> +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);
> +}

also would need adaption if we don't store '!' in the 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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH v2 guest-common 02/18] refactor method used by config GET calls into AbstractConfig

2019-10-02 Thread Fabian Grünbichler
On September 30, 2019 2:44 pm, Oguz Bektas wrote:
> 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 {

like I said when we discussed this offline, that name is at most a 
working title :-P the method either returns

A the top level config, ignoring any pending changes (called 'current' 
  in the API schema)
B the top level config, with any pending changes pseudo-applied (the 
  opposite of 'current')
C the config of a specific snapshot + digest of whole file (also not very 
'current').

we can either split this up into

sub load_config_snapshot => returns C
sub load_ ? => returns A or B, depending on parameter

or make a

sub load_config_filtered {
my ($class, $vmid, $filter) = @_;

where $filter is a hash, currently with
{ 'snapshot' => $snapname }

or

{ 'current' => 1 }

both at once don't make sense, and should probably lead to death.

I'd prefer the split, since the first half for case C, and the second 
half for cases A and B don't have much in common anyway. if we have some 
other filters in mind that we might add in the future, then the $filter 
variant might be more attractive.

> +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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH v2 container 08/18] add lxc/pending API path

2019-10-02 Thread Fabian Grünbichler
you completely ignored my comments for v1 of this patch? the whole code 
is identical to qemu-server's, except for cipassword handling. pending 
changes are also encoded identically for both pve-container and 
qemu-server, so it makes sense to move this to AbstractConfig or 
GuestHelpers.pm with an override for cipassword in QemuConfig.pm/here..

this basically just converts $conf into a different representation for 
easier client consumption..

On September 30, 2019 2:44 pm, Oguz Bektas wrote:
> 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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH v2 container 10/18] adapt CT config parser for pending changes

2019-10-02 Thread Fabian Grünbichler
On September 30, 2019 2:44 pm, Oguz Bektas wrote:
> 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

like Thomas said, please split these two (the latter is not even related 
to this series at all! while I agree it's good to do it now, together 
with the same change on qemu-server's part, let's not make this series 
any bigger than it needs to be ;))

one question inline

> 
> 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;
> + }

that seems wrong.. why handle a pending description like that?

>   }
>  
>   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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH v2 container 10/18] adapt CT config parser for pending changes

2019-10-02 Thread Fabian Grünbichler
On October 2, 2019 12:22 pm, Thomas Lamprecht wrote:
> On 9/30/19 2:44 PM, Oguz Bektas wrote:
>> 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
> 
> 1. completely nothing to do with pending changes itself -> separate patch
> 
> 2. they could be supported in 6.x already? PVE cluster host need to be on the
> same version of software, we guarantee only that old -> new and new <-> new
> works, so doing this now is no issue... Else we never could add any new
> feature in a stable release..
> 
> Also this is missing from qemu-server?

the problem is that this is not just a case of new -> old does not work, 
but it's a case of new -> old silently drops parts (/most) of your guest 
config.. since it's just nice to have, but not blocking anything 
important, we should postpone it to 7.0 IMHO (where we can assume that 
the 'old' 6.x parser already supports it, so the fallout is basically 
non-existent at that point).

> 
>> 
>> 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) {
> 
> why not add the new stuff to the end of the elsif block? less churn..

for qemu-server, we need to add it up-front to parse it earlier then a 
snapshot called pending, this would keep the two parsers (that we 
hopefully unify some day) closer together. OTOH, we'd drop all of this 
if we unify it anyway, so..

> 
>> +$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});
>>  }
>> 
> 
> 
> ___
> 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


Re: [pve-devel] [PATCH v2 container 16/18] adapt config PUT method for the new update_pct_config

2019-10-02 Thread Fabian Grünbichler
On September 30, 2019 2:44 pm, Oguz Bektas wrote:
> 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

I already asked that in v1 - wouldn't it make sense to keep the 
parameter checks in the API call, and pass the already "verified" 
$delete and $revert to update_pct_config? this would avoid the need of 
adding new module dependencies from PVE::LXC::Config to 
PVE::RPCEnvironment and PVE::Exception in #17..

if you see a good reason for moving all that to update_pct_config, 
please say so (either in the changelog of the patch, or as reply to the 
original review) and don't silently ignore open questions ;)

> 
> 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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH v2 container 17/18] rework update_pct_config to write into pending section

2019-10-02 Thread Fabian Grünbichler
On September 30, 2019 2:44 pm, Oguz Bektas wrote:
> 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);

I am still not convinced that hashes for delete and revert would not be 
more readable down below.

>  
> -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]);

still no permission checks for reverting?

> +
> +foreach my $opt (PVE::Tools::split_list($revert_str)) {

should be @revert..

> + raise_param_exc({ revert => "unknown option '$opt'" })
> + if !$class->option_exists($opt);
> +
> + raise_param_exc({ delete => "you can't use '-$opt' and " .

wrong parameter to raise the exception for

> +   "'-revert $opt' at the same time" })
> + if defined($param->{$opt});
> +
> + push @revert, $opt;
>  }

@revert now contains each reverted option twice ;)

>  
> -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?

check what?

> + $class->remove_from_pending_delete($conf, $opt); # remove from deletion 
> queue
> +}
> +$class->write_config($vmid, $conf);

do we really need to write_config here? this was just a logical change, 
and if we die afterwards the API call has failed and the changes so 
far where side-effect free anyway..

>  
> -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 =

Re: [pve-devel] [PATCH v2 container 18/18] add vmconfig_hotplug_pending and vmconfig_apply_pending

2019-10-02 Thread Fabian Grünbichler
On September 30, 2019 2:44 pm, Oguz Bektas wrote:
> 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, unde

Re: [pve-devel] [PATCH v2 00/18] lxc pending changes

2019-10-02 Thread Fabian Grünbichler
On September 30, 2019 2:44 pm, Oguz Bektas wrote:
> 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

thanks for the v2! some detailed feedback on invidivual patches. except 
for the naming/order/splitting of commits (see below) and some open 
questions, this already looks quite good!

I'll give v3 a more detailed test run again, since some stuff will 
probably be moved/refactored/rewritten again.

> 
> 
> 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

the order here is a bit wrong IMHO

#12 and #13 can go further up (they just make the later commits safe, 
and don't change anything without the later commits - good for bisecting 
;))

#14 relies on a method only introduced in #18
#15 adds an API parameter, but no code to handle it (I already told you 
this in v1 ;))
#16 reworks that API call further to adapt for changes that only come in 
patch #17
#17 relies on methods only introduced in #18

so, #18 needs to come first (if nobody calls those methods yet, it is 
clear that that change alone cannot break anything!)
#14 can come after, since it only has an effect if pending changes can 
exist (which, barring manual editing, is impossible with just the 
patches up to this point)
#15-17 are a single logical change (switching from "directly apply what 
is possible, die otherwise" to "write to pending, and either apply or 
hotplug depending on whether the CT is running"). no part of that works 
without the other, so just squash them into a single commit unless you 
find a *meaningful* way to split them up. sometimes commits are big, and 
that is okay as long as they are not big because lots of un- or 
semi-related stuff got thrown together.

> 
>  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

those could almost be one commit, since they all do the same:
code moved to AbstractConfig/GuestHelpers, drop own copy and use shared 
one. at least the first two should be squashed for sure.

> 
>  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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [PATCH access-control] parse_user_cfg: correctly parse group names in ACLs

2019-10-03 Thread Fabian Grünbichler
usernames are allowed to start with '@', so adding a user '@test@pve'
and adding it to an ACL should work, instead of ignoring that part of
the ACL entry.

note: there is no potential for user and group to be confused, since a
username must end with '@REALM', and a group reference in an ACL can
only contain one '@' (as first character).

Signed-off-by: Fabian Grünbichler 
---

Notes:
alternatively, we could also disallow usernames starting with '@', but those
are currently working as long as they just have ACLs via groups, and not
directly..

 PVE/AccessControl.pm | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/PVE/AccessControl.pm b/PVE/AccessControl.pm
index 44f4a01..6ea0b85 100644
--- a/PVE/AccessControl.pm
+++ b/PVE/AccessControl.pm
@@ -974,8 +974,9 @@ sub parse_user_config {
}
 
foreach my $ug (split_list($uglist)) {
-   if ($ug =~ m/^@(\S+)$/) {
-   my $group = $1;
+   my ($group) = $ug =~ m/^@(\S+)$/;
+
+   if ($group && verify_groupname($group, 1)) {
if ($cfg->{groups}->{$group}) { # group exists

$cfg->{acl}->{$path}->{groups}->{$group}->{$role} = $propagate;
} else {
-- 
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 16/18] adapt config PUT method for the new update_pct_config

2019-10-04 Thread Fabian Grünbichler
On October 3, 2019 4:32 pm, Oguz Bektas wrote:
> On Wed, Oct 02, 2019 at 01:52:58PM +0200, Fabian Grünbichler wrote:
>> On September 30, 2019 2:44 pm, Oguz Bektas wrote:
>> > 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
>> 
>> I already asked that in v1 - wouldn't it make sense to keep the 
>> parameter checks in the API call, and pass the already "verified" 
>> $delete and $revert to update_pct_config? this would avoid the need of 
>> adding new module dependencies from PVE::LXC::Config to 
>> PVE::RPCEnvironment and PVE::Exception in #17..
>> 
>> if you see a good reason for moving all that to update_pct_config, 
>> please say so (either in the changelog of the patch, or as reply to the 
>> original review) and don't silently ignore open questions ;)
> 
> i actually wanted to move even more. in qemu api it's like:
> 
> ---
> 
> ---
> __PACKAGE__->register_method({
> name => 'update_vm_async',
> path => '{vmid}/config',
> method => 'POST',
> ...
> 
> returns => {
> type => 'string',
> optional => 1,
> },
> code => $update_vm_api,
> });
> ---
> 
> and
> 
> ---
> __PACKAGE__->register_method({
> name => 'update_vm',
> path => '{vmid}/config',
> method => 'PUT',
> protected => 1,
> proxyto => 'node',
> description => "Set virtual machine options (synchrounous API) - You 
> should consider using the POST method instead for any actions involving 
> hotplug or storage allocation.",
> ...
> returns => { type => 'null' },
> code => sub {
> my ($param) = @_;
> &$update_vm_api($param, 1);
> return undef;
> }
> });
> ---
> 
> which i find more readable than the current situation in container code, and 
> the checks are in the $update_vm_api sub.

yes, but in qemu-server ALL of that is in the API file, not in 
QemuServer.pm ;) you can try to see how moving update_pct_config to the 
API feels, all callers are in the API anyway.

> 
> now i don't know which is better in terms of implementation, so if you 
> believe that the checks should stay in api, then we can do it like that.
> 
>> 
>> > 
>> > 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 

Re: [pve-devel] [PATCH qemu-server] fix #2395: check for iscsi on efidisk creation

2019-10-06 Thread Fabian Grünbichler
On October 4, 2019 10:55 am, Dominik Csapak wrote:
> otherwise qemu-img uses its default intiator id which may not have access

isn't this also missing from

PVE/QemuServer/Cloudinit.pm
PVE/QemuServer/ImportDisk.pm

and isn't the 'cache=none' addition for ZFS missing from all three?

maybe it would make sense to have a 'convert volume to qemu-img options' 
helper that does all of that correctly in one place?

> 
> Signed-off-by: Dominik Csapak 
> ---
>  PVE/QemuServer.pm | 12 +++-
>  1 file changed, 11 insertions(+), 1 deletion(-)
> 
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 8376260..2267a3a 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -7277,8 +7277,18 @@ sub create_efidisk($) {
>  PVE::Storage::activate_volumes($storecfg, [$volid]);
>  
>  my $path = PVE::Storage::path($storecfg, $volid);
> +
> +my $targetopts = ['-O', $fmt];
> +if ($path =~ m|^iscsi://|) {
> + $targetopts = ['--target-image-opts'];
> + $path = convert_iscsi_path($path);
> +}
> +
> +my $cmd = ['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw' ];
> +push @$cmd, @$targetopts, $ovmf_vars, $path;
> +
>  eval {
> - run_command(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', 
> $fmt, $ovmf_vars, $path]);
> + run_command($cmd);
>  };
>  die "Copying EFI vars image failed: $@" if $@;
>  
> -- 
> 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


Re: [pve-devel] [PATCH qemu-server] Fix #2171: VM statefile was not activated

2019-10-07 Thread Fabian Grünbichler
On October 7, 2019 2:41 pm, Alwin Antreich wrote:
> Machine states that were created on snapshots with memory could not be
> restored on rollback. The state volume was not activated so KVM couldn't
> load the state.
> 
> This patch moves the path generation into vm_start and de-/activates the
> state volume.

alternatively, the following could also work and re-use more code so 
that we don't miss the next special handling of some corner case. 
rolling back from a snapshot with state is just like resuming, but we 
want to keep the statefile instead of deleting it.

(untested):

diff --git a/PVE/QemuConfig.pm b/PVE/QemuConfig.pm
index edbf1a7..b70c276 100644
--- a/PVE/QemuConfig.pm
+++ b/PVE/QemuConfig.pm
@@ -358,9 +358,7 @@ sub __snapshot_rollback_vm_stop {
 sub __snapshot_rollback_vm_start {
 my ($class, $vmid, $vmstate, $data) = @_;
 
-my $storecfg = PVE::Storage::config();
-my $statefile = PVE::Storage::path($storecfg, $vmstate);
-PVE::QemuServer::vm_start($storecfg, $vmid, $statefile, undef, undef, 
undef, $data->{forcemachine});
+PVE::QemuServer::vm_start($storecfg, $vmid, $vmstate, undef, undef, undef, 
$data->{forcemachine});
 }
 
 sub __snapshot_rollback_get_unused {
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 8376260..f2d19e1 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -5418,6 +5418,11 @@ sub vm_start {
print "Resuming suspended VM\n";
}
 
+   if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
+   # re-use resume code
+   $conf->{vmstate} = $statefile;
+   }
+
my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, 
$conf, $defaults, $forcemachine);
 
my $migrate_port = 0;
@@ -5465,8 +5470,6 @@ sub vm_start {
push @$cmd, '-incoming', $migrate_uri;
push @$cmd, '-S';
 
-   } else {
-   push @$cmd, '-loadstate', $statefile;
}
} elsif ($paused) {
push @$cmd, '-S';
@@ -5616,11 +5619,16 @@ sub vm_start {
property => "guest-stats-polling-interval",
value => 2) if (!defined($conf->{balloon}) || 
$conf->{balloon});
 
-   if ($is_suspended && (my $vmstate = $conf->{vmstate})) {
-   print "Resumed VM, removing state\n";
-   delete $conf->@{qw(lock vmstate runningmachine)};
+   if (my $vmstate = $conf->{vmstate}) {
PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
-   PVE::Storage::vdisk_free($storecfg, $vmstate);
+   delete $conf->{vmstate};
+
+   if ($is_suspended) {
+   print "Resumed VM, removing state\n";
+   delete $conf->@{qw(lock runningmachine)};
+   PVE::Storage::vdisk_free($storecfg, $vmstate);
+   }
+
PVE::QemuConfig->write_config($vmid, $conf);
}
 

> 
> Signed-off-by: Alwin Antreich 
> ---
>  PVE/QemuConfig.pm |  3 +--
>  PVE/QemuServer.pm | 10 +-
>  2 files changed, 10 insertions(+), 3 deletions(-)
> 
> diff --git a/PVE/QemuConfig.pm b/PVE/QemuConfig.pm
> index edbf1a7..e9796a3 100644
> --- a/PVE/QemuConfig.pm
> +++ b/PVE/QemuConfig.pm
> @@ -359,8 +359,7 @@ sub __snapshot_rollback_vm_start {
>  my ($class, $vmid, $vmstate, $data) = @_;
>  
>  my $storecfg = PVE::Storage::config();
> -my $statefile = PVE::Storage::path($storecfg, $vmstate);
> -PVE::QemuServer::vm_start($storecfg, $vmid, $statefile, undef, undef, 
> undef, $data->{forcemachine});
> +PVE::QemuServer::vm_start($storecfg, $vmid, $vmstate, undef, undef, 
> undef, $data->{forcemachine});
>  }
>  
>  sub __snapshot_rollback_get_unused {
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 8376260..39315b3 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -5420,6 +5420,7 @@ sub vm_start {
>  
>   my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, 
> $conf, $defaults, $forcemachine);
>  
> +
>   my $migrate_port = 0;
>   my $migrate_uri;
>   if ($statefile) {
> @@ -5466,7 +5467,12 @@ sub vm_start {
>   push @$cmd, '-S';
>  
>   } else {
> - push @$cmd, '-loadstate', $statefile;
> + my $sfile = $statefile;
> + if (!-e $statefile) {
> + PVE::Storage::activate_volumes($storecfg, [$statefile]);
> + $sfile = PVE::Storage::path($storecfg, $statefile);
> + }

why only activate if the file does not exist? $statefile should be a 
full volume ID including storage at this point, it does not make sense 
to check for existence?

> + push @$cmd, '-loadstate', $sfile;
>   }
>   } elsif ($paused) {
>   push @$cmd, '-S';
> @@ -5622,6 +5628,8 @@ sub vm_start {
>   PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
>   PVE::Storage::vdisk_free($storecfg, $vmstate);
>   PVE::QemuConfig->write_config($vmid, $conf);
> + } elsif (

Re: [pve-devel] [PATCH qemu-server] Fix #2171: VM statefile was not activated

2019-10-08 Thread Fabian Grünbichler
On October 8, 2019 11:25 am, Alwin Antreich wrote:
> On Tue, Oct 08, 2019 at 08:36:57AM +0200, Fabian Grünbichler wrote:
>> On October 7, 2019 2:41 pm, Alwin Antreich wrote:
>> > Machine states that were created on snapshots with memory could not be
>> > restored on rollback. The state volume was not activated so KVM couldn't
>> > load the state.
>> > 
>> > This patch moves the path generation into vm_start and de-/activates the
>> > state volume.
>> 
>> alternatively, the following could also work and re-use more code so 
>> that we don't miss the next special handling of some corner case. 
>> rolling back from a snapshot with state is just like resuming, but we 
>> want to keep the statefile instead of deleting it.
> I will send another version with your alternative.
> 
>> 
>> (untested):
>> 
>> diff --git a/PVE/QemuConfig.pm b/PVE/QemuConfig.pm
>> index edbf1a7..b70c276 100644
>> --- a/PVE/QemuConfig.pm
>> +++ b/PVE/QemuConfig.pm
>> @@ -358,9 +358,7 @@ sub __snapshot_rollback_vm_stop {
>>  sub __snapshot_rollback_vm_start {
>>  my ($class, $vmid, $vmstate, $data) = @_;
>>  
>> -my $storecfg = PVE::Storage::config();
>> -my $statefile = PVE::Storage::path($storecfg, $vmstate);
>> -PVE::QemuServer::vm_start($storecfg, $vmid, $statefile, undef, undef, 
>> undef, $data->{forcemachine});
>> +PVE::QemuServer::vm_start($storecfg, $vmid, $vmstate, undef, undef, 
>> undef, $data->{forcemachine});
>>  }
>>  
>>  sub __snapshot_rollback_get_unused {
>> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
>> index 8376260..f2d19e1 100644
>> --- a/PVE/QemuServer.pm
>> +++ b/PVE/QemuServer.pm
>> @@ -5418,6 +5418,11 @@ sub vm_start {
>>  print "Resuming suspended VM\n";
>>  }
>>  
>> +if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
>> +# re-use resume code
>> +$conf->{vmstate} = $statefile;
>> +}
>> +
>>  my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, 
>> $conf, $defaults, $forcemachine);
>>  
>>  my $migrate_port = 0;
>> @@ -5465,8 +5470,6 @@ sub vm_start {
>>  push @$cmd, '-incoming', $migrate_uri;
>>  push @$cmd, '-S';
>>  
>> -} else {
>> -push @$cmd, '-loadstate', $statefile;
>>  }
>>  } elsif ($paused) {
>>  push @$cmd, '-S';
>> @@ -5616,11 +5619,16 @@ sub vm_start {
>>  property => "guest-stats-polling-interval",
>>  value => 2) if (!defined($conf->{balloon}) || 
>> $conf->{balloon});
>>  
>> -if ($is_suspended && (my $vmstate = $conf->{vmstate})) {
>> -print "Resumed VM, removing state\n";
>> -delete $conf->@{qw(lock vmstate runningmachine)};
>> +if (my $vmstate = $conf->{vmstate}) {
>>  PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
>> -PVE::Storage::vdisk_free($storecfg, $vmstate);
>> +delete $conf->{vmstate};
>> +
>> +if ($is_suspended) {
>> +print "Resumed VM, removing state\n";
>> +delete $conf->@{qw(lock runningmachine)};
>> +PVE::Storage::vdisk_free($storecfg, $vmstate);
>> +}
>> +
>>  PVE::QemuConfig->write_config($vmid, $conf);
>>  }
>>  
>> 
>> > 
>> > Signed-off-by: Alwin Antreich 
>> > ---
>> >  PVE/QemuConfig.pm |  3 +--
>> >  PVE/QemuServer.pm | 10 +-
>> >  2 files changed, 10 insertions(+), 3 deletions(-)
>> > 
>> > diff --git a/PVE/QemuConfig.pm b/PVE/QemuConfig.pm
>> > index edbf1a7..e9796a3 100644
>> > --- a/PVE/QemuConfig.pm
>> > +++ b/PVE/QemuConfig.pm
>> > @@ -359,8 +359,7 @@ sub __snapshot_rollback_vm_start {
>> >  my ($class, $vmid, $vmstate, $data) = @_;
>> >  
>> >  my $storecfg = PVE::Storage::config();
>> > -my $statefile = PVE::Storage::path($storecfg, $vmstate);
>> > -PVE::QemuServer::vm_start($storecfg, $vmid, $statefile, undef, undef, 
>> > undef, $data->{forcemachine});
>> > +PVE::QemuServer::vm_start($storecfg, $vmid, $vmstate, undef, undef, 
>> > undef, $data->{forcemachine});
>> >  }
>> >  
>> >  sub __snapshot_rollback_get_unused {
>> &g

Re: [pve-devel] [PATCH storage] Use bigger timeouts for zfs operations

2019-10-10 Thread Fabian Grünbichler
On October 10, 2019 8:55 am, Fabian Ebner wrote:
> On 10/1/19 12:28 PM, Fabian Grünbichler wrote:
>> On October 1, 2019 12:17 pm, Fabian Ebner wrote:
>>> Seems like 'zfs destroy' can take longer than 5 seconds, see [0].
>>> I changed the timeout to 15 seconds and also changed the default
>>> timeout to 10 instead of 5 seconds, to be on the safe side
>>> for other commands like 'zfs create'.
>>>
>>> [0]: 
>>> https://forum.proxmox.com/threads/timeout-beim-l%C3%B6schen-des-entfernen-replikats-bei-entfernung-der-replikation.58467/
>> NAK, we have a 30s timeout for synchronous API requests that call this,
>> and they might do more than 2 zfs_requests. we'd rather timeout and have
>> time to do error handling, than finish successfully sometimes, and die
>> without cleanup other times.
>>
>> the real solution for this is to convert the remaining synchronous API
>> calls that trigger storage operations to async ones, and switch the GUI
>> over to use the new variants. we had previous discussions about this
>> issue already. to implement it really nice, we'd need to things:
>> - tasks with structured return value (to implement async content listing
>>and similar operations, and make conversion of sync to async API calls
>>easier)
>> - light-weight / ephemeral tasks (not included in regular task
>>lists/log, cleaned up after final poll / 1 day after finishing / ...)
>>
>> in case of the mentioned report, please investigate whether this call in
>> 'pvesr' context is wrongly treated as sync API call (i.e., is_worker
>> should maybe return true for pvesr calls?)
> I looked at setting the worker flag for the (whole) pvesr environment, 
> but it seems a
> bit much. E.g. in prepare we need to delete stale snapshots before 
> starting the replication
> and we probably don't want to wait all too long for that to complete, 
> i.e. not
> have the worker flag when calling volume_snapshot_delete.
> 
> The situation is different with the vdisk_free call, since there we 
> don't need to
> sit and wait for the result, so there it would make sense to be treated 
> as a worker.
> So we could set the worker flag locally before that call and use our own 
> timeout,
> but it feels like a bad workaround. Also we can't use run_with_timeout 
> to set our own
> timeout, since run_command is called inside vdisk_free, which resets the 
> alarm.

but we could use run_fork_with_timeout ;)

> Since we have a mechanism to spawn a worker in vdisk_free already 
> (currently only
> used by LVM with saferemove), wouldn't it make sense to use that for zfs 
> as well? So
> having free_image in the zfs plugin return a subroutine instead of 
> executing zfs destroy
> directly. Also other callers of vdisk_free should be fine with such a 
> change, since it already
> can happen that vdisk_free spawns a worker (but I haven't looked in detail).

but that is the non-default behaviour, not the default one. I'd rather 
not switch all ZFS vdisk removals to forking a task if there are other 
solutions.

AFAICT, this vdisk_free happens only for previously, but no-longer 
replicated volumes? a simple solution might be to re-factor 139ff of 
pvesr.pm to fork a worker if any vdisks need to be removed, and remove 
them all asynchronously in a single task?

OTOH, if vdisk_free runs into this problem, it's only a question of load 
for other zfs_requests (like listing volumes, snapshots, creating 
snapshots, removing snapshots) to also run into the low timeouts.. so 
the big question still remains - do we want to increase those timeouts 
in general for pvesr, and if we do, how do we do it?

> It would introduce a bit of noise since it would create a task on every 
> vdisk_free for a zfs volume.
> There the light-weight tasks you mentioned would be ideal, but for now 
> we don't have those.
> And maybe the timeout is hit very rarely and so it's not worth the 
> change, what do you think?
> 
>>> Signed-off-by: Fabian Ebner 
>>> ---
>>>   PVE/Storage/ZFSPoolPlugin.pm | 4 ++--
>>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/PVE/Storage/ZFSPoolPlugin.pm b/PVE/Storage/ZFSPoolPlugin.pm
>>> index f66b277..3ce06be 100644
>>> --- a/PVE/Storage/ZFSPoolPlugin.pm
>>> +++ b/PVE/Storage/ZFSPoolPlugin.pm
>>> @@ -182,7 +182,7 @@ sub zfs_request {
>>>   my $msg = '';
>>>   my $output = sub { $msg .= "$_[0]\n" };
>>>   
>>> -$timeout = PVE::RPCEnvironment->is_worker() ? 60*60 : 5 if !$timeout;
>>> +$timeout = PVE

Re: [pve-devel] [PATCH qemu-server] Fix #2412: Missing VMs in pools

2019-10-11 Thread Fabian Grünbichler
On October 11, 2019 11:55 am, Dominic Jäger wrote:
> Between destroying a VM (unlink config file) and removing it from user.cfg
> creating a new VM with the ID that is still in use in user.cfg was possible.
> VMs could go missing as a consequence.
> 
> Adding a lock solves this. This lock does not interfere with the one in
> vm_destroy as they are held by the same process.
> 
> Signed-off-by: Dominic Jäger 
> ---
>  PVE/API2/Qemu.pm | 8 +---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
> index 267a08e..7dd83a9 100644
> --- a/PVE/API2/Qemu.pm
> +++ b/PVE/API2/Qemu.pm
> @@ -1492,9 +1492,11 @@ __PACKAGE__->register_method({
>   my $upid = shift;
>  
>   syslog('info', "destroy VM $vmid: $upid\n");
> - PVE::QemuServer::vm_destroy($storecfg, $vmid, $skiplock);
> - PVE::AccessControl::remove_vm_access($vmid);
> -PVE::Firewall::remove_vmfw_conf($vmid);
> + PVE::QemuConfig->lock_config($vmid, sub {
> + PVE::QemuServer::vm_destroy($storecfg, $vmid, $skiplock);
> + PVE::AccessControl::remove_vm_access($vmid);
> + PVE::Firewall::remove_vmfw_conf($vmid);
> + });

this is not enough - as soon as PVE::QemuServer::destroy_vm unlinks the 
VM config file, the lock_config becomes worthless in a clustered setup. 

you need to move the VM config unlinking to become the last step, e.g. 
by exposing destroy_vm's $keep_empty_config via vm_destroy as well, 
and setting it here.

the current situation is especially bad, since we vdisk_free unused 
disks AFTER unlinking the config file, so the delay between unlinking 
the config file, and removing from user.cfg/removing the firewall config 
can be quite long..

>   };
>  
>   return $rpcenv->fork_worker('qmdestroy', $vmid, $authuser, $realcmd);
> -- 
> 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 v4 qemu 02/12] Write understood CPU flags into static file

2019-10-14 Thread Fabian Grünbichler
On October 7, 2019 2:47 pm, Stefan Reiter wrote:
> located at /usr/share/kvm/cpu-flags-understood-$arch
> 
> This file can be read by qemu-server's "query_understood_cpu_flags"
> function, avoiding a more expensive call to QEMU.
> 
> For now, only x86_64 is implemented, since aarch64 doesn't print any flags 
> when
> called this way.
> 
> Signed-off-by: Stefan Reiter 
> ---
>  debian/rules | 9 +
>  1 file changed, 9 insertions(+)
> 
> diff --git a/debian/rules b/debian/rules
> index 8f428c7..7cf73fb 100755
> --- a/debian/rules
> +++ b/debian/rules
> @@ -128,6 +128,15 @@ install: build
>   rm -Rf $(destdir)/usr/include
>   rm -Rf $(destdir)/usr/lib*
>  
> + # write files for understood CPU flags, since these are static for every
> + # version (saves a QEMU call in qemu-server at runtime)
> + $(destdir)/usr/bin/qemu-system-x86_64 -cpu help \
> + | perl -0777 -pe ' \
> + s/^.*Recognized CPUID flags://s; # remove up to flags \
> + s/\n{2,}.*$$//s; # remove any trailing text \
> + s/\s{2,}|\n/\s/g; # remove unnecessary whitespace \
> + ' > $(destdir)/usr/share/kvm/cpu-flags-understood-x86_64

might make sense to add a check that the file is non-empty afterwards, 
to catch breakage early?

> +
>  # Build architecture-independent files here.
>  binary-indep: build install
>  # We have nothing to do by default.
> -- 
> 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


Re: [pve-devel] [PATCH v4 manager 01/12] Broadcast supported CPU flags

2019-10-14 Thread Fabian Grünbichler
On October 7, 2019 2:47 pm, Stefan Reiter wrote:
> 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
> key-value pairs to the cluster.
> 
> If detection fails, we clear the kv-store and set up a delay (120s), to not
> try again too quickly.
> 
> Signed-off-by: Stefan Reiter 
> ---
> 
> v2 -> v3:
> * broadcast tcg and kvm flags if available
> * clear kv-store on error, wait a bit until retry
> 
> 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 | 46 +++--
>  1 file changed, 44 insertions(+), 2 deletions(-)
> 
> diff --git a/PVE/Service/pvestatd.pm b/PVE/Service/pvestatd.pm
> index bad1b73d..f99036c4 100755
> --- a/PVE/Service/pvestatd.pm
> +++ b/PVE/Service/pvestatd.pm
> @@ -78,6 +78,46 @@ sub hup {
>  $restart_request = 1;
>  }
>  
> +my $cached_kvm_version = '';
> +my $next_flag_update_time;
> +my $failed_flag_update_delay_sec = 120;
> +
> +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 $cached_kvm_version && $cached_kvm_version eq $kvm_version;
> +
> +if ($next_flag_update_time && $next_flag_update_time > time()) {
> + return;
> +}
> +$next_flag_update_time = 0;
> +
> +my $supported_cpuflags = eval { 
> PVE::QemuServer::query_supported_cpu_flags() };

shouldn't this always return at least

{ tcg => undef, kvm => undef }

unless arch is aarch64 (which means it always fails anyway) or locking 
the fake VMID fails?

> +warn $@ if $@;
> +
> +if (!$supported_cpuflags) {

which makes this check kind of wrong?

> + # something went wrong, clear broadcast flags and set try-again delay
> + warn "CPU flag detection failed, will try again after delay\n";
> + $next_flag_update_time = time() + $failed_flag_update_delay_sec;
> +
> + $supported_cpuflags = {};
> +} else {

we enter the else branch

> + # only set cached version if there's actually something to braodcast
> + $cached_kvm_version = $kvm_version if $supported_cpuflags;

and set this, even though we don't have anything to broadcast. the 
post-fix if is redundant btw, since it's the negation of the outer if 
condition.

> +}
> +
> +for my $accel ("tcg", "kvm") {
> + if ($supported_cpuflags->{$accel}) {
> + PVE::Cluster::broadcast_node_kv("cpuflags-$accel", join(' ', 
> @{$supported_cpuflags->{$accel}}));
> + } else {
> + # clear potentially invalid data
> + PVE::Cluster::broadcast_node_kv("cpuflags-$accel", '');

at least we end up here and clear both values ;)

> + }
> +}
> +}
> +
>  my $generate_rrd_string = sub {
>  my ($data) = @_;
>  
> @@ -97,7 +137,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 +152,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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH v4 qemu-server 05/12] Add CPUConfig file and migrate some helpers

2019-10-14 Thread Fabian Grünbichler
On October 7, 2019 2:47 pm, Stefan Reiter wrote:
> 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.
> 
> qemu_machine_feature_enabled is moved to avoid a cyclic module dependency.
> 
> Signed-off-by: Stefan Reiter 
> ---
> 
> v3:
> * mention qemu_machine_feature_enabled in commit msg
> 
> 
>  PVE/QemuServer.pm   | 245 +-
>  PVE/QemuServer/CPUConfig.pm | 254 
>  PVE/QemuServer/Makefile |   1 +
>  3 files changed, 259 insertions(+), 241 deletions(-)
>  create mode 100644 PVE/QemuServer/CPUConfig.pm
> 
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 4447afc..58e2944 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,108 +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',
> -'Cascadelake-Server' => 'GenuineIntel',
> -KnightsMill => '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,
> @@ -606,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',

Re: [pve-devel] [PATCH v4 qemu-server 07/12] Add overrides and convenience functions to CPUConfig

2019-10-14 Thread Fabian Grünbichler
On October 7, 2019 2:47 pm, Stefan Reiter wrote:
> 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 
> ---
> 
> v3 -> v4:
> * add is_custom_model
> 
> v2 -> v3:
> * add validity checks to write_config
> 
> 
>  PVE/QemuServer/CPUConfig.pm | 65 +
>  1 file changed, 65 insertions(+)
> 
> diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm
> index 6ea5811..9876757 100644
> --- a/PVE/QemuServer/CPUConfig.pm
> +++ b/PVE/QemuServer/CPUConfig.pm
> @@ -151,6 +151,71 @@ 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
> + # models parsed from file are by definition always custom
> + cputype => "custom-$sectionId",
> +});
> +}
> +
> +sub write_config {
> +my ($class, $filename, $cfg) = @_;
> +
> +for my $model (keys %{$cfg->{ids}}) {
> + my $model_conf = $cfg->{ids}->{$model};
> +
> + die "internal error: tried saving built-in CPU model (or missing 
> prefix)\n"
> + if !is_custom_model($model_conf->{cputype});
> +
> + die "internal error: tried saving custom cpumodel with cputype 
> (ignoring prefix) not equal to \$cfg->ids entry\n"
> + if "custom-$model" ne $model_conf->{cputype};
> +
> + # saved in section header
> + delete $model_conf->{cputype};
> +}
> +
> +$class->SUPER::write_config($filename, $cfg);
> +}
> +
> +sub is_custom_model {
> +my ($cputype) = @_;
> +return $cputype =~ m/^custom-/;
> +}
> +
> +# Use this to get a single model in the format described by $cpu_fmt.
> +# Fills in defaults from schema if value is not set in config.
> +# Returns undef for unknown $name, allows names with and without custom- 
> prefix.
> +sub get_model_by_name {
> +my ($conf, $name) = @_;

see latter patches as well.

I'd rename this to get_custom_model, and inline the call to 
load_custom_model_conf since there is only one call-site which does the 
load right before just to call this, and we are only ever interested in 
a single model anyway..

adding $noerr

> +
> +$name =~ s/^custom-//;
> +
> +my $entry = $conf->{ids}->{$name};
> +return undef if !defined($entry);

and a 'die' here would also be a good idea I think.
> +
> +my $propList = $defaultData->{propertyList};
> +
> +my $model = {};
> +for my $property (keys %$propList) {
> + next if $property eq 'type';
> +
> + if (my $value = $entry->{$property}) {
> + $model->{$property} = $value;
> + } elsif (my $default = $propList->{$property}->{default}) {
> + $model->{$property} = $default;
> + }

does this really make sense here? for 'hidden' it's problematic, for 
'host-phys-bits' it has no effect anyway since the default is 0, 
reported-model is only accessed once so we could move the default 
application there, and cputype is non-optional for all intents and 
purposes, so we should never need to apply the default here?

> +}
> +
> +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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH v4 qemu-server 06/12] Adapt CPUConfig to handle custom models

2019-10-14 Thread Fabian Grünbichler
On October 7, 2019 2:47 pm, Stefan Reiter wrote:
> Turn CPUConfig into a SectionConfig with parsing/writing support for
> custom CPU models. IO is handled using cfs.
> 
> Namespacing will be provided using "custom-" prefix for custom model
> names (in VM config only, cpu-models.conf will contain unprefixed
> names).
> 
> Signed-off-by: Stefan Reiter 
> ---
> 
> v4: Use "custom-" prefix instead of distinct property for namespacing as
> suggested by Thomas. Left the v3 message below, but this fixes that issue.
> 
> v3: I changed the "custom" property to "built-in" and negated its uses, as
> Thomas suggested. I'm not sure I like this too much compared to "custom" (with
> "built-in", you have to explicitly set a value in the config to 0, which looks
> weird - basically "unsetting" something to use a feature), but I'm very much
> fine with either.
> 
> 
>  PVE/QemuServer/CPUConfig.pm | 46 +++--
>  1 file changed, 44 insertions(+), 2 deletions(-)
> 
> diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm
> index c55128f..6ea5811 100644
> --- a/PVE/QemuServer/CPUConfig.pm
> +++ b/PVE/QemuServer/CPUConfig.pm
> @@ -4,6 +4,8 @@ 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';

while this seems to work, IMHO it's would be better to merge both 'use 
base' into a single statement..

>  our @EXPORT_OK = qw(
> @@ -12,6 +14,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',
> @@ -83,11 +94,20 @@ 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 
> (custom model names must be prefixed with 'custom-').",
>   type => 'string',
> - enum => [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
> + format_description => 'string',
>   default => 'kvm64',
>   default_key => 1,
> + 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 { lc("$a") cmp lc("$b") } keys %$cpu_vendor_list ],
> + default => 'kvm64',
> + optional => 1,
>  },
>  hidden => {
>   description => "Do not identify as a KVM virtual machine.",
> @@ -113,6 +133,24 @@ our $cpu_fmt = {
>  },
>  };
>  
> +# 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) = @_;
> @@ -251,4 +289,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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH v4 qemu-server 08/12] Verify VM-specific CPU configs seperately

2019-10-14 Thread Fabian Grünbichler
On October 7, 2019 2:47 pm, Stefan Reiter wrote:
> $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 
> ---
> 
> v3 -> v4:
> * use is_custom_model
> 
> v2 -> v3:
> * move $cpu_fmt->{flags} changes here, to avoid having broken checks between
>   patches
> 
> 
>  PVE/QemuServer.pm   |  2 +-
>  PVE/QemuServer/CPUConfig.pm | 70 ++---
>  2 files changed, 67 insertions(+), 5 deletions(-)
> 
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 58e2944..04ab1c2 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 9876757..fb8e852 100644
> --- a/PVE/QemuServer/CPUConfig.pm
> +++ b/PVE/QemuServer/CPUConfig.pm
> @@ -90,9 +90,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)]})/;

maybe it makes sense to pull out both REs?

>  
> -our $cpu_fmt = {
> +my $cpu_fmt = {
>  cputype => {
>   description => "Emulated CPU type. Can be default or custom name 
> (custom model names must be prefixed with 'custom-').",
>   type => 'string',
> @@ -125,14 +125,76 @@ 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,
>  },
>  };
>  
> +# $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 parse_cpu_conf_basic {
> +my ($cpu_str, $noerr) = @_;
> +
> +my $cpu = eval { PVE::JSONSchema::parse_property_string($cpu_fmt, 
> $cpu_str) };
> +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

required, but only encoded in section header?

> +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_str, $noerr) = @_;
> +
> +my $cpu = parse_cpu_conf_basic($cpu_str, $noerr);
> +return undef if !$cpu;
> +
> +my $cputype = $cpu->{cputype};
> +
> +if (is_custom_model($cputype)) {
> + # Custom model only has to exist, all props are allowed
> + my $config = load_custom_model_conf();
> + my $cputype_id = $cputype;
> + $cputype_id =~ s/^custom-//;
> + return $cpu if $config && defined($config->{ids}->{$cputype_id});

this is very similar to get_model_by_name, see my other comments there 
and think about re-using it here..

> +
> + die "Custom cputype '$cputype_id' not found\n" if !$noerr;
> + return undef;
> +}
> +
> +# Only built-in models get here
> +if (!defined($cpu_vendor_list->{$cputype})) {
> + die "Default cputype '$cputype' not found\n" if !$noerr;

s/Default/Built-in/

or even

"(Built-in) cputype '$cputype' is not defined (missing 'custom-' prefix?)\n"

> + 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;
> +}
> +
> +die "Property 'reported-model' not allowed in VM-specific CPU config.\n"
> + if defined($cpu->{'reported-model'});
> +
> +return $cpu;
> +}
> +
>  # Section config settings
>  my $defaultData = {
>  # shallow copy, since SectionConfig modifies propertyList internally
> -- 
> 2.20.1
> 
> 
> ___
>

Re: [pve-devel] [PATCH v4 qemu-server 09/12] Add helpers to better structure CPU option handling

2019-10-14 Thread Fabian Grünbichler
On October 7, 2019 2:47 pm, Stefan Reiter wrote:
> 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 fb8e852..405ad86 100644
> --- a/PVE/QemuServer/CPUConfig.pm
> +++ b/PVE/QemuServer/CPUConfig.pm
> @@ -298,6 +298,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 = \@_;

why? it's only used once two lines below, where you immediately 
derefence it again.

> +
> +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};
> + }

eq should be ne, right? either the definedness changed, or it was and is 
defined and the value changed?

AFAICT, this is in fact the following nested conditional:

my $value_changed = (defined($flag->{value}) != defined($old_flag->{value})) ||
(defined($flag->{value}) && $flag->{value} ne 
$old_flag->{value});

which is more readable IMHO, but you could also expand it more with 
additional variables.

> +
> + 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 mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH v4 qemu-server 10/12] Rework get_cpu_options and allow custom CPU models

2019-10-14 Thread Fabian Grünbichler
On October 7, 2019 2:47 pm, Stefan Reiter wrote:
> If a cputype is custom (check via prefix), try to load options from the
> custom CPU model config, and set values accordingly.
> 
> While at it, extract currently hardcoded values into seperate sub and add
> reasonings.
> 
> Since 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 
> ---
> 
> v3 -> v4:
> * use is_custom_model
> 
> v3: Since it's just a few lines, I included the test changes into this patch
> directly. This way all patches in the series should be buildable without
> problems.
> 
> v2: It was quite interesting to dig through old commit messages/mail archives 
> to
> find the actual reasons some of the 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| 185 +++--
>  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 +-
>  7 files changed, 144 insertions(+), 53 deletions(-)
> 
> diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm
> index 405ad86..0948f67 100644
> --- a/PVE/QemuServer/CPUConfig.pm
> +++ b/PVE/QemuServer/CPUConfig.pm
> @@ -369,96 +369,187 @@ 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 $cpuconf = {};
> +my $custom_cpuconf;

bad naming:

$cpu (further below)
$cpuconf
$custom_cpuconf
$custom_conf (a bit below)

maybe

$cpu -> $cpu_str (string that is generated to be passed via -cpu)
$cpuconf -> $cpu
$custom_cpuconf -> $custom_cpu
$custom_conf -> inline, maybe even into get_model_by_name ?

>  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 (my $cpu_prop_str = $conf->{cpu}) {
> + $cpuconf = verify_vm_cpu_conf($cpu_prop_str)
> + or die "Cannot parse cpu description: $cpu_prop_str\n";

s/verify_vm_cpu_conf/parse_cpu_conf_basic ?

>  
> - if (defined(my $flags = $cpuconf->{flags})) {
> - push @$cpuFlags, split(";", $flags);
> - }
> -}
> + $cputype = $cpuconf->{cputype};
>  
> -push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
> + if (is_custom_model($cputype)) {
> + 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";
>  
> -push @$cpuFlags , '-x2apic'
> - if $conf->{ostype} && $conf->{ostype} eq 'solaris';
> + $cputype = $custom_cpuconf->{'reported-model'};
> + $kvm_off = $custom_cpuconf->{hidden};

this is a bit tricky - the schema default is 0, get_model_by_name 
applies this default, and now we override the passed-in explicit value 
with the default value from the custom CPU schema.

maybe drop the default and add an 'if defined' here?

> + $hv_vendor_id = $custom_cpuconf->{'hv-vendor-id'};
> + }
>  
> -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})) {

Re: [pve-devel] [PATCH kernel-meta] fix #2403: exclude initrd entries from /proc/cmdline

2019-10-15 Thread Fabian Grünbichler
On October 15, 2019 3:54 pm, Thomas Lamprecht wrote:
> On 10/15/19 3:22 PM, Oguz Bektas wrote:
>> if we fallback to /proc/cmdline, it can include the booted initrd.
>> 
>> to avoid loader entries with (sometimes even multiple) initrd lines,
>> we have to parse them out.
>> 
>> Signed-off-by: Oguz Bektas 
>> ---
>>  efiboot/zz-pve-efiboot | 3 ++-
>>  1 file changed, 2 insertions(+), 1 deletion(-)
>> 
>> diff --git a/efiboot/zz-pve-efiboot b/efiboot/zz-pve-efiboot
>> index 4756555..5a84af2 100755
>> --- a/efiboot/zz-pve-efiboot
>> +++ b/efiboot/zz-pve-efiboot
>> @@ -50,7 +50,8 @@ update_esps() {
>>  CMDLINE="$(cat /etc/kernel/cmdline)"
>>  else
>>  warn "No /etc/kernel/cmdline found - falling back to 
>> /proc/cmdline"
>> -CMDLINE="$(cat /proc/cmdline)"
>> +# remove initrd entries
>> +CMDLINE="$(cat /proc/cmdline | awk 
>> '{gsub(/initrd=([0-9a-zA-Z\\.-])*\s/,x)}1')"
> 
> could pontentially match a field which ends with initrd, e.g.,
> noinitrd=foo
> 
> while just an example that still should be caught..
> 
> also, this is a wrong use of cat, you could just do:
> "$(awk '...' /proc/cmdline)"
> 
> not point for the pipe..
> 
> now if the initrd= is _always_ the first one we could also do:
> "$(cut -d ' ' -f2- /proc/cmdline)"

there's potentially multiple initrd stanzas, and they can appear 
wherever in the cmdline..

> 
> but no hard feelings.
> 
>>  fi
>>  
>>  loop_esp_list update_esp_func
>> 
> 
> 
> ___
> 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


Re: [pve-devel] applied: [PATCH v3 kernel-meta] fix #2403: exclude initrd entries from /proc/cmdline

2019-10-17 Thread Fabian Grünbichler
On October 17, 2019 7:45 am, Thomas Lamprecht wrote:
> On 10/16/19 1:17 PM, Oguz Bektas wrote:
>> if we fallback to /proc/cmdline, it can include the booted initrd.
>> 
>> to avoid loader entries with initrd 'options' lines, we have to parse
>> them out.
>> 
>> Signed-off-by: Oguz Bektas 
>> ---
>> 
>> v2->v3:
>> * match forward slashes
>> * match underscore
>> * match zero or more whitespace at the end
>> 
>>  efiboot/zz-pve-efiboot | 3 ++-
>>  1 file changed, 2 insertions(+), 1 deletion(-)
>> 
>> diff --git a/efiboot/zz-pve-efiboot b/efiboot/zz-pve-efiboot
>> index 4756555..8771da9 100755
>> --- a/efiboot/zz-pve-efiboot
>> +++ b/efiboot/zz-pve-efiboot
>> @@ -50,7 +50,8 @@ update_esps() {
>>  CMDLINE="$(cat /etc/kernel/cmdline)"
>>  else
>>  warn "No /etc/kernel/cmdline found - falling back to 
>> /proc/cmdline"
>> -CMDLINE="$(cat /proc/cmdline)"
>> +# remove initrd entries
>> +CMDLINE="$(awk '{gsub(/\yinitrd=([0-9a-zA-Z\/\\._-])*\s*/,x)}1' 
>> /proc/cmdline)"
> 
> applied, but fixed up a few things, mostly style-wise so IMO no need for a v4:
> * add some spaces for separation, increasing readability
> * do not use the non-existent variable x as replacement, but an actual
>   empty string ""
> * don't use the "truth-y action" at end to make awk print the line ($0)
>   but explicitly print $0 after the gsub, makes it easier to get for
>   people with not much awk background ;)
> 
> thanks!

a bit late to the party unfortunately, but AFAICT it's also valid to 
have quoted parameter values with spaces inside - maybe it's worth a 
follow-up? not relevant for our generated ones, but maybe for manually 
built/added kernels..

also not sure whether plain ascii alpha-numeric is the proper choice for 
characters. we can also leave it as is until somebody reports actually 
running into either issue though ;)

> 
>>  fi
>>  
>>  loop_esp_list update_esp_func
>> 
> 
> 
> ___
> 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 02/23] add missing 'use PVE::Auth::Plugin'

2019-10-17 Thread Fabian Grünbichler
Signed-off-by: Fabian Grünbichler 
---
 PVE/API2/AccessControl.pm | 1 +
 1 file changed, 1 insertion(+)

diff --git a/PVE/API2/AccessControl.pm b/PVE/API2/AccessControl.pm
index dfbdfc6..9d2da8d 100644
--- a/PVE/API2/AccessControl.pm
+++ b/PVE/API2/AccessControl.pm
@@ -19,6 +19,7 @@ use PVE::API2::User;
 use PVE::API2::Group;
 use PVE::API2::Role;
 use PVE::API2::ACL;
+use PVE::Auth::Plugin;
 use PVE::OTP;
 use PVE::Tools;
 
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 1/23] API schema: add 'notoken' property

2019-10-17 Thread Fabian Grünbichler
to mark API methods which should not be available to clients authenticated 
using an API token

Signed-off-by: Fabian Grünbichler 
---

Notes:
if applied, any users of this need corresponding versioned depends.

 src/PVE/JSONSchema.pm | 5 +
 1 file changed, 5 insertions(+)

diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm
index db38d44..a42d814 100644
--- a/src/PVE/JSONSchema.pm
+++ b/src/PVE/JSONSchema.pm
@@ -1263,6 +1263,11 @@ my $method_schema = {
description => "Method needs special privileges - only pvedaemon 
can execute it",
optional => 1,
 },
+   notoken => {
+   type => 'boolean',
+   description => "Method is not available for clients authenticated 
using an API token.",
+   optional => 1,
+   },
 download => {
 type => 'boolean',
description => "Method downloads the file content (filename is the 
return value of the 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 04/23] user.cfg: sort ACL members

2019-10-17 Thread Fabian Grünbichler
Signed-off-by: Fabian Grünbichler 
---
 PVE/AccessControl.pm | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/PVE/AccessControl.pm b/PVE/AccessControl.pm
index 3e52c5f..aff9137 100644
--- a/PVE/AccessControl.pm
+++ b/PVE/AccessControl.pm
@@ -1135,11 +1135,11 @@ sub write_user_config {
}
 
foreach my $rolelist (sort keys %{$ra->{0}}) {
-   my $uglist = join (',', keys %{$ra->{0}->{$rolelist}});
+   my $uglist = join (',', sort keys %{$ra->{0}->{$rolelist}});
$data .= "acl:0:$path:$uglist:$rolelist:\n";
}
foreach my $rolelist (sort keys %{$ra->{1}}) {
-   my $uglist = join (',', keys %{$ra->{1}->{$rolelist}});
+   my $uglist = join (',', sort keys %{$ra->{1}->{$rolelist}});
$data .= "acl:1:$path:$uglist:$rolelist:\n";
}
 }
-- 
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 03/23] user.cfg: sort entries alphabetically in each section

2019-10-17 Thread Fabian Grünbichler
it's not required for dependencies (since those are only ever between
sections, and not within), but makes for easier diffing.

Signed-off-by: Fabian Grünbichler 
---
 PVE/AccessControl.pm | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/PVE/AccessControl.pm b/PVE/AccessControl.pm
index 6ea0b85..3e52c5f 100644
--- a/PVE/AccessControl.pm
+++ b/PVE/AccessControl.pm
@@ -1049,7 +1049,7 @@ sub write_user_config {
 
 my $data = '';
 
-foreach my $user (keys %{$cfg->{users}}) {
+foreach my $user (sort keys %{$cfg->{users}}) {
my $d = $cfg->{users}->{$user};
my $firstname = $d->{firstname} ? 
PVE::Tools::encode_text($d->{firstname}) : '';
my $lastname = $d->{lastname} ? PVE::Tools::encode_text($d->{lastname}) 
: '';
@@ -1063,7 +1063,7 @@ sub write_user_config {
 
 $data .= "\n";
 
-foreach my $group (keys %{$cfg->{groups}}) {
+foreach my $group (sort keys %{$cfg->{groups}}) {
my $d = $cfg->{groups}->{$group};
my $list = join (',', keys %{$d->{users}});
my $comment = $d->{comment} ? PVE::Tools::encode_text($d->{comment}) : 
'';
@@ -1072,7 +1072,7 @@ sub write_user_config {
 
 $data .= "\n";
 
-foreach my $pool (keys %{$cfg->{pools}}) {
+foreach my $pool (sort keys %{$cfg->{pools}}) {
my $d = $cfg->{pools}->{$pool};
my $vmlist = join (',', keys %{$d->{vms}});
my $storelist = join (',', keys %{$d->{storage}});
@@ -1082,7 +1082,7 @@ sub write_user_config {
 
 $data .= "\n";
 
-foreach my $role (keys %{$cfg->{roles}}) {
+foreach my $role (sort keys %{$cfg->{roles}}) {
next if $special_roles->{$role};
 
my $d = $cfg->{roles}->{$role};
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 07/23] auth: pull username REs into variables

2019-10-17 Thread Fabian Grünbichler
for reusage in API token ID format/verification

Signed-off-by: Fabian Grünbichler 
---
 PVE/Auth/Plugin.pm | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/PVE/Auth/Plugin.pm b/PVE/Auth/Plugin.pm
index 5c11991..6d59b72 100755
--- a/PVE/Auth/Plugin.pm
+++ b/PVE/Auth/Plugin.pm
@@ -27,7 +27,8 @@ sub lock_domain_config {
 }
 }
 
-my $realm_regex = qr/[A-Za-z][A-Za-z0-9\.\-_]+/;
+our $realm_regex = qr/[A-Za-z][A-Za-z0-9\.\-_]+/;
+our $user_regex = qr![^\s:/]+!;
 
 PVE::JSONSchema::register_format('pve-realm', \&pve_verify_realm);
 sub pve_verify_realm {
@@ -66,7 +67,7 @@ sub verify_username {
 # colon separated lists)!
 # slash is not allowed because it is used as pve API delimiter
 # also see "man useradd"
-if ($username =~ m!^([^\s:/]+)\@(${realm_regex})$!) {
+if ($username =~ m!^(${user_regex})\@(${realm_regex})$!) {
return wantarray ? ($username, $1, $2) : $username;
 }
 
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 09/23] API token: add REs, helpers, parsing + writing

2019-10-17 Thread Fabian Grünbichler
token definitions/references in user.cfg always use the full form of the
token id, consisting of:

USER@REALM!TOKENID

token definitions are represented by their own lines prefixed with
'token', which need to come after the corresponding user definition, but
before any ACLs referencing them.

parsed representation in a user config hash is inside a new 'tokens'
element of the corresponding user object, using the unique-per-user
token id as key.

only token metadata is stored inside user.cfg / accessible via the
parsed user config hash. the actual token values will be stored
root-readable only in a separate (shadow) file.

'enable', 'comment' and 'expire' have the same semantics as for users.
'privsep' determines whether an API token gets the full privileges of
the corresponding user, or just the intersection of privileges of the
corresponding user and those of the API token itself.

Signed-off-by: Fabian Grünbichler 
---

Notes:
I am a bit unsure how to differentiate in a clean way between:
A full userid/tokenid (username@realm OR username@real!token)
B user (username@realm)
C tokenid (username@realm!token)
D token/tokensubid/tokenid-per-user (just the part after !)

I am not sure whether it makes much sense to replace all the existing naming
where B becomes A with the introduction of tokens. it might make sense to 
have
some specific variable naming for those few places where we explicitly 
handle
the difference (A goes in, we check if it's B or C and do different stuff in
either case), as well as for cleanly separating between C and D. applies to
patches after this as well..

recommendations/input welcome ;)

 PVE/AccessControl.pm | 88 
 1 file changed, 88 insertions(+)

diff --git a/PVE/AccessControl.pm b/PVE/AccessControl.pm
index 48c9930..a43aab2 100644
--- a/PVE/AccessControl.pm
+++ b/PVE/AccessControl.pm
@@ -211,6 +211,45 @@ sub rotate_authkey {
 die $@ if $@;
 }
 
+our $token_subid_regex = $PVE::Auth::Plugin::realm_regex;
+
+# username@realm username realm tokenid
+our $token_full_regex = 
qr/((${PVE::Auth::Plugin::user_regex})\@(${PVE::Auth::Plugin::realm_regex}))!(${token_subid_regex})/;
+
+sub split_tokenid {
+my ($tokenid, $noerr) = @_;
+
+if ($tokenid =~ /^${token_full_regex}$/) {
+   return ($1, $4);
+}
+
+die "'$tokenid' is not a valid token ID - not able to split into user and 
token parts\n" if !$noerr;
+
+return undef;
+}
+
+sub join_tokenid {
+my ($username, $tokensubid) = @_;
+
+my $joined = "${username}!${tokensubid}";
+
+return pve_verify_tokenid($joined);
+}
+
+PVE::JSONSchema::register_format('pve-tokenid', \&pve_verify_tokenid);
+sub pve_verify_tokenid {
+my ($tokenid, $noerr) = @_;
+
+if ($tokenid =~ /^${token_full_regex}$/) {
+   return wantarray ? ($tokenid, $2, $3, $4) : $tokenid;
+}
+
+die "value '$tokenid' does not look like a valid token ID\n" if !$noerr;
+
+return undef;
+}
+
+
 my $csrf_prevention_secret;
 my $csrf_prevention_secret_legacy;
 my $get_csrfr_secret = sub {
@@ -988,6 +1027,12 @@ sub parse_user_config {
} else {
warn "user config - ignore invalid acl member 
'$ug'\n";
}
+   } elsif (my ($user, $token) = split_tokenid($ug, 1)) {
+   if ($cfg->{users}->{$user}->{tokens}->{$token}) { # 
token exists
+   $cfg->{acl}->{$path}->{tokens}->{$ug}->{$role} 
= $propagate;
+   } else {
+   warn "user config - ignore invalid acl token 
'$ug'\n";
+   }
} else {
warn "user config - invalid user/group '$ug' in 
acl\n";
}
@@ -1034,6 +1079,36 @@ sub parse_user_config {
}
$cfg->{pools}->{$pool}->{storage}->{$storeid} = 1;
}
+   } elsif ($et eq 'token') {
+   my ($tokenid, $enable, $expire, $privsep, $comment) = @data;
+
+   my ($user, $token) = split_tokenid($tokenid, 1);
+   if (!($user && $token)) {
+   warn "user config - ignore invalid tokenid '$tokenid'\n";
+   next;
+   }
+
+   $enable = $enable ? 1 : 0;
+   $privsep = $privsep ? 1 : 0;
+
+   $expire = 0 if !$expire;
+
+   if ($expire !~ m/^\d+$/) {
+   warn "user config - ignore token '$tokenid' - (illegal 
characters in expire '$expire')\n";
+   next;
+   }
+   $expire = int($expire);
+

[pve-devel] [PATCH 16/23] proxy_request: drop duplicate, unused parameter

2019-10-17 Thread Fabian Grünbichler
which was mistakenly added back when this was still in pve-manager.

Signed-off-by: Fabian Grünbichler 
---
 PVE/APIServer/AnyEvent.pm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/PVE/APIServer/AnyEvent.pm b/PVE/APIServer/AnyEvent.pm
index c1dade8..9aba27d 100644
--- a/PVE/APIServer/AnyEvent.pm
+++ b/PVE/APIServer/AnyEvent.pm
@@ -747,7 +747,7 @@ sub handle_api2_request {
$res->{proxy_params}->{tmpfilename} = $reqstate->{tmpfilename} if 
$upload_state;
 
$self->proxy_request($reqstate, $clientip, $host, 
$res->{proxynode}, $method,
-$r->uri, $auth->{ticket}, $auth->{token}, 
$res->{proxy_params}, $res->{proxynode});
+$r->uri, $auth->{ticket}, $auth->{token}, 
$res->{proxy_params});
return;
 
} elsif ($upgrade && ($method eq 'GET') && ($path =~ m|websocket$|)) {
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 10/23] API token: add API helpers

2019-10-17 Thread Fabian Grünbichler
the _exist/_enabled are modelled after the corresponding user methods.
the 'tokenid' option goes into PVE::AccessControl, since we need it in
multiple API modules.

Signed-off-by: Fabian Grünbichler 
---
 PVE/AccessControl.pm | 32 
 1 file changed, 32 insertions(+)

diff --git a/PVE/AccessControl.pm b/PVE/AccessControl.pm
index a43aab2..432ccc0 100644
--- a/PVE/AccessControl.pm
+++ b/PVE/AccessControl.pm
@@ -211,6 +211,12 @@ sub rotate_authkey {
 die $@ if $@;
 }
 
+PVE::JSONSchema::register_standard_option('tokenid', {
+description => "API token identifier.",
+type => "string",
+format => "pve-tokenid",
+});
+
 our $token_subid_regex = $PVE::Auth::Plugin::realm_regex;
 
 # username@realm username realm tokenid
@@ -531,6 +537,32 @@ sub check_user_enabled {
 return undef;
 }
 
+sub check_token_exist {
+my ($usercfg, $username, $tokenid, $noerr) = @_;
+
+my $user = check_user_exist($usercfg, $username, $noerr);
+return undef if !$user;
+
+return $user->{tokens}->{$tokenid} if $user->{tokens}->{$tokenid};
+
+die "no such token ('$tokenid') for user ('$username')\n" if !$noerr;
+
+return undef;
+}
+
+sub check_token_enabled {
+my ($usercfg, $username, $tokenid, $noerr) = @_;
+
+my $data = check_token_exist($usercfg, $username, $tokenid, $noerr);
+return undef if !$data;
+
+return 1 if $data->{enable};
+
+die "token '$tokenid' for user '$username' is disabled\n" if !$noerr;
+
+return undef;
+}
+
 sub verify_one_time_pw {
 my ($type, $username, $keys, $tfa_cfg, $otp) = @_;
 
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 08/23] refactor acl transformation code

2019-10-17 Thread Fabian Grünbichler
pull it into helper sub, since we need this one more time for token ACL
members.

Signed-off-by: Fabian Grünbichler 
---
 PVE/AccessControl.pm | 61 +++-
 1 file changed, 26 insertions(+), 35 deletions(-)

diff --git a/PVE/AccessControl.pm b/PVE/AccessControl.pm
index a84173e..48c9930 100644
--- a/PVE/AccessControl.pm
+++ b/PVE/AccessControl.pm
@@ -1092,47 +1092,38 @@ sub write_user_config {
 
 $data .= "\n";
 
+my $collect_ra = sub {
+   my ($acl_members, $ra, $prefix, $exclude) = @_;
+
+   foreach my $member (keys %$acl_members) {
+   next if $exclude && $member eq $exclude;
+
+   my $l0 = '';
+   my $l1 = '';
+   foreach my $role (sort keys %{$acl_members->{$member}}) {
+   my $propagate = $acl_members->{$member}->{$role};
+   if ($propagate) {
+   $l1 .= ',' if $l1;
+   $l1 .= $role;
+   } else {
+   $l0 .= ',' if $l0;
+   $l0 .= $role;
+   }
+   }
+   $ra->{0}->{$l0}->{"${prefix}${member}"} = 1 if $l0;
+   $ra->{1}->{$l1}->{"${prefix}${member}"} = 1 if $l1;
+   }
+};
+
 foreach my $path (sort keys %{$cfg->{acl}}) {
my $d = $cfg->{acl}->{$path};
 
my $ra = {};
 
-   foreach my $group (keys %{$d->{groups}}) {
-   my $l0 = '';
-   my $l1 = '';
-   foreach my $role (sort keys %{$d->{groups}->{$group}}) {
-   my $propagate = $d->{groups}->{$group}->{$role};
-   if ($propagate) {
-   $l1 .= ',' if $l1;
-   $l1 .= $role;
-   } else {
-   $l0 .= ',' if $l0;
-   $l0 .= $role;
-   }
-   }
-   $ra->{0}->{$l0}->{"\@$group"} = 1 if $l0;
-   $ra->{1}->{$l1}->{"\@$group"} = 1 if $l1;
-   }
+   $collect_ra->($d->{'groups'}, $ra, '@');
 
-   foreach my $user (keys %{$d->{users}}) {
-   # no need to save, because root is always 'Administrator'
-   next if $user eq 'root@pam';
-
-   my $l0 = '';
-   my $l1 = '';
-   foreach my $role (sort keys %{$d->{users}->{$user}}) {
-   my $propagate = $d->{users}->{$user}->{$role};
-   if ($propagate) {
-   $l1 .= ',' if $l1;
-   $l1 .= $role;
-   } else {
-   $l0 .= ',' if $l0;
-   $l0 .= $role;
-   }
-   }
-   $ra->{0}->{$l0}->{$user} = 1 if $l0;
-   $ra->{1}->{$l1}->{$user} = 1 if $l1;
-   }
+   # no need to save 'root@pam', it is always 'Administrator'
+   $collect_ra->($d->{'users'}, $ra, '', 'root@pam');
 
foreach my $rolelist (sort keys %{$ra->{0}}) {
my $uglist = join (',', sort keys %{$ra->{0}->{$rolelist}});
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 12/23] API: add API token API endpoints

2019-10-17 Thread Fabian Grünbichler
and integration for user API endpoints.

Signed-off-by: Fabian Grünbichler 
---

Notes:
pveum integration will come in a future version, but

pveum token add/modify/delete   [OPTIONS]

or

pveum user token add/modify/delete   [OPTIONS]

seem like likely candidates.

 PVE/API2/User.pm | 287 ++-
 1 file changed, 284 insertions(+), 3 deletions(-)

diff --git a/PVE/API2/User.pm b/PVE/API2/User.pm
index fb5b22a..1646418 100644
--- a/PVE/API2/User.pm
+++ b/PVE/API2/User.pm
@@ -2,9 +2,9 @@ package PVE::API2::User;
 
 use strict;
 use warnings;
-use PVE::Exception qw(raise raise_perm_exc);
+use PVE::Exception qw(raise raise_perm_exc raise_param_exc);
 use PVE::Cluster qw (cfs_read_file cfs_write_file);
-use PVE::Tools qw(split_list);
+use PVE::Tools qw(split_list extract_param);
 use PVE::AccessControl;
 use PVE::JSONSchema qw(get_standard_option register_standard_option);
 
@@ -40,6 +40,39 @@ register_standard_option('group-list', {
 optional => 1,
 completion => \&PVE::AccessControl::complete_group,
 });
+register_standard_option('token-subid', {
+type => 'string',
+pattern => $PVE::AccessControl::token_subid_regex,
+description => 'User-specific token identifier.',
+});
+register_standard_option('token-enable', {
+description => "Enable the API token (default). You can set this to '0' to 
disable this specific token.",
+type => 'boolean',
+optional => 1,
+default => 1,
+});
+register_standard_option('token-expire', {
+description => "API token expiration date (seconds since epoch). '0' means 
no expiration date.",
+type => 'integer',
+minimum => 0,
+optional => 1,
+});
+register_standard_option('token-privsep', {
+description => "Restrict API token privileges with separate ACLs 
(default), or give full privileges of corresponding user.",
+type => 'boolean',
+optional => 1,
+default => 1,
+});
+register_standard_option('token-comment', { type => 'string', optional => 1 });
+register_standard_option('token-info', {
+type => 'object',
+properties => {
+   enable => get_standard_option('token-enable'),
+   expire => get_standard_option('token-expire'),
+   privsep => get_standard_option('token-privsep'),
+   comment => get_standard_option('token-comment'),
+}
+});
 
 my $extract_user_data = sub {
 my ($data, $full) = @_;
@@ -53,6 +86,7 @@ my $extract_user_data = sub {
 return $res if !$full;
 
 $res->{groups} = $data->{groups} ? [ keys %{$data->{groups}} ] : [];
+$res->{tokens} = $data->{tokens} ? [ keys %{$data->{tokens}} ] : [];
 
 return $res;
 };
@@ -228,7 +262,17 @@ __PACKAGE__->register_method ({
email => get_standard_option('user-email'),
comment => get_standard_option('user-comment'),
keys => get_standard_option('user-keys'),
-   groups => { type => 'array' },
+   groups => {
+   type => 'array',
+   items => {
+   type => 'string',
+   format => 'pve-groupid',
+   },
+   },
+   tokens => {
+   type => 'array',
+   items => get_standard_option('token-subid'),
+   },
},
type => "object"
 },
@@ -428,4 +472,241 @@ __PACKAGE__->register_method ({
return $res;
 }});
 
+my $token_info_extend = sub {
+my ($props) = @_;
+
+my $obj = get_standard_option('token-info');
+my $base_props = $obj->{properties};
+$obj->{properties} = {};
+
+foreach my $prop (keys %$base_props) {
+   $obj->{properties}->{$prop} = $base_props->{$prop};
+}
+
+foreach my $add_prop (keys %$props) {
+   $obj->{properties}->{$add_prop} = $props->{$add_prop};
+}
+
+return $obj;
+};
+
+__PACKAGE__->register_method ({
+name => 'token_index',
+path => '{userid}/token',
+method => 'GET',
+description => "Get user API tokens.",
+permissions => {
+   check => ['userid-param', 'self'],
+},
+parameters => {
+   additionalProperties => 0,
+   properties => {
+   userid => get_standard_option('userid-completed'),
+   },
+},
+returns => {
+   type => "array",
+   items => $token_info_extend->({
+   tokenid =&

[pve-devel] [RFC 06/23] rpcenv: drop unused roles()

2019-10-17 Thread Fabian Grünbichler
it doesn't really serve a purpose, and it's not called anywhere in the codebase.

Signed-off-by: Fabian Grünbichler 
---

Notes:
alternatively, we can give this the same semantics w.r.t. tokens as
PVE::AccessControl::roles, but with pool roles mixed in via
$compile_acl_path->()

 PVE/AccessControl.pm  |  2 +-
 PVE/RPCEnvironment.pm | 23 ---
 2 files changed, 1 insertion(+), 24 deletions(-)

diff --git a/PVE/AccessControl.pm b/PVE/AccessControl.pm
index f246c85..a84173e 100644
--- a/PVE/AccessControl.pm
+++ b/PVE/AccessControl.pm
@@ -1209,7 +1209,7 @@ sub roles {
 my ($cfg, $user, $path) = @_;
 
 # NOTE: we do not consider pools here.
-# You need to use $rpcenv->roles() instead if you want that.
+# Use $rpcenv->permission() for any actual permission checks!
 
 return 'Administrator' if $user eq 'root@pam'; # root can do anything
 
diff --git a/PVE/RPCEnvironment.pm b/PVE/RPCEnvironment.pm
index 95d3029..7e0af70 100644
--- a/PVE/RPCEnvironment.pm
+++ b/PVE/RPCEnvironment.pm
@@ -81,29 +81,6 @@ my $compile_acl_path = sub {
 return $privs;
 };
 
-sub roles {
-   my ($self, $user, $path) = @_;
-
-   if ($user eq 'root@pam') { # root can do anything
-   return ('Administrator');
-   }
-
-   $user = PVE::AccessControl::verify_username($user, 1);
-   return () if !$user;
-
-   my $cache = $self->{aclcache};
-   $cache->{$user} = {} if !$cache->{$user};
-
-   my $acl = $cache->{$user};
-
-   my $roles = $acl->{roles}->{$path};
-   return @$roles if $roles;
-
-   &$compile_acl_path($self, $user, $path);
-   $roles = $acl->{roles}->{$path} || [];
-   return @$roles;
-}
-
 sub permissions {
 my ($self, $user, $path) = @_;
 
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 11/23] DO NOT APPLY: API token stubs for token value handling

2019-10-17 Thread Fabian Grünbichler
two proposed implementation sites so far:
- pmxcfs (accessible via IPCC)
- stand-alone root daemon/setuid binary

two proposed token formats so far:
- plain UUID
- hash/crypt of UUID(+salt)

in both cases the UUID would be provided as token to the user, the
latter format would provide a bit of protection against brute-forcing in
case the shadow file leaks, but makes verification more expensive.

I'd like to focus on the big picture/API structure/API integration for
this initial RFC v1 (hence just the stubs), but feedback on these
variants is of course already welcome as well ;)

Signed-off-by: Fabian Grünbichler 
---
 PVE/AccessControl.pm | 47 
 1 file changed, 47 insertions(+)

diff --git a/PVE/AccessControl.pm b/PVE/AccessControl.pm
index 432ccc0..b5dfe4b 100644
--- a/PVE/AccessControl.pm
+++ b/PVE/AccessControl.pm
@@ -397,6 +397,39 @@ sub verify_ticket {
 return wantarray ? ($username, $age, $tfa_info) : $username;
 }
 
+# API Tokens
+sub verify_token {
+my ($api_token) = @_;
+
+die "no API token specified\n" if !$api_token;
+
+my ($tokenid, $value);
+if ($api_token =~ /^($token_full_regex)=(.*)$/) {
+   $tokenid = $1;
+   $value = $2;
+} else {
+   die "no tokenid specified\n";
+}
+
+my ($username, $token) = split_tokenid($tokenid);
+
+my $usercfg = cfs_read_file('user.cfg');
+check_user_enabled($usercfg, $username);
+check_token_enabled($usercfg, $username, $token);
+
+my $ctime = time();
+
+my $user = $usercfg->{users}->{$username};
+die "account expired\n" if $user->{expire} && ($user->{expire} < $ctime);
+
+my $token_info = $user->{tokens}->{$token};
+die "token expired\n" if $token_info->{expire} && ($token_info->{expire} < 
$ctime);
+
+# FIXME: actually implement token verification here
+return wantarray ? ($tokenid) : $tokenid;
+}
+
+
 # VNC tickets
 # - they do not contain the username in plain text
 # - they are restricted to a specific resource path (example: '/vms/100')
@@ -1578,6 +1611,20 @@ sub user_get_tfa {
 }
 }
 
+# FIXME: actually implement token generation here
+sub generate_token {
+my ($tokenid) = @_;
+
+return "${tokenid}_VALUE";
+}
+
+# FIXME: actually implement token deletion here
+sub delete_token {
+my ($tokenid) = @_;
+
+return;
+}
+
 # bash completion helpers
 
 register_standard_option('userid-completed',
-- 
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 17/23] allow ticket in auth header as fallback

2019-10-17 Thread Fabian Grünbichler
based on idea & RFC by Tim Marx, incorporating feedback by Thomas
Lamprecht. this will be extended to support API tokens in the
Authorization header as well, so make it generic.

Signed-off-by: Fabian Grünbichler 
---

Notes:
semi-independent, could also leave extract_auth_cookie as alias/wrapper to
avoid a change in PMG. but since we need to change other method signatures
anyway for the token part, we could change this as well.

as-is, needs a versioned breaks/depends on pve-manager and some part of PMG?

 PVE/APIServer/AnyEvent.pm  |  5 -
 PVE/APIServer/Formatter.pm | 12 ++--
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/PVE/APIServer/AnyEvent.pm b/PVE/APIServer/AnyEvent.pm
index 9aba27d..c0b90ab 100644
--- a/PVE/APIServer/AnyEvent.pm
+++ b/PVE/APIServer/AnyEvent.pm
@@ -1232,7 +1232,10 @@ sub unshift_read_header {
} elsif ($path =~ m/^\Q$base_uri\E/) {
my $token = $r->header('CSRFPreventionToken');
my $cookie = $r->header('Cookie');
-   my $ticket = 
PVE::APIServer::Formatter::extract_auth_cookie($cookie, $self->{cookie_name});
+   my $auth_header = $r->header('Authorization');
+   my $ticket = 
PVE::APIServer::Formatter::extract_auth_value($cookie, $self->{cookie_name});
+   $ticket = 
PVE::APIServer::Formatter::extract_auth_value($auth_header, 
$self->{cookie_name})
+   if !$ticket;
 
my ($rel_uri, $format) = &$split_abs_uri($path, 
$self->{base_uri});
if (!$format) {
diff --git a/PVE/APIServer/Formatter.pm b/PVE/APIServer/Formatter.pm
index 0c459bd..def1932 100644
--- a/PVE/APIServer/Formatter.pm
+++ b/PVE/APIServer/Formatter.pm
@@ -75,16 +75,16 @@ sub get_login_formatter {
 
 # some helper functions
 
-sub extract_auth_cookie {
-my ($cookie, $cookie_name) = @_;
+sub extract_auth_value {
+my ($header, $key) = @_;
 
-return undef if !$cookie;
+return undef if !$header;
 
-my $ticket = ($cookie =~ /(?:^|\s)\Q$cookie_name\E=([^;]*)/)[0];
+my $value = ($header =~ /(?:^|\s)\Q$key\E(?:=| )([^;]*)/)[0];
 
-$ticket = uri_unescape($ticket) if $ticket;
+$value = uri_unescape($value) if $value;
 
-return $ticket;
+return $value;
 }
 
 sub create_auth_cookie {
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC/PATCH 0/23] API Tokens

2019-10-17 Thread Fabian Grünbichler
This is a draft of a patch series which aims to introduce API tokens
into PVE.

The basic idea is to allow users to generate API token values that
- are attributed to this users
- easily revokable
- possibly less privileged than the user itself
- allow direct API calls without round-trips to create/refresh a ticket

Token information is stored in user.cfg together with the other
access-control information. The actual token values will be stored in a
'shadow' file under /etc/pve/priv (see patch #12 for some
ideas/comments).

Still missing:
- thorough review ;)
- adaption/extension of user.cfg tests (especially w.r.t. #6/7)
- PVE::APIClient support
- token value generation, deletion & verification (#12)
- pveum integration
- GUI integration (just the token API, not using tokens for login..)
- documentation
- PMG adaption (at least for the changed method signatures in
  pve-http-server)
- checking API endpoints for 'notoken'-ification

I tried to order independent clean-ups etc. up front with-in each repo,
but some of them require versioned breaks/depends so it might make sense
to wait for the full series for those.

pve-common:

Fabian Grünbichler (1):
  API schema: add 'notoken' property

 src/PVE/JSONSchema.pm | 5 +
 1 file changed, 5 insertions(+)

pve-access-control:

Fabian Grünbichler (14):
  add missing 'use PVE::Auth::Plugin'
  user.cfg: sort entries alphabetically in each section
  user.cfg: sort ACL members
  access-control: remove check_permissions/permission
  rpcenv: drop unused roles()
  auth: pull username REs into variables
  refactor acl transformation code
  API token: add REs, helpers, parsing + writing
  API token: add API helpers
  DO NOT APPLY: API token stubs for token value handling
  API: add API token API endpoints
  API: include API tokens in ACL API endpoints
  API token: implement permission checks
  api: mark some paths notoken

 PVE/API2/ACL.pm   |  30 +++-
 PVE/API2/AccessControl.pm |   5 +
 PVE/API2/User.pm  | 287 ++-
 PVE/AccessControl.pm  | 307 --
 PVE/Auth/Plugin.pm|   5 +-
 PVE/RPCEnvironment.pm |  50 +++
 6 files changed, 568 insertions(+), 116 deletions(-)

pve-http-server:

Fabian Grünbichler (2):
  proxy_request: drop duplicate, unused parameter
  allow ticket in auth header as fallback
  api-server: extract, set and handle API token header

 PVE/APIServer/AnyEvent.pm| 27 +++
 PVE/APIServer/Formatter.pm   | 21 +++--
 PVE/APIServer/Formatter/Bootstrap.pm |  1 +
 3 files changed, 35 insertions(+), 14 deletions(-)

pve-manager:

Fabian Grünbichler (5):
  subscription: use rpcenv for permission check
  auth_handler: handle API tokens
  rest_handler: implement 'notoken' API endpoints
  pveproxy: use new cookie extraction method
  api/tasks: attribute token tasks to user

 PVE/API2/Cluster.pm  |  3 ++
 PVE/API2/Subscription.pm |  2 +-
 PVE/API2/Tasks.pm| 15 ++
 PVE/HTTPServer.pm| 60 +++-
 PVE/Service/pveproxy.pm  |  2 +-
 5 files changed, 54 insertions(+), 28 deletions(-)

-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 15/23] api: mark some paths notoken

2019-10-17 Thread Fabian Grünbichler
Signed-off-by: Fabian Grünbichler 
---

Notes:
requires versioned dependency on libpve-common-perl

 PVE/API2/AccessControl.pm | 4 
 1 file changed, 4 insertions(+)

diff --git a/PVE/API2/AccessControl.pm b/PVE/API2/AccessControl.pm
index 9d2da8d..2a52105 100644
--- a/PVE/API2/AccessControl.pm
+++ b/PVE/API2/AccessControl.pm
@@ -234,6 +234,7 @@ __PACKAGE__->register_method ({
user => 'world' 
 },
 protected => 1, # else we can't access shadow files
+notoken => 1, # we don't want tokens to create tickets
 description => "Create or verify authentication ticket.",
 parameters => {
additionalProperties => 0,
@@ -347,6 +348,7 @@ __PACKAGE__->register_method ({
],
 },
 protected => 1, # else we can't access shadow files
+notoken => 1, # we don't want tokens to change the regular user password
 description => "Change user password.",
 parameters => {
additionalProperties => 0,
@@ -479,6 +481,7 @@ __PACKAGE__->register_method ({
],
 },
 protected => 1, # else we can't access shadow files
+notoken => 1, # we don't want tokens to change the regular user's TFA 
settings
 description => "Change user u2f authentication.",
 parameters => {
additionalProperties => 0,
@@ -605,6 +608,7 @@ __PACKAGE__->register_method({
 method => 'POST',
 permissions => { user => 'all' },
 protected => 1, # else we can't access shadow files
+notoken => 1, # we don't want tokens to access TFA information
 description => 'Finish a u2f challenge.',
 parameters => {
additionalProperties => 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] [RFC 13/23] API: include API tokens in ACL API endpoints

2019-10-17 Thread Fabian Grünbichler
Signed-off-by: Fabian Grünbichler 
---
 PVE/API2/ACL.pm | 30 ++
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/PVE/API2/ACL.pm b/PVE/API2/ACL.pm
index 3e42ac0..c340267 100644
--- a/PVE/API2/ACL.pm
+++ b/PVE/API2/ACL.pm
@@ -46,7 +46,7 @@ __PACKAGE__->register_method ({
properties => {
propagate => get_standard_option('acl-propagate'),
path => get_standard_option('acl-path'),
-   type => { type => 'string', enum => ['user', 'group'] },
+   type => { type => 'string', enum => ['user', 'group', 'token'] 
},
ugid => { type => 'string' },
roleid => { type => 'string' },
},
@@ -68,8 +68,8 @@ __PACKAGE__->register_method ({
 
my $acl = $usercfg->{acl};
foreach my $path (keys %$acl) {
-   foreach my $type (qw(users groups)) {
-   my $d = $acl->{$path}->{$type};
+   foreach my $type (qw(user group token)) {
+   my $d = $acl->{$path}->{"${type}s"};
next if !$d;
next if !($audit || $rpcenv->check_perm_modify($authuser, 
$path, 1));
foreach my $id (keys %$d) {
@@ -77,7 +77,7 @@ __PACKAGE__->register_method ({
my $propagate = $d->{$id}->{$role};
push @$res, {
path => $path,
-   type => $type eq 'groups' ? 'group' : 'user',
+   type => $type,
ugid => $id,
roleid => $role,
propagate => $propagate,
@@ -114,6 +114,11 @@ __PACKAGE__->register_method ({
type => 'string', format => 'pve-groupid-list',
optional => 1,
},
+   tokens => {
+   description => "List of API tokens.",
+   type => 'string', format => 'pve-tokenid-list',
+   optional => 1,
+   },
roles => {
description => "List of roles.",
type => 'string', format => 'pve-roleid-list',
@@ -129,10 +134,8 @@ __PACKAGE__->register_method ({
 code => sub {
my ($param) = @_;
 
-   if (!($param->{users} || $param->{groups})) {
-   raise_param_exc({
-   users => "either 'users' or 'groups' is required.",
-   groups => "either 'users' or 'groups' is required." });
+   if (!($param->{users} || $param->{groups} || $param->{tokens})) {
+   raise_param_exc({ map { $_ => "either 'users', 'groups' or 'tokens' 
is required." } qw(users groups tokens) });
}
 
my $path = PVE::AccessControl::normalize_path($param->{path});
@@ -177,6 +180,17 @@ __PACKAGE__->register_method ({
$cfg->{acl}->{$path}->{users}->{$username}->{$role} 
= $propagate;
}
}
+
+   foreach my $tokenid (split_list($param->{tokens})) {
+   my ($username, $token) = 
PVE::AccessControl::split_tokenid($tokenid);
+   PVE::AccessControl::check_token_exist($cfg, $username, 
$token);
+
+   if ($param->{delete}) {
+   delete 
$cfg->{acl}->{$path}->{tokens}->{$tokenid}->{$role};
+   } else {
+   $cfg->{acl}->{$path}->{tokens}->{$tokenid}->{$role} 
= $propagate;
+   }
+   }
}
 
cfs_write_file("user.cfg", $cfg);
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 05/23] access-control: remove check_permissions/permission

2019-10-17 Thread Fabian Grünbichler
they have been handled by PVE::RPCEnvironment for quite some time
already, and the versions there are the complete ones that should be
actually used.

Signed-off-by: Fabian Grünbichler 
---

Notes:
this requires the corresponding patch for and a versioned breaks on
pve-manager, where a call to check_permissions has been introduced in 
2018(!?).

 PVE/AccessControl.pm | 37 -
 1 file changed, 37 deletions(-)

diff --git a/PVE/AccessControl.pm b/PVE/AccessControl.pm
index aff9137..f246c85 100644
--- a/PVE/AccessControl.pm
+++ b/PVE/AccessControl.pm
@@ -1273,43 +1273,6 @@ sub roles {
 return @ra;
 }
 
-sub permission {
-my ($cfg, $user, $path) = @_;
-
-$user = PVE::Auth::Plugin::verify_username($user, 1);
-return {} if !$user;
-
-my @ra = roles($cfg, $user, $path);
-
-my $privs = {};
-
-foreach my $role (@ra) {
-   if (my $privset = $cfg->{roles}->{$role}) {
-   foreach my $p (keys %$privset) {
-   $privs->{$p} = 1;
-   }
-   }
-}
-
-#print "priviledges $user $path = " . Dumper ($privs);
-
-return $privs;
-}
-
-sub check_permissions {
-my ($username, $path, $privlist) = @_;
-
-$path = normalize_path($path);
-my $usercfg = cfs_read_file('user.cfg');
-my $perm = permission($usercfg, $username, $path);
-
-foreach my $priv (split_list($privlist)) {
-   return undef if !$perm->{$priv};
-};
-
-return 1;
-}
-
 sub remove_vm_access {
 my ($vmid) = @_;
 my $delVMaccessFn = sub {
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 21/23] rest_handler: implement 'notoken' API endpoints

2019-10-17 Thread Fabian Grünbichler
that are not available with API tokens for security reasons, such as access 
control related endpoints.

Signed-off-by: Fabian Grünbichler 
---

Notes:
pairs with patch in pve-common that adds this to the schema-schema. any 
modules
setting that flag need a corresponding versioned depends on
libpve-common-perl..

 PVE/HTTPServer.pm | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/PVE/HTTPServer.pm b/PVE/HTTPServer.pm
index c11b4813..b45c3262 100755
--- a/PVE/HTTPServer.pm
+++ b/PVE/HTTPServer.pm
@@ -7,7 +7,7 @@ use PVE::SafeSyslog;
 use PVE::INotify;
 use PVE::Tools;
 use PVE::APIServer::AnyEvent;
-use PVE::Exception qw(raise_param_exc raise);
+use PVE::Exception qw(raise_param_exc raise_perm_exc raise);
 
 use PVE::RPCEnvironment;
 use PVE::AccessControl;
@@ -147,6 +147,9 @@ sub rest_handler {
$uri_param->{$p} = $params->{$p};
}
 
+   raise_perm_exc("URI '$rel_uri' not available with API token, need 
proper ticket.\n")
+   if $auth->{api_token} && $info->{notoken};
+
# check access permissions
$rpcenv->check_api2_permissions($info->{permissions}, $auth->{userid}, 
$uri_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 19/23] subscription: use rpcenv for permission check

2019-10-17 Thread Fabian Grünbichler
this is the last caller of PVE::AccessControl::check_permissions(),
which is the last caller of PVE::AccessControl::permission(). both can
thus be dropped altogether.

Signed-off-by: Fabian Grünbichler 
---

Notes:
this is semi-independent, but if applied we need to remember that the
corresponding patch in pve-access-control needs to break on pve-manager with
the right version

 PVE/API2/Subscription.pm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/PVE/API2/Subscription.pm b/PVE/API2/Subscription.pm
index 2c0c4e84..959c2c1b 100644
--- a/PVE/API2/Subscription.pm
+++ b/PVE/API2/Subscription.pm
@@ -108,7 +108,7 @@ __PACKAGE__->register_method ({
 
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
-   my $has_permission = PVE::AccessControl::check_permissions($authuser, 
"/nodes/$node", 'Sys.Audit');
+   my $has_permission = $rpcenv->check($authuser, "/nodes/$node", 
['Sys.Audit'], 1);
 
my $server_id = PVE::API2Tools::get_hwaddress();
my $url = "https://www.proxmox.com/proxmox-ve/pricing";;
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 14/23] API token: implement permission checks

2019-10-17 Thread Fabian Grünbichler
non-privsep tokens will always return the roles/permissions of their
associated users. privsep tokens will return unfiltered roles, but
filtered permissions.

Signed-off-by: Fabian Grünbichler 
---
 PVE/AccessControl.pm  | 30 ++
 PVE/RPCEnvironment.pm | 27 +--
 2 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/PVE/AccessControl.pm b/PVE/AccessControl.pm
index b5dfe4b..0e7f1f7 100644
--- a/PVE/AccessControl.pm
+++ b/PVE/AccessControl.pm
@@ -1353,10 +1353,25 @@ sub roles {
 my ($cfg, $user, $path) = @_;
 
 # NOTE: we do not consider pools here.
+# NOTE: for privsep tokens, this does not filter roles by those that the
+# corresponding user has.
 # Use $rpcenv->permission() for any actual permission checks!
 
 return 'Administrator' if $user eq 'root@pam'; # root can do anything
 
+if (pve_verify_tokenid($user, 1)) {
+   my $tokenid = $user;
+   my ($username, $token) = split_tokenid($tokenid);
+
+   my $token_info = $cfg->{users}->{$username}->{tokens}->{$token};
+   return () if !$token_info;
+
+   my @user_roles = roles($cfg, $username, $path);
+
+   # return full user privileges
+   return @user_roles if !$token_info->{privsep};
+}
+
 my $perm = {};
 
 foreach my $p (sort keys %{$cfg->{acl}}) {
@@ -1368,6 +1383,21 @@ sub roles {
 
#print "CHECKACL $path $p\n";
#print "ACL $path = " . Dumper ($acl);
+   if (my $ri = $acl->{tokens}->{$user}) {
+   my $new;
+   foreach my $role (keys %$ri) {
+   my $propagate = $ri->{$role};
+   if ($final || $propagate) {
+   #print "APPLY ROLE $p $user $role\n";
+   $new = {} if !$new;
+   $new->{$role} = 1;
+   }
+   }
+   if ($new) {
+   $perm = $new; # overwrite previous settings
+   next;
+   }
+   }
 
if (my $ri = $acl->{users}->{$user}) {
my $new;
diff --git a/PVE/RPCEnvironment.pm b/PVE/RPCEnvironment.pm
index 7e0af70..f378522 100644
--- a/PVE/RPCEnvironment.pm
+++ b/PVE/RPCEnvironment.pm
@@ -30,6 +30,9 @@ my $compile_acl_path = sub {
 $cache->{$user} = {} if !$cache->{$user};
 my $data = $cache->{$user};
 
+my ($username, undef) = PVE::AccessControl::split_tokenid($user, 1);
+die "internal error" if $username && !defined($cache->{$username});
+
 if (!$data->{poolroles}) {
$data->{poolroles} = {};
 
@@ -76,6 +79,13 @@ my $compile_acl_path = sub {
}
}
 }
+
+if ($username) {
+   # intersect user and token permissions
+   my $user_privs = $cache->{$username}->{privs}->{$path};
+   $privs = { map { $_ => 1 } grep { $user_privs->{$_} } keys %$privs };
+}
+
 $data->{privs}->{$path} = $privs;
 
 return $privs;
@@ -89,8 +99,21 @@ sub permissions {
return $cfg->{roles}->{'Administrator'};
 }
 
-$user = PVE::AccessControl::verify_username($user, 1);
-return {} if !$user;
+if (PVE::AccessControl::pve_verify_tokenid($user, 1)) {
+   my ($username, $token) = PVE::AccessControl::split_tokenid($user);
+   my $cfg = $self->{user_cfg};
+   my $token_info = $cfg->{users}->{$username}->{tokens}->{$token};
+   return {} if !$token_info;
+
+   # ensure cache for user is populated
+   my $user_perms = $self->permissions($username, $path);
+
+   # return user privs for non-privsep tokens
+   return $user_perms if !$token_info->{privsep};
+} else {
+   $user = PVE::AccessControl::verify_username($user, 1);
+   return {} if !$user;
+}
 
 my $cache = $self->{aclcache};
 $cache->{$user} = {} if !$cache->{$user};
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 18/23] api-server: extract, set and handle API token header

2019-10-17 Thread Fabian Grünbichler
Signed-off-by: Fabian Grünbichler 
---

Notes:
versioned breaks/depends with pve-manager and part of PMG?

 PVE/APIServer/AnyEvent.pm| 22 +++---
 PVE/APIServer/Formatter.pm   |  9 +
 PVE/APIServer/Formatter/Bootstrap.pm |  1 +
 3 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/PVE/APIServer/AnyEvent.pm b/PVE/APIServer/AnyEvent.pm
index c0b90ab..1197857 100644
--- a/PVE/APIServer/AnyEvent.pm
+++ b/PVE/APIServer/AnyEvent.pm
@@ -544,7 +544,7 @@ sub websocket_proxy {
 }
 
 sub proxy_request {
-my ($self, $reqstate, $clientip, $host, $node, $method, $uri, $ticket, 
$token, $params) = @_;
+my ($self, $reqstate, $clientip, $host, $node, $method, $uri, $auth, 
$params) = @_;
 
 eval {
my $target;
@@ -564,8 +564,12 @@ sub proxy_request {
PVEClientIP => $clientip,
};
 
-   $headers->{'cookie'} = 
PVE::APIServer::Formatter::create_auth_cookie($ticket, $self->{cookie_name}) if 
$ticket;
-   $headers->{'CSRFPreventionToken'} = $token if $token;
+   $headers->{'cookie'} = 
PVE::APIServer::Formatter::create_auth_cookie($auth->{ticket}, 
$self->{cookie_name})
+   if $auth->{ticket};
+   $headers->{'Authorization'} = 
PVE::APIServer::Formatter::create_auth_header($auth->{api_token}, 
$self->{apitoken_name})
+   if $auth->{api_token};
+   $headers->{'CSRFPreventionToken'} = $auth->{token}
+   if $auth->{token};
$headers->{'Accept-Encoding'} = 'gzip' if ($reqstate->{accept_gzip} && 
$self->{compression});
 
if (defined(my $host = $reqstate->{request}->header('Host'))) {
@@ -747,7 +751,7 @@ sub handle_api2_request {
$res->{proxy_params}->{tmpfilename} = $reqstate->{tmpfilename} if 
$upload_state;
 
$self->proxy_request($reqstate, $clientip, $host, 
$res->{proxynode}, $method,
-$r->uri, $auth->{ticket}, $auth->{token}, 
$res->{proxy_params});
+$r->uri, $auth, $res->{proxy_params});
return;
 
} elsif ($upgrade && ($method eq 'GET') && ($path =~ m|websocket$|)) {
@@ -1236,6 +1240,8 @@ sub unshift_read_header {
my $ticket = 
PVE::APIServer::Formatter::extract_auth_value($cookie, $self->{cookie_name});
$ticket = 
PVE::APIServer::Formatter::extract_auth_value($auth_header, 
$self->{cookie_name})
if !$ticket;
+   my $api_token = 
PVE::APIServer::Formatter::extract_auth_value($auth_header, 
$self->{apitoken_name})
+   if !$ticket;
 
my ($rel_uri, $format) = &$split_abs_uri($path, 
$self->{base_uri});
if (!$format) {
@@ -1244,7 +1250,7 @@ sub unshift_read_header {
}
 
eval {
-   $auth = $self->auth_handler($method, $rel_uri, $ticket, 
$token,
+   $auth = $self->auth_handler($method, $rel_uri, $ticket, 
$token, $api_token,
$reqstate->{peer_host});
};
if (my $err = $@) {
@@ -1638,6 +1644,7 @@ sub new {
 my $self = bless { %args }, $class;
 
 $self->{cookie_name} //= 'PVEAuthCookie';
+$self->{apitoken_name} //= 'PVEAPIToken';
 $self->{base_uri} //= "/api2";
 $self->{dirs} //= {};
 $self->{title} //= 'API Inspector';
@@ -1645,7 +1652,7 @@ sub new {
 
 # formatter_config: we pass some configuration values to the Formatter
 $self->{formatter_config} = {};
-foreach my $p (qw(cookie_name base_uri title)) {
+foreach my $p (qw(apitoken_name cookie_name base_uri title)) {
$self->{formatter_config}->{$p} = $self->{$p};
 }
 $self->{formatter_config}->{csrfgen_func} =
@@ -1780,7 +1787,7 @@ sub generate_csrf_prevention_token {
 }
 
 sub auth_handler {
-my ($self, $method, $rel_uri, $ticket, $token, $peer_host) = @_;
+my ($self, $method, $rel_uri, $ticket, $token, $api_token, $peer_host) = 
@_;
 
 die "implement me";
 
@@ -1790,6 +1797,7 @@ sub auth_handler {
 #userid => $username,
 #age => $age,
 #isUpload => $isUpload,
+#api_token => $api_token,
 #};
 }
 
diff --git a/PVE/APIServer/Formatter.pm b/PVE/APIServer/Formatter.pm
index def1932..20455a0 100644
--- a/PVE/APIServer/Formatter.pm
+++ b/PVE/APIServer/Formatter.pm
@@ -95,4 +95,13 @@ sub create_auth_cookie {
 return "${cookie_name}=$encticket; path=/; secure;";
 }
 
+sub create_auth_header {
+my ($value, $key) = @_;
+
+return undef if !$key;
+
+my $encoded = uri_escape($

[pve-devel] [RFC 20/23] auth_handler: handle API tokens

2019-10-17 Thread Fabian Grünbichler
Signed-off-by: Fabian Grünbichler 
---

Notes:
versioned breaks/depends between pve-manager and libpve-http-server-perl!
versioned depends on libpve-access-control

 PVE/HTTPServer.pm | 55 ++-
 1 file changed, 30 insertions(+), 25 deletions(-)

diff --git a/PVE/HTTPServer.pm b/PVE/HTTPServer.pm
index ce895725..c11b4813 100755
--- a/PVE/HTTPServer.pm
+++ b/PVE/HTTPServer.pm
@@ -52,7 +52,7 @@ sub generate_csrf_prevention_token {
 }
 
 sub auth_handler {
-my ($self, $method, $rel_uri, $ticket, $token, $peer_host) = @_;
+my ($self, $method, $rel_uri, $ticket, $token, $api_token, $peer_host) = 
@_;
 
 my $rpcenv = $self->{rpcenv};
 
@@ -77,36 +77,40 @@ sub auth_handler {
 my $isUpload = 0;
 
 if ($require_auth) {
+   if ($api_token) {
+   $username = PVE::AccessControl::verify_token($api_token);
+   $rpcenv->set_user($username); #actually tokenid in this case
+   } else {
+   die "No ticket\n" if !$ticket;
 
-   die "No ticket\n" if !$ticket;
+   ($username, $age, my $tfa_info) = 
PVE::AccessControl::verify_ticket($ticket);
 
-   ($username, $age, my $tfa_info) = 
PVE::AccessControl::verify_ticket($ticket);
-
-   if (defined($tfa_info)) {
-   if (defined(my $challenge = $tfa_info->{challenge})) {
-   $rpcenv->set_u2f_challenge($challenge);
+   if (defined($tfa_info)) {
+   if (defined(my $challenge = $tfa_info->{challenge})) {
+   $rpcenv->set_u2f_challenge($challenge);
+   }
+   die "No ticket\n"
+   if ($rel_uri ne '/access/tfa' || $method ne 'POST');
}
-   die "No ticket\n"
-   if ($rel_uri ne '/access/tfa' || $method ne 'POST');
-   }
 
-   $rpcenv->set_user($username);
+   $rpcenv->set_user($username);
 
-   if ($method eq 'POST' && $rel_uri =~ 
m|^/nodes/([^/]+)/storage/([^/]+)/upload$|) {
-   my ($node, $storeid) = ($1, $2);
-   # we disable CSRF checks if $isUpload is set,
-   # to improve security we check user upload permission here
-   my $perm = { check => ['perm', "/storage/$storeid", 
['Datastore.AllocateTemplate']] };
-   $rpcenv->check_api2_permissions($perm, $username, {});
-   $isUpload = 1;
-   }
+   if ($method eq 'POST' && $rel_uri =~ 
m|^/nodes/([^/]+)/storage/([^/]+)/upload$|) {
+   my ($node, $storeid) = ($1, $2);
+   # we disable CSRF checks if $isUpload is set,
+   # to improve security we check user upload permission here
+   my $perm = { check => ['perm', "/storage/$storeid", 
['Datastore.AllocateTemplate']] };
+   $rpcenv->check_api2_permissions($perm, $username, {});
+   $isUpload = 1;
+   }
 
-   # we skip CSRF check for file upload, because it is
-   # difficult to pass CSRF HTTP headers with native html forms,
-   # and it should not be necessary at all.
-   my $euid = $>;
-   PVE::AccessControl::verify_csrf_prevention_token($username, $token)
-   if !$isUpload && ($euid != 0) && ($method ne 'GET');
+   # we skip CSRF check for file upload, because it is
+   # difficult to pass CSRF HTTP headers with native html forms,
+   # and it should not be necessary at all.
+   my $euid = $>;
+   PVE::AccessControl::verify_csrf_prevention_token($username, $token)
+   if !$isUpload && ($euid != 0) && ($method ne 'GET');
+   }
 }
 
 return {
@@ -115,6 +119,7 @@ sub auth_handler {
userid => $username,
age => $age,
isUpload => $isUpload,
+   api_token => $api_token,
 };
 }
 
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 23/23] api/tasks: attribute token tasks to user

2019-10-17 Thread Fabian Grünbichler
and store token ID in separate, currently unused member.

Signed-off-by: Fabian Grünbichler 
---

Notes:
versioned depends on libpve-access-control

alternatively, we could also change the fork_worker signature and encode 
this
inside the task information on disk, but that would be a more invasive
solution..

 PVE/API2/Cluster.pm |  3 +++
 PVE/API2/Tasks.pm   | 15 +++
 2 files changed, 18 insertions(+)

diff --git a/PVE/API2/Cluster.pm b/PVE/API2/Cluster.pm
index 382a2c12..00f811cd 100644
--- a/PVE/API2/Cluster.pm
+++ b/PVE/API2/Cluster.pm
@@ -460,6 +460,9 @@ __PACKAGE__->register_method({
my $all = $rpcenv->check($authuser, "/", [ 'Sys.Audit' ], 1);
 
foreach my $task (@$tlist) {
+   if (PVE::AccessControl::pve_verify_tokenid($task->{user}, 1)) {
+   ($task->{user}, $task->{tokenid}) = 
PVE::AccessControl::split_tokenid($task->{user});
+   }
push @$res, $task if $all || ($task->{user} eq $authuser);
}

diff --git a/PVE/API2/Tasks.pm b/PVE/API2/Tasks.pm
index 73e398eb..5dc6a4ad 100644
--- a/PVE/API2/Tasks.pm
+++ b/PVE/API2/Tasks.pm
@@ -16,6 +16,14 @@ use PVE::AccessControl;
 
 use base qw(PVE::RESTHandler);
 
+my $convert_token_task = sub {
+my ($task) = @_;
+
+if (PVE::AccessControl::pve_verify_tokenid($task->{user}, 1)) {
+   ($task->{user}, $task->{tokenid}) = 
PVE::AccessControl::split_tokenid($task->{user});
+}
+};
+
 __PACKAGE__->register_method({
 name => 'node_tasks',
 path => '',
@@ -142,6 +150,7 @@ __PACKAGE__->register_method({
$task->{endtime} = hex($endtime) if $endtime;
$task->{status} = $status if $status;
 
+   $convert_token_task->($task);
if (!$filter_task->($task)) {
push @$res, $task;
$limit--;
@@ -242,6 +251,8 @@ __PACKAGE__->register_method({
my $user = $rpcenv->get_user();
my $node = $param->{node};
 
+   $convert_token_task->($task);
+
if ($user ne $task->{user}) {
$rpcenv->check($user, "/nodes/$node", [ 'Sys.Modify' ]);
}
@@ -309,6 +320,8 @@ __PACKAGE__->register_method({
my $start = $param->{start} // 0;
my $limit = $param->{limit} // 50;
 
+   $convert_token_task->($task);
+
if ($user ne $task->{user})  {
$rpcenv->check($user, "/nodes/$node", [ 'Sys.Audit' ]);
}
@@ -365,6 +378,8 @@ __PACKAGE__->register_method({
my $user = $rpcenv->get_user();
my $node = $param->{node};
 
+   $convert_token_task->($task);
+
if ($user ne $task->{user}) {
$rpcenv->check($user, "/nodes/$node", [ 'Sys.Audit' ]);
}
-- 
2.20.1


___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


[pve-devel] [RFC 22/23] pveproxy: use new cookie extraction method

2019-10-17 Thread Fabian Grünbichler
we only care about the regular cookie case for the index.

Signed-off-by: Fabian Grünbichler 
---

Notes:
versioned breaks/depends on libpve-http-perl!

 PVE/Service/pveproxy.pm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/PVE/Service/pveproxy.pm b/PVE/Service/pveproxy.pm
index dd123dd8..786545f2 100755
--- a/PVE/Service/pveproxy.pm
+++ b/PVE/Service/pveproxy.pm
@@ -183,7 +183,7 @@ sub get_index {
$lang = $newlang;
}
}
-   my $ticket = PVE::APIServer::Formatter::extract_auth_cookie($cookie, 
$server->{cookie_name});
+   my $ticket = PVE::APIServer::Formatter::extract_auth_value($cookie, 
$server->{cookie_name});
if (($username = PVE::AccessControl::verify_ticket($ticket, 1))) {
$token = 
PVE::AccessControl::assemble_csrf_prevention_token($username);
}
-- 
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] [RFC/PATCH 0/23] API Tokens

2019-10-17 Thread Fabian Grünbichler
and I just realized that I dropped the per-repo subject-prefix from all 
patches instead of just the cover-letter..

#1 is pve-common
#2-15 are pve-access-control
#16-18 are pve-http-server
#19-#23 are pve-manager

if you want a resend, just shout..

On October 17, 2019 3:13 pm, Fabian Grünbichler wrote:
> This is a draft of a patch series which aims to introduce API tokens
> into PVE.
> 
> The basic idea is to allow users to generate API token values that
> - are attributed to this users
> - easily revokable
> - possibly less privileged than the user itself
> - allow direct API calls without round-trips to create/refresh a ticket
> 
> Token information is stored in user.cfg together with the other
> access-control information. The actual token values will be stored in a
> 'shadow' file under /etc/pve/priv (see patch #12 for some
> ideas/comments).
> 
> Still missing:
> - thorough review ;)
> - adaption/extension of user.cfg tests (especially w.r.t. #6/7)
> - PVE::APIClient support
> - token value generation, deletion & verification (#12)
> - pveum integration
> - GUI integration (just the token API, not using tokens for login..)
> - documentation
> - PMG adaption (at least for the changed method signatures in
>   pve-http-server)
> - checking API endpoints for 'notoken'-ification
> 
> I tried to order independent clean-ups etc. up front with-in each repo,
> but some of them require versioned breaks/depends so it might make sense
> to wait for the full series for those.
> 
> pve-common:
> 
> Fabian Grünbichler (1):
>   API schema: add 'notoken' property
> 
>  src/PVE/JSONSchema.pm | 5 +
>  1 file changed, 5 insertions(+)
> 
> pve-access-control:
> 
> Fabian Grünbichler (14):
>   add missing 'use PVE::Auth::Plugin'
>   user.cfg: sort entries alphabetically in each section
>   user.cfg: sort ACL members
>   access-control: remove check_permissions/permission
>   rpcenv: drop unused roles()
>   auth: pull username REs into variables
>   refactor acl transformation code
>   API token: add REs, helpers, parsing + writing
>   API token: add API helpers
>   DO NOT APPLY: API token stubs for token value handling
>   API: add API token API endpoints
>   API: include API tokens in ACL API endpoints
>   API token: implement permission checks
>   api: mark some paths notoken
> 
>  PVE/API2/ACL.pm   |  30 +++-
>  PVE/API2/AccessControl.pm |   5 +
>  PVE/API2/User.pm  | 287 ++-
>  PVE/AccessControl.pm  | 307 --
>  PVE/Auth/Plugin.pm|   5 +-
>  PVE/RPCEnvironment.pm |  50 +++
>  6 files changed, 568 insertions(+), 116 deletions(-)
> 
> pve-http-server:
> 
> Fabian Grünbichler (2):
>   proxy_request: drop duplicate, unused parameter
>   allow ticket in auth header as fallback
>   api-server: extract, set and handle API token header
> 
>  PVE/APIServer/AnyEvent.pm| 27 +++
>  PVE/APIServer/Formatter.pm   | 21 +++--
>  PVE/APIServer/Formatter/Bootstrap.pm |  1 +
>  3 files changed, 35 insertions(+), 14 deletions(-)
> 
> pve-manager:
> 
> Fabian Grünbichler (5):
>   subscription: use rpcenv for permission check
>   auth_handler: handle API tokens
>   rest_handler: implement 'notoken' API endpoints
>   pveproxy: use new cookie extraction method
>   api/tasks: attribute token tasks to user
> 
>  PVE/API2/Cluster.pm  |  3 ++
>  PVE/API2/Subscription.pm |  2 +-
>  PVE/API2/Tasks.pm| 15 ++
>  PVE/HTTPServer.pm| 60 +++-
>  PVE/Service/pveproxy.pm  |  2 +-
>  5 files changed, 54 insertions(+), 28 deletions(-)
> 
> -- 
> 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


Re: [pve-devel] [RFC 1/23] API schema: add 'notoken' property

2019-10-17 Thread Fabian Grünbichler
On October 17, 2019 4:46 pm, Thomas Lamprecht wrote:
> On 10/17/19 3:13 PM, Fabian Grünbichler wrote:
>> to mark API methods which should not be available to clients authenticated 
>> using an API token
> 
> please wrap lines, for commit messages it's common to use << 70 as limit,
> at least <= 80 would be really great.

indeed. that sometimes happens to slip through when I compose the 
message directly with -m "..." -m "..." ;)

> 
>> 
>> Signed-off-by: Fabian Grünbichler 
>> ---
>> 
>> Notes:
>> if applied, any users of this need corresponding versioned depends.
>> 
>>  src/PVE/JSONSchema.pm | 5 +
>>  1 file changed, 5 insertions(+)
>> 
>> diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm
>> index db38d44..a42d814 100644
>> --- a/src/PVE/JSONSchema.pm
>> +++ b/src/PVE/JSONSchema.pm
>> @@ -1263,6 +1263,11 @@ my $method_schema = {
>>  description => "Method needs special privileges - only pvedaemon 
>> can execute it",
>>  optional => 1,
>>  },
>> +notoken => {
> 
> IMO slightly to general. Also, negative named properties are not ideal, even
> if I sometimes use them too, Dominik always notices it in the web ui ;)
> 
> The question is, do we want to have certain API endpoints which we straight
> forbid, or do we want some which can only be called by sending along the full
> user credentials.
> 
> The latter would allow to only use an API token for a mobile app (for 
> example),
> but still have a password change dialog there, with allows to change the
> password of the user which the token belongs, but only if the current password
> is sent along and without some hacks required by the app where it temporarily
> requests a "full user ticket". (how TFA would play into something like this is
> another question...)
> 
> I mean, just an example, but we could then resort to name it something like
> "require-fullauth"
> 
> or we reverse the default and name it:
> "token-auth-sufficient"
> 
> anyway, bike-shedding details, but for an RFC OK I hope ;P

sure - I don't care about the name at all, and a positively-named option 
with a default of 1 is also okay :)

I am not sure whether we even really need such a schema option - we 
could also just have a helper in PVE::RPCEnvironment or 
PVE::AccessControl and call that directly at the start of the API 
methods. in the end, it probably comes down to how many such API methods 
there are.

> 
>> +type => 'boolean',
>> +description => "Method is not available for clients authenticated 
>> using an API token.",
>> +optional => 1,
>> +},
>>  download => {
>>  type => 'boolean',
>>  description => "Method downloads the file content (filename is the 
>> return value of the method).",
>> 
> 
> 
> 

___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


Re: [pve-devel] [PATCH v3 guest-common 04/19] helpers: add method to represent config as a table

2019-10-17 Thread Fabian Grünbichler
On October 17, 2019 7:48 pm, Thomas Lamprecht wrote:
> On 10/14/19 10:28 AM, Oguz Bektas wrote:
>> in vm_pending API, this method is used to represent the configuration as
>> a table with current, pending and delete columns.
>> 
>> by adding it as a guesthelper, we can also use it for container pending
>> changes.
>> 
>> Signed-off-by: Oguz Bektas 
>> ---
>>  PVE/GuestHelpers.pm | 35 +++
>>  1 file changed, 35 insertions(+)
>> 
>> diff --git a/PVE/GuestHelpers.pm b/PVE/GuestHelpers.pm
>> index a36b9bc..a1ec76f 100644
>> --- a/PVE/GuestHelpers.pm
>> +++ b/PVE/GuestHelpers.pm
>> @@ -142,4 +142,39 @@ sub format_pending {
>>  }
>>  }
>>  
>> +sub conf_table_with_pending {
> 
> nothing to do with table itself, it just returns a array of
> hashes with current and pending value..
> 
> I'd rather like to not bind method names to something their caller
> may do with them, but to something they actually do their self.
> 
> Albeit a good name is not to easy here... Maybe:
> get_current_config_with_pending
>

it does not really 'get' the config either though ;)

I don't really know how to call
hash1 hash2 => list of items derived from hash1 and hash2

except that it's some kind of 'transformation'. it's not a mapping 
operation (it could be seen as sequence of three mappings), it's not a 
flattening, it's not folding.

there is in fact no information added to the input, it's just presented 
in a different structure.

'transform_to_list_with_pending' was about as far as we got off-list, 
and Oguz didn't like that at all :-P

>> +my ($conf, $pending_delete_hash) = @_;
>> +
>> +my $res = [];
>> +
>> +foreach my $opt (keys %$conf) {
>> +next if ref($conf->{$opt});
>> +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}->{force} ? 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}); # just to be sure
>> +next if defined($conf->{$opt});
>> +my $item = { key => $opt };
>> +$item->{pending} = $conf->{pending}->{$opt};
>> +
>> +push @$res, $item;
>> +}
>> +
>> +while (my ($opt, $force) = each %$pending_delete_hash) {
>> +next if $conf->{pending}->{$opt}; # just to be sure
>> +next if $conf->{$opt};
>> +my $item = { key => $opt, delete => ($force ? 2 : 1)};
>> +push @$res, $item;
>> +}
>> +
>> +return $res;
>> +}
>> +
>>  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


Re: [pve-devel] [PATCH qemu-server v3] Fix #2412: Missing VMs in pools

2019-10-17 Thread Fabian Grünbichler
On October 15, 2019 12:17 pm, Dominic Jäger wrote:
> Between calling vm_destroy and removing the ID from user.cfg 
> (remove_vm_access)
> creating a new VM with this ID was possible. VMs could go missing from pools 
> as
> a consequence.
> 
> Adding a lock solves this for clones from the same node. Additionally,
> unlinking must happen at the very end of the deletion process to avoid that
> other nodes use the ID in the meanwhile.
> 
> Co-developed-by: Fabian Grünbichler 
> Signed-off-by: Dominic Jäger 
> ---
> v1->v2: Move unlink to the end of the deletion process
> v2->v3: Use skiplock parameter and add error handling for unlink
> 
> I'll send a separate patch for the discussed clean up.

and for pve-container? ;)

>  PVE/API2/Qemu.pm | 12 +---
>  1 file changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
> index 267a08e..7e1d314 100644
> --- a/PVE/API2/Qemu.pm
> +++ b/PVE/API2/Qemu.pm
> @@ -1492,9 +1492,15 @@ __PACKAGE__->register_method({
>   my $upid = shift;
>  
>   syslog('info', "destroy VM $vmid: $upid\n");
> - PVE::QemuServer::vm_destroy($storecfg, $vmid, $skiplock);
> - PVE::AccessControl::remove_vm_access($vmid);
> -PVE::Firewall::remove_vmfw_conf($vmid);
> + PVE::QemuConfig->lock_config($vmid, sub {
> + die "VM $vmid is running - destroy failed\n"
> + if (PVE::QemuServer::check_running($vmid));
> + PVE::QemuServer::destroy_vm($storecfg, $vmid, 1, $skiplock);
> + PVE::AccessControl::remove_vm_access($vmid);
> + PVE::Firewall::remove_vmfw_conf($vmid);
> + unlink PVE::QemuConfig->config_file($vmid)
> + or die "Removal of VM $vmid config file failed: $!\n";
> + });
>   };
>  
>   return $rpcenv->fork_worker('qmdestroy', $vmid, $authuser, $realcmd);
> -- 
> 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 v4 0/7] add purge option for VM/CT destroy

2019-10-17 Thread Fabian Grünbichler
On October 17, 2019 6:40 pm, Thomas Lamprecht wrote:
> On 10/15/19 1:00 PM, Christian Ebner wrote:
>> When destroying a VM/CT, we intentionally did not remove all related configs 
>> such
>> as backup or replication jobs.
>> The intention of this flag is to allow the removal of such configs on 
>> destroy.
>> 
>> This patch series implements this functionality and additionally moves the
>> cfs register code for vzdump.cron to pve-guest-common to avoid a cyclic
>> dependency.
> 
> Looks OK for me, after a quick look.
> 
> If there are no high-level objections to the move of VZDump config/schema
> stuff I'd give it a deeper look + test and apply it, if all seems well.
> 
> Fabian, Dietmar?

no objections from me (see discussion of previous version ;))

from a quick glance: the commit IDs in commit messages are probably not 
a good idea, and this conflicts with the "fix locking in vm_destroy API 
path" patch by Dominic[1] so it might need a rebase.

[1]: applied for qemu-server, still missing for pve-container - 
potentially the latter could be fixed together with this series?

___
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


  1   2   3   4   5   6   7   8   9   10   >