[pve-devel] [RFC common] cli: more generic interactive parameter definition

Wolfgang Bumiller w.bumiller at proxmox.com
Mon Mar 12 13:04:15 CET 2018


Instead of hardcoding 'password' as a special case in the
JSONSchema's getopt handling, extend the new parameter
mapping to allow defining a parameters as 'interactive'.
They also take an optional argument on the command line
directly.

This effectively deprecates the password special case which
should be replaced in pct/pveum/... and then dropped in
pve-common.

Signed-off-by: Wolfgang Bumiller <w.bumiller at proxmox.com>
---
 src/PVE/JSONSchema.pm  | 20 ++++++++++++++++++--
 src/PVE/RESTHandler.pm | 13 +++++++------
 2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm
index 9861a8f..0e722b8 100644
--- a/src/PVE/JSONSchema.pm
+++ b/src/PVE/JSONSchema.pm
@@ -1333,7 +1333,7 @@ sub method_get_child_link {
 # a way to parse command line parameters, using a 
 # schema to configure Getopt::Long
 sub get_options {
-    my ($schema, $args, $arg_param, $fixed_param, $pwcallback) = @_;
+    my ($schema, $args, $arg_param, $fixed_param, $pwcallback, $param_mapping_hash) = @_;
 
     if (!$schema || !$schema->{properties}) {
 	raise("too many arguments\n", code => HTTP_BAD_REQUEST)
@@ -1349,13 +1349,20 @@ sub get_options {
 	$list_param = $arg_param;
     }
 
+    my @interactive = ();
     my @getopt = ();
     foreach my $prop (keys %{$schema->{properties}}) {
 	my $pd = $schema->{properties}->{$prop};
 	next if $list_param && $prop eq $list_param;
 	next if defined($fixed_param->{$prop});
 
-	if ($prop eq 'password' && $pwcallback) {
+	my $mapping = $param_mapping_hash->{$prop};
+	if ($mapping && $mapping->{interactive}) {
+	    # interactive parameters such as passwords: make the argument
+	    # optional and call the mapping function afterwards.
+	    push @getopt, "$prop:s";
+	    push @interactive, [$prop, $mapping->{func}];
+	} elsif ($prop eq 'password' && $pwcallback) {
 	    # we do not accept plain password on input line, instead
 	    # we turn this into a boolean option and ask for password below
 	    # using $pwcallback() (for security reasons).
@@ -1409,6 +1416,15 @@ sub get_options {
 	}
     }
 
+    foreach my $entry (@interactive) {
+	my ($opt, $func) = @$entry;
+	my $pd = $schema->{properties}->{$opt};
+	my $value = $opts->{$opt};
+	if (defined($value) || !$pd->{optional}) {
+	    $opts->{$opt} = $func->($value);
+	}
+    }
+
     # decode after Getopt as we are not sure how well it handles unicode
     foreach my $p (keys %$opts) {
 	if (!ref($opts->{$p})) {
diff --git a/src/PVE/RESTHandler.pm b/src/PVE/RESTHandler.pm
index 0a64158..3f5c732 100644
--- a/src/PVE/RESTHandler.pm
+++ b/src/PVE/RESTHandler.pm
@@ -514,15 +514,15 @@ my $compute_param_mapping_hash = sub {
     return $res if !defined($mapping_array);
 
     foreach my $item (@$mapping_array) {
-	my ($name, $func, $desc);
+	my ($name, $func, $desc, $interactive);
 	if (ref($item) eq 'ARRAY') {
-	    ($name, $func, $desc) = @$item;
+	    ($name, $func, $desc, $interactive) = @$item;
 	} else {
 	    $name = $item;
 	    $func = sub { return PVE::Tools::file_get_contents($_[0]) };
 	}
 	$desc //= '<filepath>';
-	$res->{$name} = { desc => $desc, func => $func };
+	$res->{$name} = { desc => $desc, func => $func, interactive => $interactive };
     }
 
     return $res;
@@ -691,6 +691,7 @@ my $replace_file_names_with_contents = sub {
     my ($param, $param_mapping_hash) = @_;
 
     while (my ($k, $d) = each %$param_mapping_hash) {
+	next if $d->{interactive}; # handled by the JSONSchema's get_options code
 	$param->{$k} = $d->{func}->($param->{$k})
 	    if defined($param->{$k});
     }
@@ -705,10 +706,10 @@ sub cli_handler {
 
     my $res;
     eval {
-	my $param = PVE::JSONSchema::get_options($info->{parameters}, $args, $arg_param, $fixed_param, $read_password_func);
+	my $param_mapping_hash = $compute_param_mapping_hash->($param_mapping_func->($name)) if $param_mapping_func;
+	my $param = PVE::JSONSchema::get_options($info->{parameters}, $args, $arg_param, $fixed_param, $read_password_func, $param_mapping_hash);
 
-	if (defined($param_mapping_func)) {
-	    my $param_mapping_hash = $compute_param_mapping_hash->(&$param_mapping_func($name));
+	if (defined($param_mapping_hash)) {
 	    &$replace_file_names_with_contents($param, $param_mapping_hash);
 	}
 
-- 
2.11.0





More information about the pve-devel mailing list