From 69d9edcc7529b42edf70ed808b583c4998e5ea07 Mon Sep 17 00:00:00 2001 From: Dominik Csapak Date: Tue, 6 Jun 2023 15:08:46 +0200 Subject: [PATCH] section config: implement array support 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 --- 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.39.5