[pve-devel] r4915 - in pve-manager/pve2: . bin lib/PVE lib/PVE/API2

svn-commits at proxmox.com svn-commits at proxmox.com
Mon Jul 19 13:27:52 CEST 2010


Author: dietmar
Date: 2010-07-19 11:27:51 +0000 (Mon, 19 Jul 2010)
New Revision: 4915

Modified:
   pve-manager/pve2/ChangeLog
   pve-manager/pve2/bin/pvesh
   pve-manager/pve2/lib/PVE/API2.pm
   pve-manager/pve2/lib/PVE/API2/AccessControl.pm
   pve-manager/pve2/lib/PVE/API2/Cluster.pm
   pve-manager/pve2/lib/PVE/API2/Storage.pm
   pve-manager/pve2/lib/PVE/API2/User.pm
   pve-manager/pve2/lib/PVE/API2/VM.pm
   pve-manager/pve2/lib/PVE/JSONSchema.pm
   pve-manager/pve2/lib/PVE/REST.pm
   pve-manager/pve2/lib/PVE/RESTHandler.pm
Log:
	* lib/PVE/RESTHandler.pm (register_method): implement some kind of
	uri templates. We can now use "path => 'config/{storage}'" instead
	of clumsy "match_re" array.


Modified: pve-manager/pve2/ChangeLog
===================================================================
--- pve-manager/pve2/ChangeLog	2010-07-19 08:11:58 UTC (rev 4914)
+++ pve-manager/pve2/ChangeLog	2010-07-19 11:27:51 UTC (rev 4915)
@@ -1,3 +1,9 @@
+2010-07-19  Proxmox Support Team  <support at proxmox.com>
+
+	* lib/PVE/RESTHandler.pm (register_method): implement some kind of
+	uri templates. We can now use "path => 'config/{storage}'" instead
+	of clumsy "match_re" array.
+
 2010-07-05  Proxmox Support Team  <support at proxmox.com>
 
 	* www/manager/PVEUtils.js: s/default_groups/default_view/

Modified: pve-manager/pve2/bin/pvesh
===================================================================
--- pve-manager/pve2/bin/pvesh	2010-07-19 08:11:58 UTC (rev 4914)
+++ pve-manager/pve2/bin/pvesh	2010-07-19 11:27:51 UTC (rev 4915)
@@ -1,6 +1,5 @@
 #!/usr/bin/perl -w
 
-
 # NOTE: this is just an experimental prototype
 
 # TODO:
@@ -105,7 +104,7 @@
 }
 
 sub get_options {
-    my ($info, $args) = @_;
+    my ($info, $args, $uri_param) = @_;
 
     if (!$info->{parameters} || !$info->{parameters}->{properties}) {
 	die "too many arguments\n"
@@ -116,6 +115,7 @@
     my @getopt = ();
     foreach my $prop (keys %{$info->{parameters}->{properties}}) {
 	my $pd = $info->{parameters}->{properties}->{$prop};
+	next if defined($uri_param->{$prop});
 
 	#print "PROP " . Dumper($pd) . "\n";
 
@@ -144,6 +144,10 @@
 	}
     }
 
+    foreach my $p (keys %$uri_param) {
+	$opts->{$p} = $uri_param->{$p};
+    }
+
     return $opts;
 }
 
@@ -151,12 +155,13 @@
     my ($dir, $args) = @_;
 
     my $stack = [ split(/\/+/, $dir) ];
-    my ($handler, $info) = PVE::API2->find_handler('POST', $stack);
+    my $uri_param = {};
+    my ($handler, $info) = PVE::API2->find_handler('POST', $stack, $uri_param);
     if (!$handler || !$info) {
 	die "no 'create' handler for '$dir'\n";
     }
 
-    my $opts = get_options($info, $args);
+    my $opts = get_options($info, $args, $uri_param);
 
     # print "CREATE $dir " . Dumper($opts) . "\n";
 
@@ -169,12 +174,13 @@
     my ($dir, $args) = @_;
 
     my $stack = [ split(/\/+/, $dir) ];
-    my ($handler, $info) = PVE::API2->find_handler('GET', $stack);
+    my $uri_param = {};
+    my ($handler, $info) = PVE::API2->find_handler('GET', $stack, $uri_param);
     if (!$handler || !$info) {
 	die "no 'get' handler for '$dir'\n";
     }
 
-    my $opts = get_options($info, $args);
+    my $opts = get_options($info, $args, $uri_param);
 
     # print "GET $dir " . Dumper($opts) . "\n";
 
@@ -187,12 +193,13 @@
     my ($dir, $args) = @_;
 
     my $stack = [ split(/\/+/, $dir) ];
-    my ($handler, $info) = PVE::API2->find_handler('PUT', $stack);
+    my $uri_param = {};
+    my ($handler, $info) = PVE::API2->find_handler('PUT', $stack, $uri_param);
     if (!$handler || !$info) {
 	die "no 'update' handler for '$dir'\n";
     }
 
-    my $opts = get_options($info, $args);
+    my $opts = get_options($info, $args, $uri_param);
 
     # print "PUT $dir " . Dumper($opts) . "\n";
 
@@ -205,23 +212,24 @@
     my ($dir) = @_;
 
     my $stack = [ split(/\/+/, $dir) ];
-    my ($handler, $info) = PVE::API2->find_handler('DELETE', $stack);
+    my $uri_param = {};
+    my ($handler, $info) = PVE::API2->find_handler('DELETE', $stack, $uri_param);
     if (!$handler || !$info) {
 	die "no 'delete' handler for '$dir'\n";
     }
     
     # print "DELETE $dir\n";
 
-    my $res = call_handler($handler, $info, $dir, {});
+    my $res = call_handler($handler, $info, $dir, $uri_param);
     
     print_result($info, $res);
 }
 
 sub test_dir {
-    my ($dir) = @_;
+    my ($dir, $uri_param) = @_;
 
     my $stack = [ split(/\/+/, $dir) ];
-    my ($handler, $info) = PVE::API2->find_handler('GET', $stack);
+    my ($handler, $info) = PVE::API2->find_handler('GET', $stack, $uri_param);
     return undef if !$handler || !$info;
 
     return wantarray ? ($handler, $info) : 1;
@@ -230,7 +238,8 @@
 sub list_dir {
     my ($dir, $args) = @_;
 
-    my ($handler, $info) = test_dir($dir);
+    my $uri_param = {};
+    my ($handler, $info) = test_dir($dir, $uri_param);
     if (!$handler || !$info) {
 	die "no such resource\n";
     }
@@ -239,7 +248,7 @@
 	die "resource does not define child links\n";
     }
 
-    my $params = get_options($info, $args);
+    my $params = get_options($info, $args, $uri_param);
 
     my $res = call_handler($handler, $info, $dir, $params);
     if (!is_success($res->{status})) {

Modified: pve-manager/pve2/lib/PVE/API2/AccessControl.pm
===================================================================
--- pve-manager/pve2/lib/PVE/API2/AccessControl.pm	2010-07-19 08:11:58 UTC (rev 4914)
+++ pve-manager/pve2/lib/PVE/API2/AccessControl.pm	2010-07-19 11:27:51 UTC (rev 4915)
@@ -7,17 +7,18 @@
 use Apache2::Const qw(:http);
 
 use PVE::RESTHandler;
+use PVE::API2::User;
 
 use base qw(PVE::RESTHandler);
 
 __PACKAGE__->register_method ({
     subclass => "PVE::API2::User",  
-    match_re => [ 'users' ],
+    path => 'users',
 });
 
 __PACKAGE__->register_method ({
     name => 'index', 
-    match_re => [], 
+    path => '', 
     method => 'GET',
     description => "Directory index.",
     parameters => {

Modified: pve-manager/pve2/lib/PVE/API2/Cluster.pm
===================================================================
--- pve-manager/pve2/lib/PVE/API2/Cluster.pm	2010-07-19 08:11:58 UTC (rev 4914)
+++ pve-manager/pve2/lib/PVE/API2/Cluster.pm	2010-07-19 11:27:51 UTC (rev 4915)
@@ -13,7 +13,7 @@
 
 __PACKAGE__->register_method ({
     name => 'index', 
-    match_re => [], 
+    path => '', 
     method => 'GET',
     description => "Cluster node index.",
     parameters => {

Modified: pve-manager/pve2/lib/PVE/API2/Storage.pm
===================================================================
--- pve-manager/pve2/lib/PVE/API2/Storage.pm	2010-07-19 08:11:58 UTC (rev 4914)
+++ pve-manager/pve2/lib/PVE/API2/Storage.pm	2010-07-19 11:27:51 UTC (rev 4915)
@@ -41,7 +41,7 @@
 
 __PACKAGE__->register_method ({
     name => 'index', 
-    match_re => [], # /storage/
+    path => '', # /storage/
     method => 'GET',
     description => "Storage index.",
     parameters => {
@@ -74,23 +74,23 @@
 
 __PACKAGE__->register_method ({
     name => 'read_config', 
-    match_re => [ 'config', '\S+' ], 
+    path => 'config/{storage}', 
     method => 'GET',
     description => "Read storage configuration.",
     parameters => {
     	additionalProperties => 0,
-	properties => {},
+	properties => {
+	    storage => { type => 'string' },
+	},
     },
     returns => {},
 });
 sub read_config {
     my ($conn, $resp, $param) = @_;
 
-    my ($storeid) = $conn->{rel_uri} =~ m!/([^/]+)$!;
-
     my $cfg = PVE::Config::read_file ("storagecfg");
 
-    my $scfg = PVE::Storage::storage_config ($cfg, $storeid);
+    my $scfg = PVE::Storage::storage_config ($cfg, $param->{storage});
 
     $scfg->{digest} = $cfg->{digest};
     $scfg->{time} = time(); # fixme: remove
@@ -109,12 +109,15 @@
 __PACKAGE__->register_method ({
     name => 'update_config',
     protected => 1,
-    match_re => [ 'config', '\S+' ], 
+    path => 'config/{storage}', 
     method => 'PUT',
     description => "Update storage configuration.",
     parameters => {
     	additionalProperties => 0,
 	properties => { 
+	    storage => { 
+		type => 'string', 
+	    },
 	    path => {
 		type => 'string',
 		optional => 1,
@@ -142,9 +145,8 @@
 sub update_config {
     my ($conn, $resp, $param) = @_;
 
-    syslog("info", Dumper($param));
-
-    my ($storeid) = $conn->{rel_uri} =~ m!/([^/]+)$!;
+    my $storeid = $param->{storage};
+    delete($param->{storage});
  
     my $digest = $param->{digest};
     delete($param->{digest});
@@ -156,7 +158,7 @@
 
 __PACKAGE__->register_method ({
     name => 'list_storage_config', 
-    match_re => [ 'config' ], # /storage/config
+    path => 'config', # /storage/config
     method => 'GET',
     description => "Storage index.",
     parameters => {
@@ -191,7 +193,7 @@
 
 __PACKAGE__->register_method ({
     name => 'scan_index', 
-    match_re => [ 'scan' ], 
+    path => 'scan', 
     method => 'GET',
     description => "Index of available scan methods",
     parameters => {
@@ -202,18 +204,18 @@
 	type => 'array',
 	items => {
 	    type => "object",
-	    properties => { type => { type => 'string'} },
+	    properties => { method => { type => 'string'} },
 	},
-	links => [ { rel => 'child', href => "{type}" } ],
+	links => [ { rel => 'child', href => "{method}" } ],
     },
 });
 sub scan_index {
     my ($conn, $resp, $param) = @_;
 
     my $res = [ 
-	{ type => 'lvm' },
-	{ type => 'iscsi' },
-	{ type => 'nfs' },
+	{ method => 'lvm' },
+	{ method => 'iscsi' },
+	{ method => 'nfs' },
 	];
 
     return $res;
@@ -221,12 +223,17 @@
 
 __PACKAGE__->register_method ({
     name => 'scan_server', 
-    match_re => [ 'scan', '(lvm|nfs|iscsi)' ], 
+    path => 'scan/{method}', 
     method => 'GET',
     description => "Scan remote storage server.",
     parameters => {
     	additionalProperties => 0,
-	properties => {},
+	properties => {
+	    method => { 
+		type => 'string',
+		enum => [ 'lvm', 'nfs', 'iscsi' ],
+	    }
+	},
     },
     returns => {},
 });
@@ -239,7 +246,7 @@
 # fixme: move to somewhere else
 __PACKAGE__->register_method ({
     name => 'cluster_index', 
-    match_re => [ 'index'], 
+    path => 'index', 
     method => 'GET',
     description => "Cluster wide storage status.",
     parameters => {
@@ -288,12 +295,17 @@
 __PACKAGE__->register_method ({
     name => 'list_nodes', 
     # /storage/(status|content)
-    match_re => [ '(status|content)' ],  
+    path => '{subdir}',  
     method => 'GET',
     description => "List storage nodes.",
     parameters => {
     	additionalProperties => 0,
-	properties => {},
+	properties => {
+	    subdir => {
+		type => 'string',
+		enum => [ 'status', 'content' ],
+	    },
+	},
     },
     returns => {
 	type => 'array',
@@ -318,18 +330,21 @@
 	];
 
     return $nodes;
-    
 }
 
 __PACKAGE__->register_method ({
     name => 'list_store_ids', 
     # /storage/content/{node}/
-    match_re => [ 'content' , '\S+'], 
+    path => 'content/{node}', 
     method => 'GET',
     description => "List storage IDs.",
     parameters => {
     	additionalProperties => 0,
-	properties => {},
+	properties => {
+	    node => {
+		type => 'string',		
+	    },
+	},
     },
     returns => {
 	type => 'array',
@@ -347,9 +362,9 @@
 
     my $cfg = PVE::Config::read_file ("storagecfg");
 
-    my ($nodeid) = $conn->{rel_uri} =~ m|/([^/]+)$|;
+   my $node = $param->{node};
 
-    # fixme: verify nodeid (node exists)?
+    # fixme: verify node (node exists)?
 
     my @sids =  PVE::Storage::storage_ids ($cfg);
 
@@ -367,12 +382,18 @@
     name => 'list_content', 
     protected => 1,
     # /storage/content/{nodeid}/{storeid}
-    match_re => [ 'content', '\S+', '\S+' ], 
+    path => 'content/{node}/{storage}',
     method => 'GET',
     description => "List storage content.",
     parameters => {
     	additionalProperties => 0,
 	properties => { 
+	    node => {
+		type => 'string',		
+	    },
+	    storage => {
+		type => 'string',		
+	    },
 	    content => {
 		type => 'string',
 		enum => [ @ctypes  ],
@@ -384,7 +405,11 @@
 	type => 'array',
 	items => {
 	    type => "object",
-	    properties => { volname => { type => 'string' } },
+	    properties => { 
+		volname => { 
+		    type => 'string' 
+		} 
+	    },
 	},
 	links => [
 	    { rel => 'child', href => "{volname}" }, 
@@ -396,7 +421,8 @@
 
     my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
 
-    my ($nodeid, $storeid) = $conn->{rel_uri} =~ m!/([^/]+)/([^/]+)$!;
+    my $node = $param->{node};
+    my $storeid = $param->{storage};
 
     # fixme: verify $node
 
@@ -431,12 +457,16 @@
     name => 'list_status', 
     protected => 1,
     # /storage/status/{nodeid}
-    match_re => [ 'status', '\S+' ],
+    path => 'status/{node}',
     method => 'GET',
     description => "Get status for all datastores.",
     parameters => {
     	additionalProperties => 0,
-	properties => {},
+	properties => {
+	    node => {
+		type => 'string',
+	    }
+	},
     },
     returns => {
 	type => 'array',
@@ -455,9 +485,9 @@
 
     my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
 
-    my ($nodeid) = $conn->{rel_uri} =~ m!/([^/]+)$!;
+    my $node = $param->{node};
 
-    # fixme: verify $nodeid
+    # fixme: verify $node
 
     my $cfg = PVE::Config::read_file ("storagecfg");
 
@@ -472,12 +502,19 @@
     name => 'get_status', 
     protected => 1,
     # /storage/status/{nodeid}/{storeid}
-    match_re => [ 'status', '\S+', '\S+' ],
+    path => 'status/{node}/{storage}',
     method => 'GET',
     description => "Get status for specific datastore.",
     parameters => {
     	additionalProperties => 0,
-	properties => {},
+	properties => {
+	    node => {
+		type => 'string',		
+	    },
+	    storage => {
+		type => 'string',		
+	    },
+	},
     },
     returns => {},
 });
@@ -487,9 +524,10 @@
 
     my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
 
-    my ($nodeid, $storeid) = $conn->{rel_uri} =~ m!/([^/]+)/([^/]+)$!;
+    my $node = $param->{node};
+    my $storeid = $param->{storage};
 
-    # fixme: verify $nodeid
+    # fixme: verify $node
 
     my $cfg = PVE::Config::read_file ("storagecfg");
 
@@ -500,6 +538,4 @@
     return $info->{$storeid};
 }
 
-
-
 1;

Modified: pve-manager/pve2/lib/PVE/API2/User.pm
===================================================================
--- pve-manager/pve2/lib/PVE/API2/User.pm	2010-07-19 08:11:58 UTC (rev 4914)
+++ pve-manager/pve2/lib/PVE/API2/User.pm	2010-07-19 11:27:51 UTC (rev 4915)
@@ -15,7 +15,7 @@
 
 __PACKAGE__->register_method ({
     name => 'index', 
-    match_re => [], 
+    path => '', 
     method => 'GET',
     description => "User index.",
     parameters => {
@@ -52,12 +52,13 @@
 __PACKAGE__->register_method ({
     name => 'create_user', 
     protected => 1,
-    match_re => [ '\S+' ], 
+    path => '{userid}', 
     method => 'POST',
     description => "Create new user.",
     parameters => {
-	type => "object",
+   	additionalProperties => 0,
 	properties => {
+	    userid => { type => 'string' },
 	    password => { type => 'string', optional => 1 },
 	    groups => { type => 'string', optional => 1 },
 	},
@@ -67,10 +68,8 @@
 sub create_user {
     my ($conn, $resp, $param) = @_;
 
-    my ($userid) = $conn->{rel_uri} =~ m|/([^/]+)$|;
-
     $param->{create} = 1;
-    PVE::AccessControl::modify_user($userid, $param);
+    PVE::AccessControl::modify_user($param->{userid}, $param);
 
     # fixme: maybe it is better to return the user data ?
 
@@ -79,20 +78,23 @@
 
 __PACKAGE__->register_method ({
     name => 'get_user', 
-    match_re => [ '\S+' ], 
+    path => '{userid}', 
     method => 'GET',
     description => "Get user configuration.",
-    parameters => {},
+    parameters => {
+   	additionalProperties => 0,
+	properties => {
+	    userid => { type => 'string' },
+	},
+    },
     returns => {},
 }); 
 sub get_user {
     my ($conn, $resp, $param) = @_;
 
-    my ($userid) = $conn->{rel_uri} =~ m|/([^/]+)$|;
-
     my $usercfg = PVE::Config::read_file("usercfg");
  
-    my $data = $usercfg->{users}->{$userid};
+    my $data = $usercfg->{users}->{$param->{userid}};
     die "no such user\n" if !$data;
 
     return $data;
@@ -101,12 +103,13 @@
 __PACKAGE__->register_method ({
     name => 'update_user', 
     protected => 1,
-    match_re => [ '\S+' ], 
+    path => '{userid}', 
     method => 'PUT',
     description => "Update user configuration.",
     parameters => {
-	type => "object",
+   	additionalProperties => 0,
 	properties => {
+	    userid => { type => 'string' },
 	    password => { type => 'string', optional => 1 },
 	    groups => { type => 'string', optional => 1 },
 	    append => { 
@@ -125,10 +128,8 @@
 sub update_user {
     my ($conn, $resp, $param) = @_;
 
-    my ($userid) = $conn->{rel_uri} =~ m|/([^/]+)$|;
+    PVE::AccessControl::modify_user($param->{userid}, $param);
 
-    PVE::AccessControl::modify_user($userid, $param);
-
     # fixme: maybe it is better to return the user data ?
 
     return undef;
@@ -137,18 +138,21 @@
 __PACKAGE__->register_method ({
     name => 'delete_user', 
     protected => 1,
-    match_re => [ '\S+' ], 
+    path => '{userid}', 
     method => 'DELETE',
     description => "Delete user.",
-    parameters => {},
+    parameters => {
+   	additionalProperties => 0,
+	properties => {
+	    userid => { type => 'string' },
+	}
+    },
     returns => { type => 'null' },
 }); 
 sub delete_user {
-    my ($conn, $resp) = @_;
+    my ($conn, $resp, $param) = @_;
 
-    my ($userid) = $conn->{rel_uri} =~ m|/([^/]+)$|;
-    
-    PVE::AccessControl::delete_user($userid);  
+    PVE::AccessControl::delete_user($param->{userid});  
 
     return undef;
 }

Modified: pve-manager/pve2/lib/PVE/API2/VM.pm
===================================================================
--- pve-manager/pve2/lib/PVE/API2/VM.pm	2010-07-19 08:11:58 UTC (rev 4914)
+++ pve-manager/pve2/lib/PVE/API2/VM.pm	2010-07-19 11:27:51 UTC (rev 4915)
@@ -13,7 +13,7 @@
 
 __PACKAGE__->register_method ({
     name => 'index', 
-    match_re => [], 
+    path => '', 
     method => 'GET',
     description => "Virtual machine index.",
     parameters => {

Modified: pve-manager/pve2/lib/PVE/API2.pm
===================================================================
--- pve-manager/pve2/lib/PVE/API2.pm	2010-07-19 08:11:58 UTC (rev 4914)
+++ pve-manager/pve2/lib/PVE/API2.pm	2010-07-19 11:27:51 UTC (rev 4915)
@@ -16,27 +16,27 @@
 
 __PACKAGE__->register_method ({
     subclass => "PVE::API2::VM",  
-    match_re => [ 'vms' ],
+    path => 'vms',
 });
 
 __PACKAGE__->register_method ({
     subclass => "PVE::API2::Cluster",  
-    match_re => [ 'cluster' ],
+    path => 'cluster',
 });
 
 __PACKAGE__->register_method ({
     subclass => "PVE::API2::Storage",  
-    match_re => [ 'storage' ],
+    path => 'storage',
 });
 
 __PACKAGE__->register_method ({
     subclass => "PVE::API2::AccessControl",  
-    match_re => [ 'access' ],
+    path => 'access',
 });
 
 __PACKAGE__->register_method ({
     name => 'index', 
-    match_re => [], 
+    path => '',
     method => 'GET',
     description => "Directory index.",
     parameters => {

Modified: pve-manager/pve2/lib/PVE/JSONSchema.pm
===================================================================
--- pve-manager/pve2/lib/PVE/JSONSchema.pm	2010-07-19 08:11:58 UTC (rev 4914)
+++ pve-manager/pve2/lib/PVE/JSONSchema.pm	2010-07-19 11:27:51 UTC (rev 4915)
@@ -485,7 +485,7 @@
                     description => {},
  	            method => {},
                     parameters => {},
-                    match_re => {},
+                    path => {},
                     parameters => {},
                     returns => {},
                 }             
@@ -502,12 +502,9 @@
 	    description => "method needs special privileges - only pvedaemon can execute it",            
 	    optional => 1,
         },
-	match_re => {
-	    type =>  'array',
-	    description => "regular expressions for URL matching",
-	    items => {
-		type => 'string',
-	    },
+	path => {
+	    type =>  'string',
+	    description => "path for URL matching (uri template)",
 	},
 	parameters => {
 	    type => 'object',
@@ -527,7 +524,7 @@
  		additionalProperties => 0,
 		properties => {
                     subclass => {},
-                    match_re => {},
+                    path => {},
                 }             
             },
 	}, 

Modified: pve-manager/pve2/lib/PVE/REST.pm
===================================================================
--- pve-manager/pve2/lib/PVE/REST.pm	2010-07-19 08:11:58 UTC (rev 4914)
+++ pve-manager/pve2/lib/PVE/REST.pm	2010-07-19 11:27:51 UTC (rev 4915)
@@ -277,23 +277,33 @@
     syslog ('info', "GOT VALID TICKET $ticket");
     
     my $stack = [ grep { length($_) > 0 }  split('\/+' , $rel_uri)] ; # skip empty fragments
+    my $uri_param = {};
+    my ($handler, $info) = PVE::API2->find_handler($method, $stack, $uri_param);
+    if (!$handler || !$info) {
+	return {
+	    status => HTTP_NOT_IMPLEMENTED,
+	    message => "Method '$method $abs_uri' not implemented",
+	};
+    }
 
+    foreach my $p (keys %{$params}) {
+	if (defined($uri_param->{$p})) {
+	    return {
+		status => HTTP_BAD_REQUEST,
+		message => "Parameter verification failed - duplicate parameter '$p'",
+	    };
+	}
+	$uri_param->{$p} = $params->{$p};
+    }
+
     # fixme: language ?
     my $conn = {
 	abs_uri => $abs_uri,
 	rel_uri => $rel_uri,
 	user => $username,
-	params => $params,
+	params => $uri_param,
     };
 
-    my ($handler, $info) = PVE::API2->find_handler($method, $stack);
-    if (!$handler || !$info) {
-	return {
-	    status => HTTP_NOT_IMPLEMENTED,
-	    message => "Method '$method $abs_uri' not implemented",
-	};
-    }
-
     # fixme: not sure if we should do that here, because we can't proxy those
     # methods to other hosts?
     return { proxy => 'localhost' } if $info->{protected} && ($euid != 0);

Modified: pve-manager/pve2/lib/PVE/RESTHandler.pm
===================================================================
--- pve-manager/pve2/lib/PVE/RESTHandler.pm	2010-07-19 08:11:58 UTC (rev 4914)
+++ pve-manager/pve2/lib/PVE/RESTHandler.pm	2010-07-19 11:27:51 UTC (rev 4915)
@@ -14,6 +14,24 @@
 
     PVE::JSONSchema::validate_method_info($info);
 
+    my $match_re = [];
+    my $match_name = [];
+
+    foreach my $comp (split(/\/+/, $info->{path})) {
+	die "path compoment has zero length" if $comp eq '';
+	if ($comp =~ m/^\{(\w+)\}$/) {
+	    my $name = $1;
+	    push @$match_re, '\S+';
+	    push @$match_name,  $1;
+	} else {
+	    push @$match_re, $comp;
+	    push @$match_name,  undef;
+	}
+    }
+
+    $info->{match_re} = $match_re;
+    $info->{match_name} = $match_name;
+
     push @{$method_registry->{$self}}, $info;
 
 }
@@ -25,7 +43,7 @@
 }
 
 sub map_method {
-    my ($self, $stack, $method) = @_;
+    my ($self, $stack, $method, $uri_param) = @_;
 
     my $ma = $method_registry->{$self};
 
@@ -45,28 +63,37 @@
 
 	#syslog ('info', "TEST1 " . Dumper($info));
 
+	my $param = {};
 	my $i = 0;
 	for (; $i < $regexlen; $i++) {
 	    my $comp = $stack->[$i];
 	    my $re = $info->{match_re}->[$i];
 	    #print "COMPARE $comp $info->{match_re}->[$i]\n";
-	    last if $stack->[$i] !~ m/^$re$/;
+	    my ($match) = $stack->[$i] =~ m/^($re)$/;
+	    last if !defined($match);
+	    if (my $name = $info->{match_name}->[$i]) {
+		$param->{$name} = $match; 
+	    }
 	}
 
 	next if $i != $regexlen;
 
 	#print "MATCH $info->{name}\n";
 	
+	foreach my $p (keys %$param) {
+	    $uri_param->{$p} = $param->{$p};
+	}
+
 	return $info;
     }
 }
 
 sub find_handler {
-    my ($class, $method, $stack) = @_;
+    my ($class, $method, $stack, $uri_param) = @_;
 
     my $info;
     eval {
-	$info = $class->map_method($stack, $method);
+	$info = $class->map_method($stack, $method, $uri_param);
     };
     syslog('err', $@) if $@;
 
@@ -87,7 +114,7 @@
 	    # fixme: store $fragments somewhere ?
 	}
 
-	return $subh->find_handler($method, $stack);
+	return $subh->find_handler($method, $stack, $uri_param);
     }
 
     return ($class, $info);




More information about the pve-devel mailing list