* [pve-devel] [PATCH common/http/guest-common/qemu-server v2] schema/config array support
@ 2023-06-06 8:39 Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH common v2 1/3] JSONSchema: add support for array parameter in api calls, cli and config Dominik Csapak
` (6 more replies)
0 siblings, 7 replies; 14+ messages in thread
From: Dominik Csapak @ 2023-06-06 8:39 UTC (permalink / raw)
To: pve-devel
and removal of the '-alist' format
This series aims to implement array support for the api and
(section)config and remove the support for the (rarely used) '-alist'
formats.
currently sending arrays over the api (by sending a parameter multiple
times with form-urlencoded) results in the api call getting a \0
separated string, which it must split with e.g. split_list.
Instead, we want to simply specify an 'array' type for the api.
We only ever used '-alist' in two places:
* 'exclude-path' config/parameter for vzdump
* 'command' parameter for qemu guest agent exec via api (cli has it's
own implementation with 'extra-args')
additionally, we (incidentally?) allowed the same format for the regular
'-list' formats, and the gui makes heavy use of this (iow. sending
arrays which get converted to \0 byte separated strings)
so we also auto-convert in some circumstances (which we want to
deprecate in a future version)
changes from v1:
* rebased on master
* incorporated feedback from wolfang
* added auto conversion of string <-> array in appropriate situations
* added tests for above
* omit applied manager patch
The dependcies/breaks are like this:
pve-http-server 1/2 is rather independent (did encounter this during
testing, and the current behaviour is imho wrong)
pve-guest-common depends on new (applied) pve-manager,
pve-http-server and pve-common 1/3
qemu-sever depends on pve-http-server and pve-common 1/3
pve-http-server does not technically break the older pve-guest-common
and qemu-server versions, but the parameters would need to be
encoded/sent differently than before (iow. the api user would have to
send the commands/paths \0 separated already instead of repeating the
parameters (form-urlencoded arrays))
pve-common 2/3 depend on all above
pve-common 3/3 depend on all above and it breaks every version that uses
an '-alist' format (so older pve-guest-common + qemu-server)
we can of course omit pve-common 3/3 and leave support in the
jsonschema, but imho it's really weird to use and has no real upsides
versus using simply an array type
pve-common:
Dominik Csapak (3):
JSONSchema: add support for array parameter in api calls, cli and
config
section config: implement array support
JSONSchema: disable '-alist' format
src/PVE/JSONSchema.pm | 26 +++++-----
src/PVE/RESTHandler.pm | 61 ++++++++++++++++++----
src/PVE/SectionConfig.pm | 42 +++++++++++++--
test/Makefile | 9 +++-
test/api_parameter_test.pl | 100 ++++++++++++++++++++++++++++++++++++
test/section_config_test.pl | 26 ++++++++++
6 files changed, 237 insertions(+), 27 deletions(-)
create mode 100755 test/api_parameter_test.pl
pve-http-server:
Dominik Csapak (2):
proxy request: forward json content type and parameters
use proper arrays for array parameter
src/PVE/APIServer/AnyEvent.pm | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
pve-guest-common:
Dominik Csapak (1):
vzdump: change 'exclude-path' from alist to an array format
src/PVE/VZDump/Common.pm | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
qemu-server:
Dominik Csapak (1):
api: switch agent api call to 'array' type
PVE/API2/Qemu/Agent.pm | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
--
2.30.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [pve-devel] [PATCH common v2 1/3] JSONSchema: add support for array parameter in api calls, cli and config
2023-06-06 8:39 [pve-devel] [PATCH common/http/guest-common/qemu-server v2] schema/config array support Dominik Csapak
@ 2023-06-06 8:39 ` Dominik Csapak
2023-06-06 9:12 ` Thomas Lamprecht
2023-06-06 8:39 ` [pve-devel] [PATCH common v2 2/3] section config: implement array support Dominik Csapak
` (5 subsequent siblings)
6 siblings, 1 reply; 14+ messages in thread
From: Dominik Csapak @ 2023-06-06 8:39 UTC (permalink / raw)
To: pve-devel
a few things were missing for it to work:
* on the cli, we have to get the option as an array if the type is an
array
* the untainting must be done recursively, otherwise, the regex matching
converts an array hash into the string 'ARRAY(0x123412341234)'
* JSONSchema::parse_config did not handle array formats specially, but
we want to allow to specify them multiple time
* the biggest point: in the RESTHandler, to be compatible with the
current gui behavior, we have to rewrite two parameter types:
- when the api defines a '-list' format for a string type, but we get
a list (because of the changes in http-server), we join the list
with a comma into a string
- when the api defines an 'array' type, but we get a scalar value,
wrap the value in an array (because for www-form-urlencoded, you
cannot send an array with a single value) add tests for this
behavior, some of which we want to deprecate and remove in the
future
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
changes from v1:
* include wolfangs feedback
* include auto-conversion from string <-> list where appropriate and add
tests for it
src/PVE/JSONSchema.pm | 12 +++++
src/PVE/RESTHandler.pm | 61 ++++++++++++++++++----
test/Makefile | 9 +++-
test/api_parameter_test.pl | 100 +++++++++++++++++++++++++++++++++++++
4 files changed, 172 insertions(+), 10 deletions(-)
create mode 100755 test/api_parameter_test.pl
diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm
index 527e409..526fc2b 100644
--- a/src/PVE/JSONSchema.pm
+++ b/src/PVE/JSONSchema.pm
@@ -1709,6 +1709,8 @@ sub get_options {
} else {
if ($pd->{format} && $pd->{format} =~ m/-a?list/) {
push @getopt, "$prop=s@";
+ } elsif ($pd->{type} eq 'array') {
+ push @getopt, "$prop=s@";
} else {
push @getopt, "$prop=s";
}
@@ -1869,6 +1871,16 @@ sub parse_config : prototype($$$;$) {
$value = parse_boolean($value) // $value;
}
+ if ($schema->{properties}->{$key} &&
+ $schema->{properties}->{$key}->{type} eq 'array') {
+
+ if (defined($cfg->{$key})) {
+ push $cfg->{$key}->@*, $value;
+ } else {
+ $cfg->{$key} = [$value];
+ }
+ next;
+ }
$cfg->{$key} = $value;
} else {
warn "ignore config line: $line\n"
diff --git a/src/PVE/RESTHandler.pm b/src/PVE/RESTHandler.pm
index db86af2..369e302 100644
--- a/src/PVE/RESTHandler.pm
+++ b/src/PVE/RESTHandler.pm
@@ -426,6 +426,56 @@ sub find_handler {
return ($handler_class, $method_info);
}
+my $untaint_recursive;
+
+$untaint_recursive = sub {
+ my ($param) = @_;
+
+ my $ref = ref($param);
+ if ($ref eq 'HASH') {
+ $param->{$_} = $untaint_recursive->($param->{$_}) for keys $param->%*;
+ } elsif ($ref eq 'ARRAY') {
+ for (my $i = 0; $i < scalar($param->@*); $i++) {
+ $param->[$i] = $untaint_recursive->($param->[$i]);
+ }
+ } else {
+ if (defined($param)) {
+ my ($newval) = $param =~ /^(.*)$/s;
+ $param = $newval;
+ }
+ }
+
+ return $param;
+};
+
+# convert arrays to strings where we expect a '-list' format and convert scalar
+# values to arrays when we expect an array (because of www-form-urlencoded)
+#
+# only on the top level, since www-form-urlencoded cannot be nested anyway
+#
+# FIXME: change gui/api calls to not rely on this during 8.x, mark the
+# behaviour deprecated with 9.x, and remove it with 10.x
+my $convert_params = sub { my ($param, $schema) = @_;
+
+ return if !$schema->{properties};
+ return if (ref($param) // '') ne 'HASH';
+
+ for my $key (keys $schema->{properties}->%*) {
+ if (my $value = $param->{$key}) {
+ my $type = $schema->{properties}->{$key}->{type} // '';
+ my $format = $schema->{properties}->{$key}->{format} // '';
+ my $ref = ref($value);
+ if ($ref eq 'ARRAY' && $type eq 'string' && $format =~ m/-list$/) {
+ $param->{$key} = join(',', $value->@*);
+ } elsif (!$ref && $type eq 'array') {
+ $param->{$key} = [$value];
+ }
+ }
+ }
+
+ return $param;
+};
+
sub handle {
my ($self, $info, $param, $result_verification) = @_;
@@ -437,17 +487,10 @@ sub handle {
if (my $schema = $info->{parameters}) {
# warn "validate ". Dumper($param}) . "\n" . Dumper($schema);
+ $param = $convert_params->($param, $schema);
PVE::JSONSchema::validate($param, $schema);
# untaint data (already validated)
- my $extra = delete $param->{'extra-args'};
- while (my ($key, $val) = each %$param) {
- if (defined($val)) {
- ($param->{$key}) = $val =~ /^(.*)$/s;
- } else {
- $param->{$key} = undef;
- }
- }
- $param->{'extra-args'} = [map { /^(.*)$/ } @$extra] if $extra;
+ $param = $untaint_recursive->($param);
}
my $result = $func->($param); # the actual API code execution call
diff --git a/test/Makefile b/test/Makefile
index 5c64867..82f40ab 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,4 +1,11 @@
SUBDIRS = etc_network_interfaces
+TESTS = lock_file.test \
+ calendar_event_test.test \
+ convert_size_test.test \
+ procfs_tests.test \
+ format_test.test \
+ section_config_test.test \
+ api_parameter_test.test \
all:
@@ -6,7 +13,7 @@ all:
export PERLLIB=../src
-check: lock_file.test calendar_event_test.test convert_size_test.test procfs_tests.test format_test.test section_config_test.test
+check: $(TESTS)
for d in $(SUBDIRS); do $(MAKE) -C $$d check; done
%.test: %.pl
diff --git a/test/api_parameter_test.pl b/test/api_parameter_test.pl
new file mode 100755
index 0000000..7ade386
--- /dev/null
+++ b/test/api_parameter_test.pl
@@ -0,0 +1,100 @@
+#!/usr/bin/perl
+package PVE::TestAPIParameters;
+
+# Tests the automatic conversion of -list and array parameter types
+
+use strict;
+use warnings;
+
+use lib '../src';
+
+use PVE::RESTHandler;
+use PVE::JSONSchema;
+
+use Test::More;
+
+use base qw(PVE::RESTHandler);
+
+my $setup = [
+ {
+ name => 'list-format-with-list',
+ parameter => {
+ type => 'string',
+ format => 'pve-configid-list',
+ },
+ value => "foo,bar",
+ 'value-expected' => "foo,bar",
+ },
+ {
+ name => 'array-format-with-array',
+ parameter => {
+ type => 'array',
+ items => {
+ type => 'string',
+ format => 'pve-configid',
+ },
+ },
+ value => ['foo', 'bar'],
+ 'value-expected' => ['foo', 'bar'],
+ },
+ # TODO: below behaviour should be deprecated with 9.x and fail with 10.x
+ {
+ name => 'list-format-with-alist',
+ parameter => {
+ type => 'string',
+ format => 'pve-configid-list',
+ },
+ value => "foo\0bar",
+ 'value-expected' => "foo\0bar",
+ },
+ {
+ name => 'array-format-with-non-array',
+ parameter => {
+ type => 'array',
+ items => {
+ type => 'string',
+ format => 'pve-configid',
+ },
+ },
+ value => "foo",
+ 'value-expected' => ['foo'],
+ },
+ {
+ name => 'list-format-with-array',
+ parameter => {
+ type => 'string',
+ format => 'pve-configid-list',
+ },
+ value => ['foo', 'bar'],
+ 'value-expected' => "foo,bar",
+ },
+];
+
+for my $data ($setup->@*) {
+ __PACKAGE__->register_method({
+ name => $data->{name},
+ path => $data->{name},
+ method => 'POST',
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ param => $data->{parameter},
+ },
+ },
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+ return $param->{param};
+ }
+ });
+
+ my ($handler, $info) = __PACKAGE__->find_handler('POST', $data->{name});
+ my $param = {
+ param => $data->{value},
+ };
+
+ my $res = $handler->handle($info, $param);
+ is_deeply($res, $data->{'value-expected'}, $data->{name});
+}
+
+done_testing();
--
2.30.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [pve-devel] [PATCH common v2 2/3] section config: implement array support
2023-06-06 8:39 [pve-devel] [PATCH common/http/guest-common/qemu-server v2] schema/config array support Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH common v2 1/3] JSONSchema: add support for array parameter in api calls, cli and config Dominik Csapak
@ 2023-06-06 8:39 ` Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH common v2 3/3] JSONSchema: disable '-alist' format Dominik Csapak
` (4 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: Dominik Csapak @ 2023-06-06 8:39 UTC (permalink / raw)
To: pve-devel
enables section configs in the style of:
----
type: id
property value
property value2
property value3
----
can be combined with property strings
the provided create and update schema just pass through the array type
to the api, so the api call must always contain the complete array
also adds a test case for such array fields
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
changes from v1:
* remove unnecessary code move
src/PVE/SectionConfig.pm | 42 ++++++++++++++++++++++++++++++++-----
test/section_config_test.pl | 26 +++++++++++++++++++++++
2 files changed, 63 insertions(+), 5 deletions(-)
diff --git a/src/PVE/SectionConfig.pm b/src/PVE/SectionConfig.pm
index f36cede..97492db 100644
--- a/src/PVE/SectionConfig.pm
+++ b/src/PVE/SectionConfig.pm
@@ -254,7 +254,15 @@ sub check_value {
if (!$skipSchemaCheck) {
my $errors = {};
- PVE::JSONSchema::check_prop($value, $schema, '', $errors);
+
+ my $checkschema = $schema;
+
+ if ($ct eq 'array') {
+ die "no item schema for array" if !defined($schema->{items});
+ $checkschema = $schema->{items};
+ }
+
+ PVE::JSONSchema::check_prop($value, $checkschema, '', $errors);
if (scalar(keys %$errors)) {
die "$errors->{$key}\n" if $errors->{$key};
die "$errors->{_root}\n" if $errors->{_root};
@@ -311,6 +319,15 @@ sub parse_config {
}
};
+ my $is_array = sub {
+ my ($type, $key) = @_;
+
+ my $schema = $pdata->{propertyList}->{$key};
+ die "unknown property type\n" if !$schema;
+
+ return $schema->{type} eq 'array';
+ };
+
my $errors = [];
while (@lines) {
my $line = $nextline->();
@@ -352,11 +369,19 @@ sub parse_config {
my ($k, $v) = ($1, $3);
eval {
- die "duplicate attribute\n" if defined($config->{$k});
- if (!$unknown) {
- $v = $plugin->check_value($type, $k, $v, $sectionId);
+ if ($is_array->($type, $k)) {
+ if (!$unknown) {
+ $v = $plugin->check_value($type, $k, $v, $sectionId);
+ }
+ $config->{$k} = [] if !defined($config->{$k});
+ push $config->{$k}->@*, $v;
+ } else {
+ die "duplicate attribute\n" if defined($config->{$k});
+ if (!$unknown) {
+ $v = $plugin->check_value($type, $k, $v, $sectionId);
+ }
+ $config->{$k} = $v;
}
- $config->{$k} = $v;
};
if (my $err = $@) {
warn "$errprefix (section '$sectionId') - unable to parse value of '$k': $err";
@@ -448,6 +473,13 @@ my $format_config_line = sub {
if ($ct eq 'boolean') {
return "\t$key " . ($value ? 1 : 0) . "\n"
if defined($value);
+ } elsif ($ct eq 'array') {
+ die "property '$key' is not an array" if ref($value) ne 'ARRAY';
+ my $result = '';
+ for my $line ($value->@*) {
+ $result .= "\t$key $line\n" if $value ne '';
+ }
+ return $result;
} else {
return "\t$key $value\n" if "$value" ne '';
}
diff --git a/test/section_config_test.pl b/test/section_config_test.pl
index 22a9643..02242bc 100755
--- a/test/section_config_test.pl
+++ b/test/section_config_test.pl
@@ -105,6 +105,25 @@ sub properties {
minimum => 3,
maximum => 9,
},
+ arrayfield => {
+ description => "Array Field with property string",
+ type => 'array',
+ items => {
+ type => 'string',
+ description => 'a property string',
+ format => {
+ subfield1 => {
+ type => 'string',
+ description => 'first subfield'
+ },
+ subfield2 => {
+ type => 'integer',
+ minimum => 0,
+ optional => 1,
+ },
+ },
+ },
+ },
};
}
@@ -113,6 +132,7 @@ sub options {
common => { optional => 1 },
field2 => {},
another => {},
+ arrayfield => { optional => 1 },
};
}
@@ -190,6 +210,10 @@ my $with_unknown_data = {
type => 'two',
field2 => 5,
another => 'even more text',
+ arrayfield => [
+ 'subfield1=test,subfield2=2',
+ 'subfield1=test2',
+ ],
},
invalid => {
type => 'bad',
@@ -214,6 +238,8 @@ bad: invalid
two: t3
field2 5
another even more text
+ arrayfield subfield1=test,subfield2=2
+ arrayfield subfield1=test2
EOF
Conf->expect_fail('unknown-forbidden', $with_unknown_data, $with_unknown_text);
--
2.30.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [pve-devel] [PATCH common v2 3/3] JSONSchema: disable '-alist' format
2023-06-06 8:39 [pve-devel] [PATCH common/http/guest-common/qemu-server v2] schema/config array support Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH common v2 1/3] JSONSchema: add support for array parameter in api calls, cli and config Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH common v2 2/3] section config: implement array support Dominik Csapak
@ 2023-06-06 8:39 ` Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH http-server v2 1/2] proxy request: forward json content type and parameters Dominik Csapak
` (3 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: Dominik Csapak @ 2023-06-06 8:39 UTC (permalink / raw)
To: pve-devel
this should not be needed anymore since we can now use a simple array
in the api instead
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
src/PVE/JSONSchema.pm | 14 ++------------
1 file changed, 2 insertions(+), 12 deletions(-)
diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm
index 526fc2b..b148ce9 100644
--- a/src/PVE/JSONSchema.pm
+++ b/src/PVE/JSONSchema.pm
@@ -795,7 +795,7 @@ sub check_format {
return if $format eq 'regex';
my $parsed;
- $format =~ m/^(.*?)(?:-a?(list|opt))?$/;
+ $format =~ m/^(.*?)(?:-(list|opt))?$/;
my ($format_name, $format_type) = ($1, $2 // 'none');
my $registered = get_format($format_name);
die "undefined format '$format'\n" if !$registered;
@@ -1707,7 +1707,7 @@ sub get_options {
} elsif ($pd->{type} eq 'boolean') {
push @getopt, "$prop:s";
} else {
- if ($pd->{format} && $pd->{format} =~ m/-a?list/) {
+ if ($pd->{format} && $pd->{format} =~ m/-list/) {
push @getopt, "$prop=s@";
} elsif ($pd->{type} eq 'array') {
push @getopt, "$prop=s@";
@@ -1812,16 +1812,6 @@ sub get_options {
# allow --vmid 100 --vmid 101 and --vmid 100,101
# allow --dow mon --dow fri and --dow mon,fri
$opts->{$p} = join(",", @{$opts->{$p}}) if ref($opts->{$p}) eq 'ARRAY';
- } elsif ($pd->{format} =~ m/-alist/) {
- # we encode array as \0 separated strings
- # Note: CGI.pm also use this encoding
- if (scalar(@{$opts->{$p}}) != 1) {
- $opts->{$p} = join("\0", @{$opts->{$p}});
- } else {
- # st that split_list knows it is \0 terminated
- my $v = $opts->{$p}->[0];
- $opts->{$p} = "$v\0";
- }
}
}
}
--
2.30.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [pve-devel] [PATCH http-server v2 1/2] proxy request: forward json content type and parameters
2023-06-06 8:39 [pve-devel] [PATCH common/http/guest-common/qemu-server v2] schema/config array support Dominik Csapak
` (2 preceding siblings ...)
2023-06-06 8:39 ` [pve-devel] [PATCH common v2 3/3] JSONSchema: disable '-alist' format Dominik Csapak
@ 2023-06-06 8:39 ` Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH http-server v2 2/2] use proper arrays for array parameter Dominik Csapak
` (2 subsequent siblings)
6 siblings, 0 replies; 14+ messages in thread
From: Dominik Csapak @ 2023-06-06 8:39 UTC (permalink / raw)
To: pve-devel
instead of always trying to encode them as x-www-form-urlencoded
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
src/PVE/APIServer/AnyEvent.pm | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/src/PVE/APIServer/AnyEvent.pm b/src/PVE/APIServer/AnyEvent.pm
index b2ae99b..e9d87b3 100644
--- a/src/PVE/APIServer/AnyEvent.pm
+++ b/src/PVE/APIServer/AnyEvent.pm
@@ -745,11 +745,16 @@ sub proxy_request {
my $content;
if ($method eq 'POST' || $method eq 'PUT') {
- $headers->{'Content-Type'} = 'application/x-www-form-urlencoded';
- # use URI object to format application/x-www-form-urlencoded content.
- my $url = URI->new('http:');
- $url->query_form(%$params);
- $content = $url->query;
+ if ($reqstate->{request}->header('Content-Type') =~ 'application/json') {
+ $headers->{'Content-Type'} = 'application/json';
+ $content = encode_json($params);
+ } else {
+ $headers->{'Content-Type'} = 'application/x-www-form-urlencoded';
+ # use URI object to format application/x-www-form-urlencoded content.
+ my $url = URI->new('http:');
+ $url->query_form(%$params);
+ $content = $url->query;
+ }
if (defined($content)) {
$headers->{'Content-Length'} = length($content);
}
--
2.30.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [pve-devel] [PATCH http-server v2 2/2] use proper arrays for array parameter
2023-06-06 8:39 [pve-devel] [PATCH common/http/guest-common/qemu-server v2] schema/config array support Dominik Csapak
` (3 preceding siblings ...)
2023-06-06 8:39 ` [pve-devel] [PATCH http-server v2 1/2] proxy request: forward json content type and parameters Dominik Csapak
@ 2023-06-06 8:39 ` Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH guest-common v2 1/1] vzdump: change 'exclude-path' from alist to an array format Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH qemu-server v2 1/1] api: switch agent api call to 'array' type Dominik Csapak
6 siblings, 0 replies; 14+ messages in thread
From: Dominik Csapak @ 2023-06-06 8:39 UTC (permalink / raw)
To: pve-devel
since there is no other way to get an array parameter when using
x-www-form-urlencoded content type
the previous format with \0 separated strings (known as '-alist' format)
should not be used anymore (in favor of the now supported arrays)
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
src/PVE/APIServer/AnyEvent.pm | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/PVE/APIServer/AnyEvent.pm b/src/PVE/APIServer/AnyEvent.pm
index e9d87b3..e56a196 100644
--- a/src/PVE/APIServer/AnyEvent.pm
+++ b/src/PVE/APIServer/AnyEvent.pm
@@ -850,7 +850,12 @@ sub decode_urlencoded {
$v = Encode::decode('utf8', $v);
if (defined(my $old = $res->{$k})) {
- $v = "$old\0$v";
+ if (ref($old) eq 'ARRAY') {
+ push @$old, $v;
+ $v = $old;
+ } else {
+ $v = [$old, $v];
+ }
}
}
--
2.30.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [pve-devel] [PATCH guest-common v2 1/1] vzdump: change 'exclude-path' from alist to an array format
2023-06-06 8:39 [pve-devel] [PATCH common/http/guest-common/qemu-server v2] schema/config array support Dominik Csapak
` (4 preceding siblings ...)
2023-06-06 8:39 ` [pve-devel] [PATCH http-server v2 2/2] use proper arrays for array parameter Dominik Csapak
@ 2023-06-06 8:39 ` Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH qemu-server v2 1/1] api: switch agent api call to 'array' type Dominik Csapak
6 siblings, 0 replies; 14+ messages in thread
From: Dominik Csapak @ 2023-06-06 8:39 UTC (permalink / raw)
To: pve-devel
to get rid of the '-alist' format
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
src/PVE/VZDump/Common.pm | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/PVE/VZDump/Common.pm b/src/PVE/VZDump/Common.pm
index 4b0e8e0..7d3c311 100644
--- a/src/PVE/VZDump/Common.pm
+++ b/src/PVE/VZDump/Common.pm
@@ -154,11 +154,14 @@ my $confdesc = {
optional => 1,
},
'exclude-path' => {
- type => 'string', format => 'string-alist',
+ type => 'array',
description => "Exclude certain files/directories (shell globs)." .
" Paths starting with '/' are anchored to the container's root, " .
" other paths match relative to each subdirectory.",
optional => 1,
+ items => {
+ type => 'string',
+ },
},
mailto => {
type => 'string',
@@ -422,7 +425,7 @@ sub command_line {
my $v = $param->{$p};
my $pd = $confdesc->{$p} || die "no such vzdump option '$p'\n";
if ($p eq 'exclude-path') {
- foreach my $path (split(/\0/, $v || '')) {
+ foreach my $path (@$v) {
$cmd .= " --$p " . PVE::Tools::shellquote($path);
}
} else {
--
2.30.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [pve-devel] [PATCH qemu-server v2 1/1] api: switch agent api call to 'array' type
2023-06-06 8:39 [pve-devel] [PATCH common/http/guest-common/qemu-server v2] schema/config array support Dominik Csapak
` (5 preceding siblings ...)
2023-06-06 8:39 ` [pve-devel] [PATCH guest-common v2 1/1] vzdump: change 'exclude-path' from alist to an array format Dominik Csapak
@ 2023-06-06 8:39 ` Dominik Csapak
6 siblings, 0 replies; 14+ messages in thread
From: Dominik Csapak @ 2023-06-06 8:39 UTC (permalink / raw)
To: pve-devel
we don't want to use the '-alist' formats anymore in favor of real arrays
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
PVE/API2/Qemu/Agent.pm | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/PVE/API2/Qemu/Agent.pm b/PVE/API2/Qemu/Agent.pm
index 5ff1fa9d..dceee770 100644
--- a/PVE/API2/Qemu/Agent.pm
+++ b/PVE/API2/Qemu/Agent.pm
@@ -274,10 +274,12 @@ __PACKAGE__->register_method({
vmid => get_standard_option('pve-vmid', {
completion => \&PVE::QemuServer::complete_vmid_running }),
command => {
- type => 'string',
- format => 'string-alist',
- description => 'The command as a list of program + arguments',
- optional => 1,
+ type => 'array',
+ description => 'The command as a list of program + arguments.',
+ items => {
+ format => 'string',
+ description => 'A single part of the program + arguments.',
+ }
},
'input-data' => {
type => 'string',
@@ -300,10 +302,7 @@ __PACKAGE__->register_method({
my ($param) = @_;
my $vmid = $param->{vmid};
- my $cmd = undef;
- if ($param->{command}) {
- $cmd = [PVE::Tools::split_list($param->{command})];
- }
+ my $cmd = $param->{command};
my $res = PVE::QemuServer::Agent::qemu_exec($vmid, $param->{'input-data'}, $cmd);
return $res;
--
2.30.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [pve-devel] [PATCH common v2 1/3] JSONSchema: add support for array parameter in api calls, cli and config
2023-06-06 8:39 ` [pve-devel] [PATCH common v2 1/3] JSONSchema: add support for array parameter in api calls, cli and config Dominik Csapak
@ 2023-06-06 9:12 ` Thomas Lamprecht
2023-06-06 9:41 ` Dominik Csapak
0 siblings, 1 reply; 14+ messages in thread
From: Thomas Lamprecht @ 2023-06-06 9:12 UTC (permalink / raw)
To: Proxmox VE development discussion, Dominik Csapak
Am 06/06/2023 um 10:39 schrieb Dominik Csapak:
> a few things were missing for it to work:
> * on the cli, we have to get the option as an array if the type is an
> array
> * the untainting must be done recursively, otherwise, the regex matching
> converts an array hash into the string 'ARRAY(0x123412341234)'
> * JSONSchema::parse_config did not handle array formats specially, but
> we want to allow to specify them multiple time
> * the biggest point: in the RESTHandler, to be compatible with the
> current gui behavior, we have to rewrite two parameter types:
> - when the api defines a '-list' format for a string type, but we get
> a list (because of the changes in http-server), we join the list
> with a comma into a string
> - when the api defines an 'array' type, but we get a scalar value,
> wrap the value in an array (because for www-form-urlencoded, you
> cannot send an array with a single value) add tests for this
> behavior, some of which we want to deprecate and remove in the
> future
>
> Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
> ---
> changes from v1:
> * include wolfangs feedback
> * include auto-conversion from string <-> list where appropriate and add
> tests for it
>
> src/PVE/JSONSchema.pm | 12 +++++
> src/PVE/RESTHandler.pm | 61 ++++++++++++++++++----
> test/Makefile | 9 +++-
> test/api_parameter_test.pl | 100 +++++++++++++++++++++++++++++++++++++
> 4 files changed, 172 insertions(+), 10 deletions(-)
> create mode 100755 test/api_parameter_test.pl
>
> diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm
> index 527e409..526fc2b 100644
> --- a/src/PVE/JSONSchema.pm
> +++ b/src/PVE/JSONSchema.pm
> @@ -1709,6 +1709,8 @@ sub get_options {
> } else {
> if ($pd->{format} && $pd->{format} =~ m/-a?list/) {
> push @getopt, "$prop=s@";
> + } elsif ($pd->{type} eq 'array') {
> + push @getopt, "$prop=s@";
> } else {
> push @getopt, "$prop=s";
> }
> @@ -1869,6 +1871,16 @@ sub parse_config : prototype($$$;$) {
>
> $value = parse_boolean($value) // $value;
> }
> + if ($schema->{properties}->{$key} &&
> + $schema->{properties}->{$key}->{type} eq 'array') {
code style, and can be fixed up:
for multi-line if's place the closing parenthesis and opening block { on it's own line:
It also doesn't hurt to move all expressions part of the condition in a separate line
(albeit that part is not a rule in our style guide):
if (
$schema->{properties}->{$key}
&& $schema->{properties}->{$key}->{type} eq 'array'
) {
# ...
> +
> + if (defined($cfg->{$key})) {
> + push $cfg->{$key}->@*, $value;
> + } else {
> + $cfg->{$key} = [$value];
> + }
Could be written shorter, but just fine as above
$cfg->{$key} //= [];
push $cfg->{$key}->@*, $value;
> + next;
> + }
> $cfg->{$key} = $value;
> } else {
> warn "ignore config line: $line\n"
> diff --git a/src/PVE/RESTHandler.pm b/src/PVE/RESTHandler.pm
> index db86af2..369e302 100644
> --- a/src/PVE/RESTHandler.pm
> +++ b/src/PVE/RESTHandler.pm
> @@ -426,6 +426,56 @@ sub find_handler {
> return ($handler_class, $method_info);
> }
>
> +my $untaint_recursive;
I got flash backs w.r.t. refcount cycles here keeping all variables, and thus memory
inside the body alive forever, don't we need a weaken?
E.g., like we had to do in PVE::Status::Graphite's assemble.
> +
> +$untaint_recursive = sub {
> + my ($param) = @_;
> +
> + my $ref = ref($param);
> + if ($ref eq 'HASH') {
> + $param->{$_} = $untaint_recursive->($param->{$_}) for keys $param->%*;
> + } elsif ($ref eq 'ARRAY') {
> + for (my $i = 0; $i < scalar($param->@*); $i++) {
> + $param->[$i] = $untaint_recursive->($param->[$i]);
> + }
> + } else {
> + if (defined($param)) {
could be merged into upper branch as elsif, but no hard feelings.
> + my ($newval) = $param =~ /^(.*)$/s;
> + $param = $newval;
> + }
> + }
> +
> + return $param;
> +};
> +
> +# convert arrays to strings where we expect a '-list' format and convert scalar
> +# values to arrays when we expect an array (because of www-form-urlencoded)
> +#
> +# only on the top level, since www-form-urlencoded cannot be nested anyway
> +#
> +# FIXME: change gui/api calls to not rely on this during 8.x, mark the
> +# behaviour deprecated with 9.x, and remove it with 10.x
> +my $convert_params = sub { my ($param, $schema) = @_;
please keep the method paramethers on it's own line.
Also, maybe go for a more telling names, as convert_params could mean everytrhing
and nothing ^^
> +
> + return if !$schema->{properties};
> + return if (ref($param) // '') ne 'HASH';
doesn't this breaks the assignment when used below? I.e.,:
$param = $convert_params->($param, $schema);
or messes with silenting parameters sent to a endpoint without properties, which would
create an extra param error otherwise?
> +
> + for my $key (keys $schema->{properties}->%*) {
> + if (my $value = $param->{$key}) {
> + my $type = $schema->{properties}->{$key}->{type} // '';
> + my $format = $schema->{properties}->{$key}->{format} // '';
> + my $ref = ref($value);
> + if ($ref eq 'ARRAY' && $type eq 'string' && $format =~ m/-list$/) {
Should this also check ref to not be undef, i.e.
if ($ref && $ref eq 'ARRAY' && ...
> + $param->{$key} = join(',', $value->@*);
> + } elsif (!$ref && $type eq 'array') {
> + $param->{$key} = [$value];
> + }
> + }
> + }
> +
> + return $param;
> +};
> +
> sub handle {
> my ($self, $info, $param, $result_verification) = @_;
>
> @@ -437,17 +487,10 @@ sub handle {
>
> if (my $schema = $info->{parameters}) {
> # warn "validate ". Dumper($param}) . "\n" . Dumper($schema);
> + $param = $convert_params->($param, $schema);
> PVE::JSONSchema::validate($param, $schema);
> # untaint data (already validated)
> - my $extra = delete $param->{'extra-args'};
> - while (my ($key, $val) = each %$param) {
> - if (defined($val)) {
> - ($param->{$key}) = $val =~ /^(.*)$/s;
> - } else {
> - $param->{$key} = undef;
> - }
> - }
> - $param->{'extra-args'} = [map { /^(.*)$/ } @$extra] if $extra;
> + $param = $untaint_recursive->($param);
> }
>
> my $result = $func->($param); # the actual API code execution call
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [pve-devel] [PATCH common v2 1/3] JSONSchema: add support for array parameter in api calls, cli and config
2023-06-06 9:12 ` Thomas Lamprecht
@ 2023-06-06 9:41 ` Dominik Csapak
2023-06-06 10:45 ` Thomas Lamprecht
0 siblings, 1 reply; 14+ messages in thread
From: Dominik Csapak @ 2023-06-06 9:41 UTC (permalink / raw)
To: Thomas Lamprecht, Proxmox VE development discussion
On 6/6/23 11:12, Thomas Lamprecht wrote:
> Am 06/06/2023 um 10:39 schrieb Dominik Csapak:
>> a few things were missing for it to work:
>> * on the cli, we have to get the option as an array if the type is an
>> array
>> * the untainting must be done recursively, otherwise, the regex matching
>> converts an array hash into the string 'ARRAY(0x123412341234)'
>> * JSONSchema::parse_config did not handle array formats specially, but
>> we want to allow to specify them multiple time
>> * the biggest point: in the RESTHandler, to be compatible with the
>> current gui behavior, we have to rewrite two parameter types:
>> - when the api defines a '-list' format for a string type, but we get
>> a list (because of the changes in http-server), we join the list
>> with a comma into a string
>> - when the api defines an 'array' type, but we get a scalar value,
>> wrap the value in an array (because for www-form-urlencoded, you
>> cannot send an array with a single value) add tests for this
>> behavior, some of which we want to deprecate and remove in the
>> future
>>
>> Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
>> ---
>> changes from v1:
>> * include wolfangs feedback
>> * include auto-conversion from string <-> list where appropriate and add
>> tests for it
>>
>> src/PVE/JSONSchema.pm | 12 +++++
>> src/PVE/RESTHandler.pm | 61 ++++++++++++++++++----
>> test/Makefile | 9 +++-
>> test/api_parameter_test.pl | 100 +++++++++++++++++++++++++++++++++++++
>> 4 files changed, 172 insertions(+), 10 deletions(-)
>> create mode 100755 test/api_parameter_test.pl
>>
>> diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm
>> index 527e409..526fc2b 100644
>> --- a/src/PVE/JSONSchema.pm
>> +++ b/src/PVE/JSONSchema.pm
>> @@ -1709,6 +1709,8 @@ sub get_options {
>> } else {
>> if ($pd->{format} && $pd->{format} =~ m/-a?list/) {
>> push @getopt, "$prop=s@";
>> + } elsif ($pd->{type} eq 'array') {
>> + push @getopt, "$prop=s@";
>> } else {
>> push @getopt, "$prop=s";
>> }
>> @@ -1869,6 +1871,16 @@ sub parse_config : prototype($$$;$) {
>>
>> $value = parse_boolean($value) // $value;
>> }
>> + if ($schema->{properties}->{$key} &&
>> + $schema->{properties}->{$key}->{type} eq 'array') {
>
> code style, and can be fixed up:
> for multi-line if's place the closing parenthesis and opening block { on it's own line:
>
> It also doesn't hurt to move all expressions part of the condition in a separate line
> (albeit that part is not a rule in our style guide):
>
> if (
> $schema->{properties}->{$key}
> && $schema->{properties}->{$key}->{type} eq 'array'
> ) {
> # ...
>
sure, sorry
>> +
>> + if (defined($cfg->{$key})) {
>> + push $cfg->{$key}->@*, $value;
>> + } else {
>> + $cfg->{$key} = [$value];
>> + }
>
> Could be written shorter, but just fine as above
>
> $cfg->{$key} //= [];
> push $cfg->{$key}->@*, $value;
yours is shorter and still understandable
>
>> + next;
>> + }
>> $cfg->{$key} = $value;
>> } else {
>> warn "ignore config line: $line\n"
>> diff --git a/src/PVE/RESTHandler.pm b/src/PVE/RESTHandler.pm
>> index db86af2..369e302 100644
>> --- a/src/PVE/RESTHandler.pm
>> +++ b/src/PVE/RESTHandler.pm
>> @@ -426,6 +426,56 @@ sub find_handler {
>> return ($handler_class, $method_info);
>> }
>>
>> +my $untaint_recursive;
>
> I got flash backs w.r.t. refcount cycles here keeping all variables, and thus memory
> inside the body alive forever, don't we need a weaken?
>
> E.g., like we had to do in PVE::Status::Graphite's assemble.
mhmm isn't that because there we use variables from outside the
function? here we only use the parameters themselves
anyway the solution there is to set the sub to undef after use, but
we can do that here only if we move the sub into the regular
function
i can also make it a proper sub if that's better?
how can i test for these things properly?
>> +
>> +$untaint_recursive = sub {
>> + my ($param) = @_;
>> +
>> + my $ref = ref($param);
>> + if ($ref eq 'HASH') {
>> + $param->{$_} = $untaint_recursive->($param->{$_}) for keys $param->%*;
>> + } elsif ($ref eq 'ARRAY') {
>> + for (my $i = 0; $i < scalar($param->@*); $i++) {
>> + $param->[$i] = $untaint_recursive->($param->[$i]);
>> + }
>> + } else {
>> + if (defined($param)) {
>
> could be merged into upper branch as elsif, but no hard feelings.
>
>> + my ($newval) = $param =~ /^(.*)$/s;
>> + $param = $newval;
>> + }
>> + }
>> +
>> + return $param;
>> +};
>> +
>> +# convert arrays to strings where we expect a '-list' format and convert scalar
>> +# values to arrays when we expect an array (because of www-form-urlencoded)
>> +#
>> +# only on the top level, since www-form-urlencoded cannot be nested anyway
>> +#
>> +# FIXME: change gui/api calls to not rely on this during 8.x, mark the
>> +# behaviour deprecated with 9.x, and remove it with 10.x
>> +my $convert_params = sub { my ($param, $schema) = @_;
>
> please keep the method paramethers on it's own line.
oops, one shift+j to many without noticing^^
>
> Also, maybe go for a more telling names, as convert_params could mean everytrhing
> and nothing ^^
>
sure, any suggestions? ;)
>
>
>> +
>> + return if !$schema->{properties};
>> + return if (ref($param) // '') ne 'HASH';
>
> doesn't this breaks the assignment when used below? I.e.,:
>
> $param = $convert_params->($param, $schema);
>
> or messes with silenting parameters sent to a endpoint without properties, which would
> create an extra param error otherwise?
yes, we have to return the original param here in both cases
>
>> +
>> + for my $key (keys $schema->{properties}->%*) {
>> + if (my $value = $param->{$key}) {
>> + my $type = $schema->{properties}->{$key}->{type} // '';
>> + my $format = $schema->{properties}->{$key}->{format} // '';
>> + my $ref = ref($value);
>> + if ($ref eq 'ARRAY' && $type eq 'string' && $format =~ m/-list$/) {
>
> Should this also check ref to not be undef, i.e.
>
> if ($ref && $ref eq 'ARRAY' && ...
>
yes
>
>> + $param->{$key} = join(',', $value->@*);
>> + } elsif (!$ref && $type eq 'array') {
>> + $param->{$key} = [$value];
>> + }
>> + }
>> + }
>> +
>> + return $param;
>> +};
>> +
>> sub handle {
>> my ($self, $info, $param, $result_verification) = @_;
>>
>> @@ -437,17 +487,10 @@ sub handle {
>>
>> if (my $schema = $info->{parameters}) {
>> # warn "validate ". Dumper($param}) . "\n" . Dumper($schema);
>> + $param = $convert_params->($param, $schema);
>> PVE::JSONSchema::validate($param, $schema);
>> # untaint data (already validated)
>> - my $extra = delete $param->{'extra-args'};
>> - while (my ($key, $val) = each %$param) {
>> - if (defined($val)) {
>> - ($param->{$key}) = $val =~ /^(.*)$/s;
>> - } else {
>> - $param->{$key} = undef;
>> - }
>> - }
>> - $param->{'extra-args'} = [map { /^(.*)$/ } @$extra] if $extra;
>> + $param = $untaint_recursive->($param);
>> }
>>
>> my $result = $func->($param); # the actual API code execution call
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [pve-devel] [PATCH common v2 1/3] JSONSchema: add support for array parameter in api calls, cli and config
2023-06-06 9:41 ` Dominik Csapak
@ 2023-06-06 10:45 ` Thomas Lamprecht
2023-06-06 11:19 ` Dominik Csapak
2023-06-06 12:05 ` Wolfgang Bumiller
0 siblings, 2 replies; 14+ messages in thread
From: Thomas Lamprecht @ 2023-06-06 10:45 UTC (permalink / raw)
To: Proxmox VE development discussion, Dominik Csapak
Am 06/06/2023 um 11:41 schrieb Dominik Csapak:
>>> +my $untaint_recursive;
>>
>> I got flash backs w.r.t. refcount cycles here keeping all variables, and thus memory
>> inside the body alive forever, don't we need a weaken?
>>
>> E.g., like we had to do in PVE::Status::Graphite's assemble.
>
> mhmm isn't that because there we use variables from outside the
> function? here we only use the parameters themselves
I'm not 100% sure about the details, but since then, seeing something like
this pattern triggers my cycle instincts, I'd like to have that checked out
closely.
>
> anyway the solution there is to set the sub to undef after use, but
> we can do that here only if we move the sub into the regular
> function
>
> i can also make it a proper sub if that's better?
>
> how can i test for these things properly?
easiest: pass large hashes and loop, then see if memory goes up. For metrics
back then you could see the RSS of pbvestatd grow by ~ the metric data size
every update.
What I also used back then, IIRC, was the Devel::Cycle module, it should give
you a more specific answer if there's a cycle, but naturally has no idea what
the practical implications are.
>>> +# convert arrays to strings where we expect a '-list' format and convert scalar
>>> +# values to arrays when we expect an array (because of www-form-urlencoded)
>>> +#
>>> +# only on the top level, since www-form-urlencoded cannot be nested anyway
>>> +#
>>> +# FIXME: change gui/api calls to not rely on this during 8.x, mark the
>>> +# behaviour deprecated with 9.x, and remove it with 10.x
>>> +my $convert_params = sub { my ($param, $schema) = @_;
>>
>> please keep the method paramethers on it's own line.
>
> oops, one shift+j to many without noticing^^
>
>>
>> Also, maybe go for a more telling names, as convert_params could mean everytrhing
>> and nothing ^^
>>
>
> sure, any suggestions? 😉
sure, lets start with what this actually does in more explicit steps:
1) normalize_form_data
still a bit general but we now know that it handles form data and normalizes it to a
single representation
2) normalize_param_list_to_array
A bit more telling about what happens.
3) convert_legacy_list_format_to_array
very telling, but as this is a internal helper, and thus not used elsewhere, that
wouldn't hurt, having "legacy" in it underlines that we want to drop it sometimes.
Personally, I'd favor 3) or 2).
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [pve-devel] [PATCH common v2 1/3] JSONSchema: add support for array parameter in api calls, cli and config
2023-06-06 10:45 ` Thomas Lamprecht
@ 2023-06-06 11:19 ` Dominik Csapak
2023-06-06 11:24 ` Thomas Lamprecht
2023-06-06 12:05 ` Wolfgang Bumiller
1 sibling, 1 reply; 14+ messages in thread
From: Dominik Csapak @ 2023-06-06 11:19 UTC (permalink / raw)
To: Thomas Lamprecht, Proxmox VE development discussion
On 6/6/23 12:45, Thomas Lamprecht wrote:
> Am 06/06/2023 um 11:41 schrieb Dominik Csapak:
>>>> +my $untaint_recursive;
>>>
>>> I got flash backs w.r.t. refcount cycles here keeping all variables, and thus memory
>>> inside the body alive forever, don't we need a weaken?
>>>
>>> E.g., like we had to do in PVE::Status::Graphite's assemble.
>>
>> mhmm isn't that because there we use variables from outside the
>> function? here we only use the parameters themselves
>
> I'm not 100% sure about the details, but since then, seeing something like
> this pattern triggers my cycle instincts, I'd like to have that checked out
> closely.
>
sure
>>
>> anyway the solution there is to set the sub to undef after use, but
>> we can do that here only if we move the sub into the regular
>> function
>>
>> i can also make it a proper sub if that's better?
>>
>
>
>
>> how can i test for these things properly?
>
> easiest: pass large hashes and loop, then see if memory goes up. For metrics
> back then you could see the RSS of pbvestatd grow by ~ the metric data size
> every update.
>
>
> What I also used back then, IIRC, was the Devel::Cycle module, it should give
> you a more specific answer if there's a cycle, but naturally has no idea what
> the practical implications are.
i wrote a small program where i copied the function to and did basically:
---8<---
use Storable qw(dclone);
my $normalize;
$normalize = sub {...};
my $data = /* create large hash here, with nested data */;
while(1) {
my $newdata = dclone($data);
$newdata = $normalize->($newdata);
}
--->8---
executed it and monitored the rss usage, while letting it run for multiple minutes
the memory usage increased after the initial creation of the hash, and the first
dclone, but not after.
is that a sufficient test?
>
>>>> +# convert arrays to strings where we expect a '-list' format and convert scalar
>>>> +# values to arrays when we expect an array (because of www-form-urlencoded)
>>>> +#
>>>> +# only on the top level, since www-form-urlencoded cannot be nested anyway
>>>> +#
>>>> +# FIXME: change gui/api calls to not rely on this during 8.x, mark the
>>>> +# behaviour deprecated with 9.x, and remove it with 10.x
>>>> +my $convert_params = sub { my ($param, $schema) = @_;
>>>
>>> please keep the method paramethers on it's own line.
>>
>> oops, one shift+j to many without noticing^^
>>
>>>
>>> Also, maybe go for a more telling names, as convert_params could mean everytrhing
>>> and nothing ^^
>>>
>>
>> sure, any suggestions? 😉
>
> sure, lets start with what this actually does in more explicit steps:
>
> 1) normalize_form_data
> still a bit general but we now know that it handles form data and normalizes it to a
> single representation
>
>
> 2) normalize_param_list_to_array
> A bit more telling about what happens.
>
>
> 3) convert_legacy_list_format_to_array
> very telling, but as this is a internal helper, and thus not used elsewhere, that
> wouldn't hurt, having "legacy" in it underlines that we want to drop it sometimes.
>
> Personally, I'd favor 3) or 2).
mhmm both are ok for me, but it also does the reverse
(convert an array to a legacy list so to speak)
maybe i'd use something like 'normalize_legacy_param_formats' ?
it's a bit more general than 2,3 but still has legacy in its name...
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [pve-devel] [PATCH common v2 1/3] JSONSchema: add support for array parameter in api calls, cli and config
2023-06-06 11:19 ` Dominik Csapak
@ 2023-06-06 11:24 ` Thomas Lamprecht
0 siblings, 0 replies; 14+ messages in thread
From: Thomas Lamprecht @ 2023-06-06 11:24 UTC (permalink / raw)
To: Dominik Csapak, Proxmox VE development discussion
Am 06/06/2023 um 13:19 schrieb Dominik Csapak:
> ---8<---
> use Storable qw(dclone);
>
> my $normalize;
> $normalize = sub {...};
>
> my $data = /* create large hash here, with nested data */;
>
> while(1) {
> my $newdata = dclone($data);
> $newdata = $normalize->($newdata);
> }
> --->8---
>
>
> executed it and monitored the rss usage, while letting it run for multiple minutes
> the memory usage increased after the initial creation of the hash, and the first
> dclone, but not after.
>
> is that a sufficient test?
yeah, seems fine enough to me.
> maybe i'd use something like 'normalize_legacy_param_formats' ?
would be an improvement over the original convert_params and fine enough for me.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [pve-devel] [PATCH common v2 1/3] JSONSchema: add support for array parameter in api calls, cli and config
2023-06-06 10:45 ` Thomas Lamprecht
2023-06-06 11:19 ` Dominik Csapak
@ 2023-06-06 12:05 ` Wolfgang Bumiller
1 sibling, 0 replies; 14+ messages in thread
From: Wolfgang Bumiller @ 2023-06-06 12:05 UTC (permalink / raw)
To: Thomas Lamprecht; +Cc: Proxmox VE development discussion, Dominik Csapak
On Tue, Jun 06, 2023 at 12:45:57PM +0200, Thomas Lamprecht wrote:
> Am 06/06/2023 um 11:41 schrieb Dominik Csapak:
> >>> +my $untaint_recursive;
> >>
> >> I got flash backs w.r.t. refcount cycles here keeping all variables, and thus memory
> >> inside the body alive forever, don't we need a weaken?
> >>
> >> E.g., like we had to do in PVE::Status::Graphite's assemble.
> >
> > mhmm isn't that because there we use variables from outside the
> > function? here we only use the parameters themselves
>
> I'm not 100% sure about the details, but since then, seeing something like
> this pattern triggers my cycle instincts, I'd like to have that checked out
> closely.
I *do* prefer `my sub` these days.
However, for recursive subs you need to `use feature 'current_sub'` to
avoid ... well... leaks ;-)
So:
my sub untaint_recursive : prototype($) {
use feature 'current_sub';
my ($arg) = @_;
...
# For recursion:
__SUB__->($stuff);
...
}
Given that this function shouldn't be leaky, you could keep it, or even
pre-declare the sub to allow recursion:
my sub untaint_recursive : prototype($);
sub untaint_recursive : prototype($) {
<regular code>
}
however, `perlsub` explicitly states that this, too, can leak ;-)
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2023-06-06 12:05 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-06 8:39 [pve-devel] [PATCH common/http/guest-common/qemu-server v2] schema/config array support Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH common v2 1/3] JSONSchema: add support for array parameter in api calls, cli and config Dominik Csapak
2023-06-06 9:12 ` Thomas Lamprecht
2023-06-06 9:41 ` Dominik Csapak
2023-06-06 10:45 ` Thomas Lamprecht
2023-06-06 11:19 ` Dominik Csapak
2023-06-06 11:24 ` Thomas Lamprecht
2023-06-06 12:05 ` Wolfgang Bumiller
2023-06-06 8:39 ` [pve-devel] [PATCH common v2 2/3] section config: implement array support Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH common v2 3/3] JSONSchema: disable '-alist' format Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH http-server v2 1/2] proxy request: forward json content type and parameters Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH http-server v2 2/2] use proper arrays for array parameter Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH guest-common v2 1/1] vzdump: change 'exclude-path' from alist to an array format Dominik Csapak
2023-06-06 8:39 ` [pve-devel] [PATCH qemu-server v2 1/1] api: switch agent api call to 'array' type Dominik Csapak
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox