[pve-devel] [RFC PATCH common 1/2] Handle string parameter to file content replacement

Fabian Grünbichler f.gruenbichler at proxmox.com
Tue Apr 5 09:20:50 CEST 2016


This is modelled after the way read_password() is used to
wrap -password parameters on the command line. If a mapping
for a certain API method and parameter is defined in the
sub class of CLIHandler.pm, the parameter is interpreted as
a file path on the command line and the parameter is
filled with the string contents of the referenced file.

This allows us to use the same API schema once in API2, but
overwrite the behaviour for individual parameters in the CLI
tools when desired.
---
Note: for testing, you need to define a method 'string_param_file_mapping'
which takes the API2 method name as argument and returns a list of
parameters that should be mapped, for example in pct.pm:

sub string_param_file_mapping {
    my ($name) = @_;
    my $mapping = {
        'api-method-name' => ['api-param-name'],
    };

    return defined($mapping->{$name}) ? $mapping->{$name} : [];
}

The associated 'pct api-command' cmd will now work with
'-api-param-name /path/to/file' instead of '-api-param-name "param value"',
displaying an error message if the file does not exist.

 src/PVE/CLIHandler.pm  | 13 +++++++------
 src/PVE/RESTHandler.pm | 17 ++++++++++++++++-
 2 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/src/PVE/CLIHandler.pm b/src/PVE/CLIHandler.pm
index c2d3438..9a2f841 100644
--- a/src/PVE/CLIHandler.pm
+++ b/src/PVE/CLIHandler.pm
@@ -452,7 +452,7 @@ sub generate_asciidoc_synopsys {
 }
 
 my $handle_cmd  = sub {
-    my ($def, $cmdname, $cmd, $args, $pwcallback, $podfn, $preparefunc) = @_;
+    my ($def, $cmdname, $cmd, $args, $pwcallback, $podfn, $preparefunc, $stringfilemap) = @_;
 
     $cmddef = $def;
     $exename = $cmdname;
@@ -486,13 +486,13 @@ my $handle_cmd  = sub {
     }
 
     my $prefix = "$exename $cmd";
-    my $res = $class->cli_handler($prefix, $name, \@ARGV, $arg_param, $uri_param, $pwcallback);
+    my $res = $class->cli_handler($prefix, $name, \@ARGV, $arg_param, $uri_param, $pwcallback, $stringfilemap);
 
     &$outsub($res) if $outsub;
 };
 
 my $handle_simple_cmd = sub {
-    my ($def, $args, $pwcallback, $podfn, $preparefunc) = @_;
+    my ($def, $args, $pwcallback, $podfn, $preparefunc, $stringfilemap) = @_;
 
     my ($class, $name, $arg_param, $uri_param, $outsub) = @{$def};
     die "no class specified" if !$class;
@@ -519,7 +519,7 @@ my $handle_simple_cmd = sub {
 
     &$preparefunc() if $preparefunc;
 
-    my $res = $class->cli_handler($name, $name, \@ARGV, $arg_param, $uri_param, $pwcallback);
+    my $res = $class->cli_handler($name, $name, \@ARGV, $arg_param, $uri_param, $pwcallback, $stringfilemap);
 
     &$outsub($res) if $outsub;
 };
@@ -553,6 +553,7 @@ sub run_cli_handler {
     my $no_init = $params{no_init};
 
     my $pwcallback = $class->can('read_password');
+    my $stringfilemap = $class->can('string_param_file_mapping');
 
     $exename = &$get_exe_name($class);
 
@@ -573,11 +574,11 @@ sub run_cli_handler {
     my $def = ${"${class}::cmddef"};
 
     if (ref($def) eq 'ARRAY') {
-	&$handle_simple_cmd($def, \@ARGV, $pwcallback, $podfn, $preparefunc);
+	&$handle_simple_cmd($def, \@ARGV, $pwcallback, $podfn, $preparefunc, $stringfilemap);
     } else {
 	$cmddef = $def;
 	my $cmd = shift @ARGV;
-	&$handle_cmd($cmddef, $exename, $cmd, \@ARGV, $pwcallback, $podfn, $preparefunc);
+	&$handle_cmd($cmddef, $exename, $cmd, \@ARGV, $pwcallback, $podfn, $preparefunc, $stringfilemap);
     }
 
     exit 0;
diff --git a/src/PVE/RESTHandler.pm b/src/PVE/RESTHandler.pm
index edf23d1..9e0980e 100644
--- a/src/PVE/RESTHandler.pm
+++ b/src/PVE/RESTHandler.pm
@@ -631,14 +631,29 @@ sub dump_properties {
     return $raw;
 }
 
+my $replace_file_names_with_contents = sub {
+    my ($param, $mapping) = @_;
+
+    if ($mapping) {
+	foreach my $elem ( @$mapping ) {
+	    $param->{$elem} = PVE::Tools::file_get_contents($param->{$elem})
+		if defined($param->{$elem});
+	}
+    }
+
+    return $param;
+};
+
 sub cli_handler {
-    my ($self, $prefix, $name, $args, $arg_param, $fixed_param, $pwcallback) = @_;
+    my ($self, $prefix, $name, $args, $arg_param, $fixed_param, $pwcallback, $stringfilemap) = @_;
 
     my $info = $self->map_method_by_name($name);
 
     my $res;
     eval {
 	my $param = PVE::JSONSchema::get_options($info->{parameters}, $args, $arg_param, $fixed_param, $pwcallback);
+	&$replace_file_names_with_contents($param, &$stringfilemap($name))
+	    if defined($stringfilemap);
 	$res = $self->handle($info, $param);
     };
     if (my $err = $@) {
-- 
2.1.4




More information about the pve-devel mailing list