X-Git-Url: https://git.proxmox.com/?p=pve-common.git;a=blobdiff_plain;f=src%2FPVE%2FJSONSchema.pm;h=45ce5ba58c3ad5720bdf727d4615ac2d4b8e34d7;hp=2837cf56378a766d5f5dbe93f8431eabfd1291a9;hb=40605176f349f031d890a2ebe4c4ee015c078eb6;hpb=c38ac70fe0212e878bacabfc57cef026c6451010 diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm index 2837cf5..45ce5ba 100644 --- a/src/PVE/JSONSchema.pm +++ b/src/PVE/JSONSchema.pm @@ -83,6 +83,13 @@ PVE::JSONSchema::register_standard_option('pve-config-digest', { maxLength => 40, # sha1 hex digest lenght is 40 }); +PVE::JSONSchema::register_standard_option('extra-args', { + description => "Extra arguments as array", + type => 'array', + items => { type => 'string' }, + optional => 1 +}); + my $format_list = {}; sub register_format { @@ -220,26 +227,70 @@ sub pve_verify_ipv4mask { return $mask; } -register_format('CIDR', \&pve_verify_cidr); -sub pve_verify_cidr { +register_format('CIDRv6', \&pve_verify_cidrv6); +sub pve_verify_cidrv6 { my ($cidr, $noerr) = @_; - if ($cidr =~ m!^(?:$IPV4RE)(?:/(\d+))$! && ($1 > 7) && ($1 < 32)) { + if ($cidr =~ m!^(?:$IPV6RE)(?:/(\d+))$! && ($1 > 7) && ($1 <= 120)) { return $cidr; - } elsif ($cidr =~ m!^(?:$IPV6RE)(?:/(\d+))$! && ($1 > 7) && ($1 <= 120)) { + } + + return undef if $noerr; + die "value does not look like a valid IPv6 CIDR network\n"; +} + +register_format('CIDRv4', \&pve_verify_cidrv4); +sub pve_verify_cidrv4 { + my ($cidr, $noerr) = @_; + + if ($cidr =~ m!^(?:$IPV4RE)(?:/(\d+))$! && ($1 > 7) && ($1 < 32)) { return $cidr; } return undef if $noerr; - die "value does not look like a valid CIDR network\n"; + die "value does not look like a valid IPv4 CIDR network\n"; +} + +register_format('CIDR', \&pve_verify_cidr); +sub pve_verify_cidr { + my ($cidr, $noerr) = @_; + + if (!(pve_verify_cidrv4($cidr, 1) || + pve_verify_cidrv6($cidr, 1))) + { + return undef if $noerr; + die "value does not look like a valid CIDR network\n"; + } + + return $cidr; +} + +register_format('pve-ipv4-config', \&pve_verify_ipv4_config); +sub pve_verify_ipv4_config { + my ($config, $noerr) = @_; + + return $config if $config =~ /^(?:dhcp|manual)$/ || + pve_verify_cidrv4($config, 1); + return undef if $noerr; + die "value does not look like a valid ipv4 network configuration\n"; +} + +register_format('pve-ipv6-config', \&pve_verify_ipv6_config); +sub pve_verify_ipv6_config { + my ($config, $noerr) = @_; + + return $config if $config =~ /^(?:auto|dhcp|manual)$/ || + pve_verify_cidrv6($config, 1); + return undef if $noerr; + die "value does not look like a valid ipv6 network configuration\n"; } register_format('email', \&pve_verify_email); sub pve_verify_email { my ($email, $noerr) = @_; - # we use same regex as extjs Ext.form.VTypes.email - if ($email !~ /^(\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,6}$/) { + # we use same regex as in Utils.js + if ($email !~ /^(\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,63}$/) { return undef if $noerr; die "value does not look like a valid email address\n"; } @@ -556,6 +607,19 @@ sub check_object { } } +sub check_object_warn { + my ($path, $schema, $value, $additional_properties) = @_; + my $errors = {}; + check_object($path, $schema, $value, $additional_properties, $errors); + if (scalar(%$errors)) { + foreach my $k (keys %$errors) { + warn "parse error: $k: $errors->{$k}\n"; + } + return 0; + } + return 1; +} + sub check_prop { my ($value, $schema, $path, $errors) = @_; @@ -790,6 +854,11 @@ my $default_schema_noref = { optional => 1, description => "This provides a description of the purpose the instance property. The value can be a string or it can be an object with properties corresponding to various different instance languages (with an optional default property indicating the default description).", }, + format_description => { + type => "string", + optional => 1, + description => "This provides a shorter (usually just one word) description for a property used to generate descriptions for comma separated list property strings.", + }, title => { type => "string", optional => 1, @@ -810,6 +879,11 @@ my $default_schema_noref = { optional => 1, description => "This indicates the default for the instance property." }, + completion => { + type => 'coderef', + description => "Bash completion function. This function should return a list of possible values.", + optional => 1, + }, disallow => { type => "object", optional => 1, @@ -955,6 +1029,11 @@ my $method_schema = { description => "JSON Schema for parameters.", optional => 1, }, + formatter => { + type => 'object', + description => "Used to store page formatter information (set by PVE::RESTHandler->register_page_formatter).", + optional => 1, + }, returns => { type => 'object', description => "JSON Schema for return value.", @@ -1070,20 +1149,30 @@ sub get_options { } } + Getopt::Long::Configure('prefix_pattern=(--|-)'); + my $opts = {}; raise("unable to parse option\n", code => HTTP_BAD_REQUEST) if !Getopt::Long::GetOptionsFromArray($args, $opts, @getopt); - if (my $acount = scalar(@$args)) { + if (@$args) { if ($list_param) { $opts->{$list_param} = $args; $args = []; } elsif (ref($arg_param)) { - raise("wrong number of arguments\n", code => HTTP_BAD_REQUEST) - if scalar(@$arg_param) != $acount; - foreach my $p (@$arg_param) { - $opts->{$p} = shift @$args; + foreach my $arg_name (@$arg_param) { + if ($opts->{'extra-args'}) { + raise("internal error: extra-args must be the last argument\n", code => HTTP_BAD_REQUEST); + } + if ($arg_name eq 'extra-args') { + $opts->{'extra-args'} = $args; + $args = []; + next; + } + raise("not enough arguments\n", code => HTTP_BAD_REQUEST) if !@$args; + $opts->{$arg_name} = shift @$args; } + raise("too many arguments\n", code => HTTP_BAD_REQUEST) if @$args; } else { raise("too many arguments\n", code => HTTP_BAD_REQUEST) if scalar(@$args) != 0; @@ -1117,7 +1206,7 @@ sub get_options { if ($pd->{format} =~ m/-list/) { # allow --vmid 100 --vmid 101 and --vmid 100,101 # allow --dow mon --dow fri and --dow mon,fri - $opts->{$p} = join(",", @{$opts->{$p}}); + $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 @@ -1200,4 +1289,41 @@ sub dump_config { return $data; } +sub generate_typetext { + my ($schema) = @_; + my $typetext = ''; + my (@optional, @required); + foreach my $key (sort keys %$schema) { + next if !$schema->{$key}->{format_description} && + !$schema->{$key}->{typetext}; + if ($schema->{$key}->{optional}) { + push @optional, $key; + } else { + push @required, $key; + } + } + my ($pre, $post) = ('', ''); + my $add = sub { + my ($key) = @_; + if (my $desc = $schema->{$key}->{format_description}) { + $typetext .= "$pre$key=<$desc>$post"; + } elsif (my $text = $schema->{$key}->{typetext}) { + $typetext .= "$pre$text$post"; + } else { + die "internal error: neither format_description nor typetext found"; + } + }; + foreach my $key (@required) { + &$add($key); + $pre = ', '; + } + $pre = $pre ? ' [,' : '['; + $post = ']'; + foreach my $key (@optional) { + &$add($key); + $pre = ' [,'; + } + return $typetext; +} + 1;