[pve-devel] r4901 - in pve-manager/pve2: bin lib/PVE lib/PVE/API2 www/manager www/manager/util

svn-commits at proxmox.com svn-commits at proxmox.com
Thu Jul 15 11:57:39 CEST 2010


Author: dietmar
Date: 2010-07-15 09:57:39 +0000 (Thu, 15 Jul 2010)
New Revision: 4901

Added:
   pve-manager/pve2/www/manager/util/
   pve-manager/pve2/www/manager/util/base64.js
Modified:
   pve-manager/pve2/bin/pvesh
   pve-manager/pve2/lib/PVE/API2.pm
   pve-manager/pve2/lib/PVE/API2/Storage.pm
   pve-manager/pve2/lib/PVE/RESTHandler.pm
   pve-manager/pve2/www/manager/Makefile.am
   pve-manager/pve2/www/manager/StorageBrowser.js
Log:
improve storage api


Modified: pve-manager/pve2/bin/pvesh
===================================================================
--- pve-manager/pve2/bin/pvesh	2010-07-14 12:33:41 UTC (rev 4900)
+++ pve-manager/pve2/bin/pvesh	2010-07-15 09:57:39 UTC (rev 4901)
@@ -68,6 +68,8 @@
 
     my $msg = $res->{message} || status_message($status);
 
+    chomp($msg);
+
     warn "$status $msg\n";
 
     return if $nodata;

Modified: pve-manager/pve2/lib/PVE/API2/Storage.pm
===================================================================
--- pve-manager/pve2/lib/PVE/API2/Storage.pm	2010-07-14 12:33:41 UTC (rev 4900)
+++ pve-manager/pve2/lib/PVE/API2/Storage.pm	2010-07-15 09:57:39 UTC (rev 4901)
@@ -5,14 +5,17 @@
 # /storage/config GET whole config, CREATE storage
 # /storage/config/{storeid}/ GET/SET storage config
 
-# /storage/status/{node}/{storeid}/state GET/SET state (activate/disable)
+# /storage/status/{node}/ GET/SET status list
+# /storage/status/{node}/{storeid}  GET/SET state (activate/disable)
 
+# /storage/content/{node}/{storeid}/  list/upload content
+# /storage/content/{node}/{storeid}/{volname} DELETE content
+
+
 # /storage/scan/lvm list volume groups
 # /storage/scan/nfs list nfs exports
 # /storage/scan/iscsi list iscsi exports
 
-# /storage/content/{storeid}/{node}  list/upload content
-# /storage/content/{storeid}/{node}/{volname} DELETE content
 
 # iso/*.iso
 # vztmpl/*.tgz
@@ -134,7 +137,7 @@
     name => 'scan_index', 
     match_re => [ 'scan' ], 
     method => 'GET',
-    description => "Index of available svan methods",
+    description => "Index of available scan methods",
     parameters => {
     	additionalProperties => 0,
 	properties => {},
@@ -177,9 +180,59 @@
     return [];
 };
 
+# fixme: move to somewhere else
 __PACKAGE__->register_method ({
+    name => 'cluster_index', 
+    match_re => [ 'index'], 
+    method => 'GET',
+    description => "Cluster wide storage status.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => {},
+	},
+#	links => [ { rel => 'child', href => "{storage}" } ],
+    },
+});
+sub cluster_index {
+    my ($conn, $resp, $param) = @_;
+
+    my $nodes = [ 'node-0', 'node-1', 'node-2', 'node-3' ]; # fixme: use the real list
+
+    my $cfg = PVE::Config::read_file ("storagecfg");
+
+    my @sids =  PVE::Storage::storage_ids ($cfg);
+
+    my $res = [];
+    foreach my $storeid (@sids) {
+	my $scfg =  PVE::Storage::storage_config ($cfg, $storeid);
+	if ($scfg->{shared}) {
+	    my $data = { name => $storeid, storage => $storeid, type => $scfg->{type}, shared => 1};
+	    push @$res, $data;
+	} else {
+	    # we create a entry for each node
+	    foreach my $node (@$nodes) {
+		my $data = { name => "$storeid ($node)", storage => $storeid, node => $node, 
+			     type => $scfg->{type}, shared => 0};
+		push @$res, $data;
+	    }
+	}
+    }
+
+    # $resp->{digest} = $cfg->{digest}; # fixme: how do we handle that
+
+    return $res;
+}
+
+__PACKAGE__->register_method ({
     name => 'list_nodes', 
-    match_re => [ '(status|content)' ],  # /storage/(status|content)
+    # /storage/(status|content)
+    match_re => [ '(status|content)' ],  
     method => 'GET',
     description => "List storage nodes.",
     parameters => {
@@ -200,11 +253,8 @@
 sub list_nodes {
     my ($conn, $resp, $param) = @_;
 
-    my ($storeid) = $conn->{rel_uri} =~ m|/([^/]+)$|;
-
-    # fixme: check if storeid exists on node 
-
-    my $nodes = [ # fixme: use the real list
+    # fixme: use the real list
+    my $nodes = [ 
 	{ node => 'node-0'},
 	{ node => 'node-1'},
 	{ node => 'node-2'},
@@ -215,12 +265,12 @@
     
 }
 
-# fixme: move to somewhere else
 __PACKAGE__->register_method ({
-    name => 'cluster_index', 
-    match_re => [ 'index'], 
+    name => 'list_store_ids', 
+    # /storage/content/{node}/
+    match_re => [ 'content' , '\S+'], 
     method => 'GET',
-    description => "Cluster wide storage status.",
+    description => "List storage IDs.",
     parameters => {
     	additionalProperties => 0,
 	properties => {},
@@ -229,45 +279,39 @@
 	type => 'array',
 	items => {
 	    type => "object",
-	    properties => {},
+	    properties => { storage => { type => 'string' } },
 	},
-#	links => [ { rel => 'child', href => "{storage}" } ],
+	links => [
+	    { rel => 'child', href => "{storage}" }, 
+	    ],
     },
 });
-sub cluster_index {
-    my ($conn, $resp, $param) = @_;
+sub list_store_ids {
+   my ($conn, $resp, $param) = @_;
 
-    my $nodes = [ 'node-0', 'node-1', 'node-2', 'node-3' ]; # fixme: use the real list
-
     my $cfg = PVE::Config::read_file ("storagecfg");
 
+    my ($nodeid) = $conn->{rel_uri} =~ m|/([^/]+)$|;
+
+    # fixme: verify nodeid (node exists)?
+
     my @sids =  PVE::Storage::storage_ids ($cfg);
 
     my $res = [];
     foreach my $storeid (@sids) {
-	my $scfg =  PVE::Storage::storage_config ($cfg, $storeid);
-	if ($scfg->{shared}) {
-	    my $data = { name => $storeid, storage => $storeid, type => $scfg->{type}, shared => 1};
-	    push @$res, $data;
-	} else {
-	    # we create a entry for each node
-	    foreach my $node (@$nodes) {
-		my $data = { name => "$storeid ($node)", storage => $storeid, node => $node, 
-			     type => $scfg->{type}, shared => 0};
-		push @$res, $data;
-	    }
-	}
+	# fixme: check if storeage exists on node ?
+	push @$res, { storage => $storeid };
     }
 
-    # $resp->{digest} = $cfg->{digest}; # fixme: how do we handle that
-
     return $res;
 }
 
+
 __PACKAGE__->register_method ({
     name => 'list_content', 
     protected => 1,
-    match_re => [ 'content', '\S+', '\S+' ], # /storage/content/{storeid}/{nodeid}
+    # /storage/content/{nodeid}/{storeid}
+    match_re => [ 'content', '\S+', '\S+' ], 
     method => 'GET',
     description => "List storage content.",
     parameters => {
@@ -296,7 +340,7 @@
 
     my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
 
-    my ($storeid, $nodeid) = $conn->{rel_uri} =~ m!/([^/]+)/([^/]+)$!;
+    my ($nodeid, $storeid) = $conn->{rel_uri} =~ m!/([^/]+)/([^/]+)$!;
 
     # fixme: verify $node
 
@@ -330,15 +374,26 @@
 __PACKAGE__->register_method ({
     name => 'list_status', 
     protected => 1,
-    match_re => [ 'status', '\S+' ], # /storage/status/{nodeid}
+    # /storage/status/{nodeid}
+    match_re => [ 'status', '\S+' ],
     method => 'GET',
-    description => "Get storage status.",
+    description => "Get status for all datastores.",
     parameters => {
     	additionalProperties => 0,
 	properties => {},
     },
-    returns => {},
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => { storage => { type => 'string' } },
+	},
+	links => [
+	    { rel => 'child', href => "{storage}" }, 
+	    ],
+    },
 });
+
 sub list_status {
     my ($conn, $resp, $param) = @_;
 
@@ -346,15 +401,49 @@
 
     my ($nodeid) = $conn->{rel_uri} =~ m!/([^/]+)$!;
 
-    # fixme: verify $node
+    # fixme: verify $nodeid
 
     my $cfg = PVE::Config::read_file ("storagecfg");
 
+    # fixme: connect to correct node
+
     my $info = PVE::Storage::storage_info ($cfg);
 
-    return $info;
+    return PVE::RESTHandler::hash_to_array($info, 'storage');
 }
 
+__PACKAGE__->register_method ({
+    name => 'get_status', 
+    protected => 1,
+    # /storage/status/{nodeid}/{storeid}
+    match_re => [ 'status', '\S+', '\S+' ],
+    method => 'GET',
+    description => "Get status for specific datastore.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {},
+    },
+    returns => {},
+});
 
+sub get_status {
+    my ($conn, $resp, $param) = @_;
 
+    my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
+
+    my ($nodeid, $storeid) = $conn->{rel_uri} =~ m!/([^/]+)/([^/]+)$!;
+
+    # fixme: verify $nodeid
+
+    my $cfg = PVE::Config::read_file ("storagecfg");
+
+    # fixme: connect to correct node
+
+    my $info = PVE::Storage::storage_info ($cfg);
+
+    return $info->{$storeid};
+}
+
+
+
 1;

Modified: pve-manager/pve2/lib/PVE/API2.pm
===================================================================
--- pve-manager/pve2/lib/PVE/API2.pm	2010-07-14 12:33:41 UTC (rev 4900)
+++ pve-manager/pve2/lib/PVE/API2.pm	2010-07-15 09:57:39 UTC (rev 4901)
@@ -8,6 +8,12 @@
 
 use base qw(PVE::RESTHandler);
 
+# preload classes
+use PVE::API2::VM;
+use PVE::API2::Cluster;
+use PVE::API2::Storage;
+use PVE::API2::AccessControl;
+
 __PACKAGE__->register_method ({
     subclass => "PVE::API2::VM",  
     match_re => [ 'vms' ],

Modified: pve-manager/pve2/lib/PVE/RESTHandler.pm
===================================================================
--- pve-manager/pve2/lib/PVE/RESTHandler.pm	2010-07-14 12:33:41 UTC (rev 4900)
+++ pve-manager/pve2/lib/PVE/RESTHandler.pm	2010-07-15 09:57:39 UTC (rev 4901)
@@ -138,7 +138,6 @@
 	    $resp->{status} = HTTP_INTERNAL_SERVER_ERROR;
 	    $resp->{errors} = $res->{errors};
 
-	    print Dumper($resp);
 	    return $resp->{status};
 	} 
     }
@@ -146,4 +145,20 @@
     return $resp->{status};
 }
 
+# utility methods
+# note: this modifies the original hash by adding the id property
+sub hash_to_array {
+    my ($hash, $idprop) = @_;
+
+    my $res = [];
+    return $res if !$hash;
+
+    foreach my $k (keys %$hash) {
+	$hash->{$k}->{$idprop} = $k;
+	push @$res, $hash->{$k};
+    }
+
+    return $res;
+}
+
 1;

Modified: pve-manager/pve2/www/manager/Makefile.am
===================================================================
--- pve-manager/pve2/www/manager/Makefile.am	2010-07-14 12:33:41 UTC (rev 4900)
+++ pve-manager/pve2/www/manager/Makefile.am	2010-07-15 09:57:39 UTC (rev 4901)
@@ -4,6 +4,7 @@
 	../ext/extjs/examples/ux/MultiSelect.js	 	\
 	../ext/extjs/examples/ux/BufferView.js 		\
 	PVEUtils.js 					\
+	util/base64.js					\
 	data/ObjectReader.js				\
 	data/ObjectStore.js				\
 	data/UpdateStore.js				\

Modified: pve-manager/pve2/www/manager/StorageBrowser.js
===================================================================
--- pve-manager/pve2/www/manager/StorageBrowser.js	2010-07-14 12:33:41 UTC (rev 4900)
+++ pve-manager/pve2/www/manager/StorageBrowser.js	2010-07-15 09:57:39 UTC (rev 4901)
@@ -1,19 +1,48 @@
 Ext.ns("PVE");
 
-PVE.StorageStatus = Ext.extend(Ext.Panel, {
+PVE.StorageStatus = Ext.extend(PVE.grid.ObjectView, {
 
     initComponent : function() {
 	var self = this;
 
+	var storeid = self.confdata.storage;
+	var node = self.confdata.node;
+
+	if (!storeid)
+	    throw "no storage id specified";
+
+	if (!node)
+	    throw "no node specified";
+
+	var smid = Ext.util.base64.encode("storage.status." + node + '.' + storeid);  
+	var store = Ext.StoreMgr.lookup(smid);
+
+	if (!store) {
+	    store = new PVE.data.ObjectStore({
+		url: "/api2/json/storage/status/" + node + "/" + storeid,
+		method: 'GET',
+		id: smid,
+		simpleSelect: true,
+		rows: {
+		    total: { header: 'Capacity' },
+		    used: { header: 'Used' },
+		    free: { header: 'Free' }
+		}
+	    });
+	}
+
+	store.load();
+
 	Ext.apply(self, {
 	    layout: 'fit',
 	    tbar: [ 
 		"<b>Status", '->',
 		{ 
-		    text: "Refresh"
+		    text: "Refresh",
+		    handler: function() { store.load(); }
 		}
 	    ],
-	    html: "data2345"
+	    store: store
 	});
 
 	PVE.StorageStatus.superclass.initComponent.call(self);
@@ -91,6 +120,10 @@
 		    //flex: 1,
 		},
 		new PVE.StorageStatus ({
+		    confdata: {
+			storage: self.confdata.storage,
+			node: self.confdata.node || 'localhost'
+		    },
 		    width: 300
 		})
 	    ]
@@ -143,7 +176,7 @@
 	    }
 	};
 
-	var smid = "storage.config." + storeid;  
+	var smid =  Ext.util.base64.encode("storage.config." + storeid);  
 	var store = Ext.StoreMgr.lookup(smid);
 
 	var set_visible_tabs = function() {
@@ -175,10 +208,6 @@
 	    });
 	} 
 
-	store.on('load',  set_visible_tabs);
-
-	store.load();
-
 	Ext.apply(self, {
 	    title: title, 
 	    layout: 'fit',
@@ -224,6 +253,10 @@
 	    ]
 	});
 
+	store.on('load',  set_visible_tabs);
+
+	store.load();
+
 	PVE.StorageBrowser.superclass.initComponent.call(self);
 
 	self.on('destroy', function () {

Added: pve-manager/pve2/www/manager/util/base64.js
===================================================================
--- pve-manager/pve2/www/manager/util/base64.js	                        (rev 0)
+++ pve-manager/pve2/www/manager/util/base64.js	2010-07-15 09:57:39 UTC (rev 4901)
@@ -0,0 +1,52 @@
+
+// code from ExtJs Forum
+
+Ext.util.base64 = {
+
+    base64s : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
+    
+    encode: function(decStr){
+        if (typeof btoa === 'function') {
+             return btoa(decStr);            
+        }
+        var base64s = this.base64s;
+        var bits;
+        var dual;
+        var i = 0;
+        var encOut = "";
+        while(decStr.length >= i + 3){
+            bits = (decStr.charCodeAt(i++) & 0xff) <<16 | (decStr.charCodeAt(i++) & 0xff) <<8 | decStr.charCodeAt(i++) & 0xff;
+            encOut += base64s.charAt((bits & 0x00fc0000) >>18) + base64s.charAt((bits & 0x0003f000) >>12) + base64s.charAt((bits & 0x00000fc0) >> 6) + base64s.charAt((bits & 0x0000003f));
+        }
+        if(decStr.length -i > 0 && decStr.length -i < 3){
+            dual = Boolean(decStr.length -i -1);
+            bits = ((decStr.charCodeAt(i++) & 0xff) <<16) |    (dual ? (decStr.charCodeAt(i) & 0xff) <<8 : 0);
+            encOut += base64s.charAt((bits & 0x00fc0000) >>18) + base64s.charAt((bits & 0x0003f000) >>12) + (dual ? base64s.charAt((bits & 0x00000fc0) >>6) : '=') + '=';
+        }
+        return(encOut);
+    },
+    
+    decode: function(encStr){
+        if (typeof atob === 'function') {
+            return atob(encStr); 
+        }
+        var base64s = this.base64s;        
+        var bits;
+        var decOut = "";
+        var i = 0;
+        for(; i<encStr.length; i += 4){
+            bits = (base64s.indexOf(encStr.charAt(i)) & 0xff) <<18 | (base64s.indexOf(encStr.charAt(i +1)) & 0xff) <<12 | (base64s.indexOf(encStr.charAt(i +2)) & 0xff) << 6 | base64s.indexOf(encStr.charAt(i +3)) & 0xff;
+            decOut += String.fromCharCode((bits & 0xff0000) >>16, (bits & 0xff00) >>8, bits & 0xff);
+        }
+        if(encStr.charCodeAt(i -2) == 61){
+            return(decOut.substring(0, decOut.length -2));
+        }
+        else if(encStr.charCodeAt(i -1) == 61){
+            return(decOut.substring(0, decOut.length -1));
+        }
+        else {
+            return(decOut);
+        }
+    }
+
+};



More information about the pve-devel mailing list