[pve-devel] [PATCH common 1/2] JSONSchema: add format validator support and cleanup check_format
Stefan Reiter
s.reiter at proxmox.com
Thu Apr 16 16:39:32 CEST 2020
Adds a third, optional parameter to register_format that allows specifying
a function that will be called after parsing and can validate the parsed
data. A validator should die on failed validation, and can also change the
parsed object by returning a modified version of it.
This is useful so one can register a format with its hash, thus allowing
documentation to be generated automatically, while still enforcing certain
validation rules.
And since I found it impossible to extend the current check_format code,
clean that function up as well (which pretty much amounts to a rewrite).
Also use get_format consistently to avoid future breakages.
No existing functionality is intentionally changed.
Signed-off-by: Stefan Reiter <s.reiter at proxmox.com>
---
@Fabian G.: Since we discussed this off-list, is this good? At least there
shouldn't be a possibility for a parser/hash format drift the way I've
implemented it.
src/PVE/JSONSchema.pm | 60 +++++++++++++++++++++++++++----------------
1 file changed, 38 insertions(+), 22 deletions(-)
diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm
index 01a3cce..106a812 100644
--- a/src/PVE/JSONSchema.pm
+++ b/src/PVE/JSONSchema.pm
@@ -120,19 +120,26 @@ register_standard_option('pve-snapshot-name', {
});
my $format_list = {};
+my $format_validators = {};
sub register_format {
- my ($format, $code) = @_;
+ my ($name, $format, $validator) = @_;
- die "JSON schema format '$format' already registered\n"
- if $format_list->{$format};
+ die "JSON schema format '$name' already registered\n"
+ if $format_list->{$name};
- $format_list->{$format} = $code;
+ if ($validator) {
+ die "A \$validator function can only be specified for hash-based formats\n"
+ if ref($format) ne 'HASH';
+ $format_validators->{$name} = $validator;
+ }
+
+ $format_list->{$name} = $format;
}
sub get_format {
- my ($format) = @_;
- return $format_list->{$format};
+ my ($name) = @_;
+ return $format_list->{$name};
}
my $renderer_hash = {};
@@ -646,13 +653,16 @@ sub pve_verify_tfa_secret {
sub check_format {
my ($format, $value, $path) = @_;
- return parse_property_string($format, $value, $path) if ref($format) eq 'HASH';
return if $format eq 'regex';
- if ($format =~ m/^(.*)-a?list$/) {
+ my $parsed;
- my $code = $format_list->{$1};
+ if (ref($format) eq 'HASH') {
+ # in case it's a hash we can't have a validator registered, so return
+ return parse_property_string($format, $value, $path);
+ } elsif ($format =~ m/^(.*)-a?list$/) {
+ my $code = get_format($1);
die "undefined format '$format'\n" if !$code;
# Note: we allow empty lists
@@ -660,25 +670,31 @@ sub check_format {
&$code($v);
}
- } elsif ($format =~ m/^(.*)-opt$/) {
-
- my $code = $format_list->{$1};
+ # since the list might contain multiple values, we don't allow running
+ # validator functions either
+ return undef;
+ } elsif ($format =~ m/^(.*)-opt$/) {
+ my $code = get_format($1);
die "undefined format '$format'\n" if !$code;
- return if !$value; # allow empty string
-
- &$code($value);
+ # empty string is allowed
+ $parsed = $code->($value) if $value;
} else {
+ my $registered_format = get_format($format);
+ die "undefined format '$format'\n" if !$registered_format;
- my $code = $format_list->{$format};
-
- die "undefined format '$format'\n" if !$code;
-
- return parse_property_string($code, $value, $path) if ref($code) eq 'HASH';
- &$code($value);
+ if (ref($registered_format) eq 'HASH') {
+ $parsed = parse_property_string($registered_format, $value, $path);
+ } else {
+ $parsed = $registered_format->($value);
+ }
}
+
+ my $validator = $format_validators->{$format};
+ $parsed = $validator->($parsed) if $validator;
+ return $parsed;
}
sub parse_size {
@@ -735,7 +751,7 @@ sub parse_property_string {
# Support named formats here, too:
if (!ref($format)) {
- if (my $desc = $format_list->{$format}) {
+ if (my $desc = get_format($format)) {
$format = $desc;
} else {
die "unknown format: $format\n";
--
2.26.1
More information about the pve-devel
mailing list