]> git.proxmox.com Git - pve-common.git/blobdiff - src/PVE/JSONSchema.pm
added 'extra-args' CLI handling
[pve-common.git] / src / PVE / JSONSchema.pm
index 3e0fd52c13f54d0eab19e49dac5eece2129c7c5b..c925ecbad664164e4670d51e2a5002fa48d0725e 100644 (file)
@@ -37,12 +37,12 @@ sub get_standard_option {
     my ($name, $base) = @_;
 
     my $std =  $standard_options->{$name};
-    die "no such standard option\n" if !$std;
+    die "no such standard option '$name'\n" if !$std;
 
     my $res = $base || {};
 
     foreach my $opt (keys %$std) {
-       next if $res->{$opt};
+       next if defined($res->{$opt});
        $res->{$opt} = $std->{$opt};
     }
 
@@ -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 {
@@ -147,13 +154,35 @@ register_format('ipv4', \&pve_verify_ipv4);
 sub pve_verify_ipv4 {
     my ($ipv4, $noerr) = @_;
 
-    if (!Net::IP::ip_is_ipv4($ipv4))  {
-       return undef if $noerr;
-       die "value does not look like a valid IP address\n";
+    if ($ipv4 !~ m/^(?:$IPV4RE)$/) {
+       return undef if $noerr;
+       die "value does not look like a valid IPv4 address\n";
     }
     return $ipv4;
 }
 
+register_format('ipv6', \&pve_verify_ipv6);
+sub pve_verify_ipv6 {
+    my ($ipv6, $noerr) = @_;
+
+    if ($ipv6 !~ m/^(?:$IPV6RE)$/) {
+       return undef if $noerr;
+       die "value does not look like a valid IPv6 address\n";
+    }
+    return $ipv6;
+}
+
+register_format('ip', \&pve_verify_ip);
+sub pve_verify_ip {
+    my ($ip, $noerr) = @_;
+
+    if ($ip !~ m/^(?:(?:$IPV4RE)|(?:$IPV6RE))$/) {
+       return undef if $noerr;
+       die "value does not look like a valid IP address\n";
+    }
+    return $ip;
+}
+
 my $ipv4_mask_hash = {
     '128.0.0.0' => 1,
     '192.0.0.0' => 2,
@@ -249,9 +278,23 @@ sub pve_verify_iface {
     return $id;
 }
 
+# general addresses by name or IP
+register_format('address', \&pve_verify_address);
+sub pve_verify_address {
+    my ($addr, $noerr) = @_;
+
+    if (!(pve_verify_ip($addr, 1) ||
+         pve_verify_dns_name($addr, 1)))
+    {
+          return undef if $noerr;
+          die "value does not look like a valid address: $addr\n";
+    }
+    return $addr;
+}
+
 register_standard_option('spice-proxy', {
     description => "SPICE proxy server. This can be used by the client to specify the proxy server. All nodes in a cluster runs 'spiceproxy', so it is up to the client to choose one. By default, we return the node where the VM is currently running. As resonable setting is to use same node you use to connect to the API (This is window.location.hostname for the JS GUI).",
-    type => 'string', format => 'dns-name',
+    type => 'string', format => 'address',
 }); 
 
 register_standard_option('remote-viewer-config', {
@@ -266,6 +309,48 @@ register_standard_option('remote-viewer-config', {
     },
 });
 
+register_format('pve-startup-order', \&pve_verify_startup_order);
+sub pve_verify_startup_order {
+    my ($value, $noerr) = @_;
+
+    return $value if pve_parse_startup_order($value);
+
+    return undef if $noerr;
+
+    die "unable to parse startup options\n";
+}
+
+sub pve_parse_startup_order {
+    my ($value) = @_;
+
+    return undef if !$value;
+
+    my $res = {};
+
+    foreach my $p (split(/,/, $value)) {
+       next if $p =~ m/^\s*$/;
+
+       if ($p =~ m/^(order=)?(\d+)$/) {
+           $res->{order} = $2;
+       } elsif ($p =~ m/^up=(\d+)$/) {
+           $res->{up} = $1;
+       } elsif ($p =~ m/^down=(\d+)$/) {
+           $res->{down} = $1;
+       } else {
+           return undef;
+       }
+    }
+
+    return $res;
+}
+
+PVE::JSONSchema::register_standard_option('pve-startup-order', {
+    description => "Startup and shutdown behavior. Order is a non-negative number defining the general startup order. Shutdown in done with reverse ordering. Additionally you can set the 'up' or 'down' delay in seconds, which specifies a delay to wait before the next VM is started or stopped.",
+    optional => 1,
+    type => 'string', format => 'pve-startup-order',
+    typetext => '[[order=]\d+] [,up=\d+] [,down=\d+] ',
+});
+
 sub check_format {
     my ($format, $value) = @_;
 
@@ -996,16 +1081,24 @@ sub get_options {
     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;
@@ -1072,13 +1165,12 @@ sub parse_config {
 
     my $cfg = {};
 
-    while ($raw && $raw =~ s/^(.*?)(\n|$)//) {
+    while ($raw =~ /^\s*(.+?)\s*$/gm) {
        my $line = $1;
-       next if $line =~ m/^\#/; # skip comment lines
-       next if $line =~ m/^\s*$/; # skip empty lines
 
-       if ($line =~ m/^(\S+):\s*(\S+)\s*$/) {
+       next if $line =~ /^#/;
+
+       if ($line =~ m/^(\S+?):\s*(.*)$/) {
            my $key = $1;
            my $value = $2;
            if ($schema->{properties}->{$key} &&