[pve-devel] r5030 - in pve-storage/pve2: . PVE PVE/API2 PVE/API2/Storage

svn-commits at proxmox.com svn-commits at proxmox.com
Thu Aug 19 10:51:35 CEST 2010


Author: dietmar
Date: 2010-08-19 08:51:35 +0000 (Thu, 19 Aug 2010)
New Revision: 5030

Added:
   pve-storage/pve2/PVE/
   pve-storage/pve2/PVE/API2/
   pve-storage/pve2/PVE/API2/Makefile
   pve-storage/pve2/PVE/API2/Storage.pm
   pve-storage/pve2/PVE/API2/Storage/
   pve-storage/pve2/PVE/API2/Storage/Config.pm
   pve-storage/pve2/PVE/API2/Storage/Content.pm
   pve-storage/pve2/PVE/API2/Storage/Makefile
   pve-storage/pve2/PVE/API2/Storage/Scan.pm
   pve-storage/pve2/PVE/API2/Storage/Status.pm
   pve-storage/pve2/PVE/Makefile
Removed:
   pve-storage/pve2/API2Storage.pm
Modified:
   pve-storage/pve2/ChangeLog
   pve-storage/pve2/Makefile
   pve-storage/pve2/Storage.pm
   pve-storage/pve2/changelog.Debian
   pve-storage/pve2/copyright
   pve-storage/pve2/pvesm
Log:
start code cleanups - build is broken now



Deleted: pve-storage/pve2/API2Storage.pm
===================================================================
--- pve-storage/pve2/API2Storage.pm	2010-08-19 07:00:48 UTC (rev 5029)
+++ pve-storage/pve2/API2Storage.pm	2010-08-19 08:51:35 UTC (rev 5030)
@@ -1,572 +0,0 @@
-package PVE::API2::Storage;
-
-# fixme: split things into different files?
-
-# /storage/config GET whole config, CREATE storage
-# /storage/config/{storeid}/ GET/SET storage config
-
-# /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
-
-
-# iso/*.iso
-# vztmpl/*.tgz
-# backup/*.tar
-# images/{vmid}/*.qcow2
-# images/vm-100-test1
-
-use strict;
-use warnings;
-
-use PVE::SafeSyslog;
-use PVE::INotify qw(read_file write_file);;
-use PVE::Storage;
-use HTTP::Status qw(:constants);
-
-use Data::Dumper; # fixme: remove
-
-use PVE::RESTHandler;
-
-use base qw(PVE::RESTHandler);
-
-my @ctypes = qw(images vztmpl iso backup);
-
-__PACKAGE__->register_method ({
-    name => 'index', 
-    path => '', # /storage/
-    method => 'GET',
-    description => "Storage index.",
-    parameters => {
-    	additionalProperties => 0,
-	properties => {},
-    },
-    returns => {
-	type => 'array',
-	items => {
-	    type => "object",
-	    properties => { subdir => { type => 'string'} },
-	},
-	links => [ { rel => 'child', href => "{subdir}" } ],
-    },
-    code => sub {
-	my ($conn, $param) = @_;
-
-	my $res = [
-	    { subdir => 'config' },
-	    { subdir => 'status' },
-	    { subdir => 'content' },
-	    { subdir => 'index' },
-	    { subdir => 'scan' },
-	    ];
-	return $res;
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'read_config', 
-    path => 'config/{storage}', 
-    method => 'GET',
-    description => "Read storage configuration.",
-    parameters => {
-    	additionalProperties => 0,
-	properties => {
-	    storage => { type => 'string' },
-	},
-    },
-    returns => {},
-    code => sub {
-	my ($conn, $param) = @_;
-
-	my $cfg = read_file ("storagecfg");
-
-	my $scfg = PVE::Storage::storage_config ($cfg, $param->{storage});
-
-	$scfg->{digest} = $cfg->{digest};
-	$scfg->{time} = time(); # fixme: remove
-
-	my @cta;
-	foreach my $ct (keys %{$scfg->{content}}) {
-	    push @cta, $ct if $scfg->{content}->{$ct};
-	} 
-
-	$scfg->{content} =  join(',', @cta);
- 
-	return $scfg;
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'update_config',
-    protected => 1,
-    path => 'config/{storage}', 
-    method => 'PUT',
-    description => "Update storage configuration.",
-    parameters => {
-    	additionalProperties => 0,
-	properties => { 
-	    storage => { 
-		type => 'string', 
-	    },
-	    path => {
-		type => 'string',
-		optional => 1,
-	    },
-	    content => {
-		type => 'string',
-		optional => 1,
-	    },
-	    disable => {
-		type => 'boolean',
-		optional => 1,
-	    },
-	    shared => {
-		type => 'boolean',
-		optional => 1,
-	    },
-	    digest => {
-		type => 'string',
-		optional => 1,
-	    }
-	},
-    },
-    returns => { type => 'null' },
-    code => sub {
-	my ($conn, $param) = @_;
-
-	my $storeid = $param->{storage};
-	delete($param->{storage});
- 
-	my $digest = $param->{digest};
-	delete($param->{digest});
-
-	PVE::Storage::storage_set($storeid, $param, $digest);
-
-	return undef;
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'list_storage_config', 
-    path => 'config', # /storage/config
-    method => 'GET',
-    description => "Storage index.",
-    parameters => {
-    	additionalProperties => 0,
-	properties => {},
-    },
-    returns => {
-	type => 'array',
-	items => {
-	    type => "object",
-	    properties => { storage => { type => 'string'} },
-	},
-	links => [ { rel => 'child', href => "{storage}" } ],
-    },
-    code => sub {
-	my ($conn, $param) = @_;
-
-	my $cfg = read_file ("storagecfg");
-
-	my @sids =  PVE::Storage::storage_ids ($cfg);
-
-	my $res = [];
-	foreach my $storeid (@sids) {
-	    my $scfg = PVE::Storage::storage_config ($cfg, $storeid);
-	    $scfg->{storage} = $storeid;
-	    push @$res, $scfg;
-	}
-
-	return $res;
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'scan_index', 
-    path => 'scan', 
-    method => 'GET',
-    description => "Index of available scan methods",
-    parameters => {
-    	additionalProperties => 0,
-	properties => {},
-    },
-    returns => {
-	type => 'array',
-	items => {
-	    type => "object",
-	    properties => { method => { type => 'string'} },
-	},
-	links => [ { rel => 'child', href => "{method}" } ],
-    },
-    code => sub {
-	my ($conn, $param) = @_;
-
-	my $res = [ 
-	    { method => 'lvm' },
-	    { method => 'iscsi' },
-	    { method => 'nfs' },
-	    ];
-
-	return $res;
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'scan_server', 
-    path => 'scan/{method}', 
-    method => 'GET',
-    description => "Scan remote storage server.",
-    parameters => {
-    	additionalProperties => 0,
-	properties => {
-	    method => { 
-		type => 'string',
-		enum => [ 'lvm', 'nfs', 'iscsi' ],
-	    }
-	},
-    },
-    returns => {},
-    code => sub {
-	my ($conn, $param) = @_;
-
-	return [];
-    }});
-
-# fixme: move to somewhere else
-__PACKAGE__->register_method ({
-    name => 'cluster_index', 
-    path => 'index', 
-    method => 'GET',
-    description => "Cluster wide storage status.",
-    parameters => {
-    	additionalProperties => 0,
-	properties => {},
-    },
-    returns => {
-	type => 'array',
-	items => {
-	    type => "object",
-	    properties => {},
-	},
-#	links => [ { rel => 'child', href => "{storage}" } ],
-    },
-    code => sub {
-	my ($conn, $param) = @_;
-
-	my $nodes = [ 'node-0', 'node-1', 'node-2', 'node-3' ]; # fixme: use the real list
-
-	my $cfg = 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', 
-    # /storage/(status|content)
-    path => '{subdir}',  
-    method => 'GET',
-    description => "List storage nodes.",
-    parameters => {
-    	additionalProperties => 0,
-	properties => {
-	    subdir => {
-		type => 'string',
-		enum => [ 'status', 'content' ],
-	    },
-	},
-    },
-    returns => {
-	type => 'array',
-	items => {
-	    type => "object",
-	    properties => { node => { type => 'string' } },
-	},
-	links => [ { rel => 'child', href => "{node}" } ],
-    },
-    code => sub {
-	my ($conn, $param) = @_;
-
-	# fixme: use the real list
-	my $nodes = [ 
-	    { node => 'node-0'},
-	    { node => 'node-1'},
-	    { node => 'node-2'},
-	    { node => 'node-3'},
-	    ];
-
-	return $nodes;
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'list_store_ids', 
-    # /storage/content/{node}/
-    path => 'content/{node}', 
-    method => 'GET',
-    description => "List storage IDs.",
-    parameters => {
-    	additionalProperties => 0,
-	properties => {
-	    node => {
-		type => 'string',		
-	    },
-	},
-    },
-    returns => {
-	type => 'array',
-	items => {
-	    type => "object",
-	    properties => { storage => { type => 'string' } },
-	},
-	links => [ { rel => 'child', href => "{storage}" } ],
-    },
-    code => sub {
-	my ($conn, $param) = @_;
-
-	my $cfg = read_file ("storagecfg");
-
-	my $node = $param->{node};
-
-	# fixme: verify node (node exists)?
-
-	my @sids =  PVE::Storage::storage_ids ($cfg);
-
-	my $res = [];
-	foreach my $storeid (@sids) {
-	    # fixme: check if storeage exists on node ?
-	    push @$res, { storage => $storeid };
-	}
-
-	return $res;
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'list_content', 
-    protected => 1,
-    # /storage/content/{nodeid}/{storeid}
-    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  ],
-		optional => 1,
-	    }
-	},
-    },
-    returns => {
-	type => 'array',
-	items => {
-	    type => "object",
-	    properties => { 
-		volname => { 
-		    type => 'string' 
-		} 
-	    },
-	},
-	links => [ { rel => 'child', href => "{volname}" } ],
-    },
-    code => sub {
-	my ($conn, $param) = @_;
-
-	my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
-
-	my $node = $param->{node};
-	my $storeid = $param->{storage};
-
-	# fixme: verify $node
-
-	my $cfg = read_file ("storagecfg");
-
-	my $scfg = PVE::Storage::storage_config ($cfg, $storeid);
-
-	my $res = [];
-	foreach my $ct (@$cts) {
-	    my $data;
-	    if ($ct eq 'images') {
-		$data = PVE::Storage::vdisk_list ($cfg, $storeid);
-	    } elsif ($ct eq 'iso') {
-		$data = PVE::Storage::template_list ($cfg, $storeid, 'iso');
-	    } elsif ($ct eq 'vztmpl') {
-		$data = PVE::Storage::template_list ($cfg, $storeid, 'vztmpl');
-	    } elsif ($ct eq 'backup') {
-		$data = PVE::Storage::template_list ($cfg, $storeid, 'backup');
-	    }
-
-	    next if !$data || !$data->{$storeid};
-
-	    foreach my $item (@{$data->{$storeid}}) {
-		push @$res, $item;
-	    }
-	}
-
-	return $res;    
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'upload_content', 
-    # /storage/content/{nodeid}/{storeid}
-    path => 'content/{node}/{storage}',
-    method => 'POST',
-    description => "Upload content.",
-    parameters => {
-    	additionalProperties => 0,
-	properties => { 
-	    node => {
-		type => 'string',		
-	    },
-	    storage => {
-		type => 'string',		
-	    },
-	    upload => {
-		type => 'string',		
-	    },
-	},
-    },
-    returns => { type => 'null' },
-    code => sub {
-	my ($conn, $param) = @_;
-
-	my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
-
-	my $node = $param->{node};
-	my $storeid = $param->{storage};
-	my $filename = $param->{upload};
-	my $fh = CGI::upload('upload') || die "unable to get file handle\n";
-
-	syslog ('info', "UPLOAD $filename to $node $storeid");
-	
-	die "upload not implemented\n";
-
-	my $buffer = "";
-	my $tmpname = "/tmp/proxmox_upload-$$.bin";
-
-	eval {
-	    open FILE, ">$tmpname" || die "can't open temporary file '$tmpname' - $!\n";
-	    while (read($fh, $buffer, 32768)) {
-		die "write failed - $!" unless print FILE $buffer;
-	    }
-	    close FILE || die " can't close temporary file '$tmpname' - $!\n";
-	};
-	my $err = $@;
-
-	if ($err) {
-	    unlink $tmpname;
-	    die $err;
-	}
-
-	unlink $tmpname; # fixme: proxy to local host import
-
-	return undef;
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'list_status', 
-    protected => 1,
-    # /storage/status/{nodeid}
-    path => 'status/{node}',
-    method => 'GET',
-    description => "Get status for all datastores.",
-    parameters => {
-    	additionalProperties => 0,
-	properties => {
-	    node => {
-		type => 'string',
-	    }
-	},
-    },
-    returns => {
-	type => 'array',
-	items => {
-	    type => "object",
-	    properties => { storage => { type => 'string' } },
-	},
-	links => [ { rel => 'child', href => "{storage}" } ],
-    },
-    code => sub {
-	my ($conn, $param) = @_;
-
-	my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
-	
-	my $node = $param->{node};
-
-	# fixme: verify $node
-
-	my $cfg = read_file ("storagecfg");
-
-	# fixme: connect to correct node
-
-	my $info = PVE::Storage::storage_info ($cfg);
-
-	return PVE::RESTHandler::hash_to_array($info, 'storage');
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'get_status', 
-    protected => 1,
-    # /storage/status/{nodeid}/{storeid}
-    path => 'status/{node}/{storage}',
-    method => 'GET',
-    description => "Get status for specific datastore.",
-    parameters => {
-    	additionalProperties => 0,
-	properties => {
-	    node => {
-		type => 'string',		
-	    },
-	    storage => {
-		type => 'string',		
-	    },
-	},
-    },
-    returns => {},
-    code =>  sub {
-	my ($conn, $param) = @_;
-
-	my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
-
-	my $node = $param->{node};
-	my $storeid = $param->{storage};
-
-	# fixme: verify $node
-
-	my $cfg = read_file ("storagecfg");
-
-	# fixme: connect to correct node
-
-	my $info = PVE::Storage::storage_info ($cfg);
-	
-	return $info->{$storeid};
-    }});
-
-1;

Modified: pve-storage/pve2/ChangeLog
===================================================================
--- pve-storage/pve2/ChangeLog	2010-08-19 07:00:48 UTC (rev 5029)
+++ pve-storage/pve2/ChangeLog	2010-08-19 08:51:35 UTC (rev 5030)
@@ -2,6 +2,8 @@
 
 	* API2::Storage.pm: moved from pve-manager
 
+	* split API::Storage into different files
+	
 2010-08-16  Proxmox Support Team  <support at proxmox.com>
 
 	* Storage.pm (file_read_firstline): import from PVE::Tools

Modified: pve-storage/pve2/Makefile
===================================================================
--- pve-storage/pve2/Makefile	2010-08-19 07:00:48 UTC (rev 5029)
+++ pve-storage/pve2/Makefile	2010-08-19 08:51:35 UTC (rev 5030)
@@ -1,8 +1,8 @@
-RELEASE=1.5
+RELEASE=2.0
 
-VERSION=1.0
+VERSION=2.0
 PACKAGE=libpve-storage-perl
-PKGREL=10
+PKGREL=1
 
 DESTDIR=
 PREFIX=/usr
@@ -11,7 +11,7 @@
 MANDIR=${PREFIX}/share/man
 DOCDIR=${PREFIX}/share/doc
 MAN1DIR=${MANDIR}/man1/
-PERLDIR=${PREFIX}/share/perl5
+export PERLDIR=${PREFIX}/share/perl5
 
 #ARCH:=$(shell dpkg-architecture -qDEB_BUILD_ARCH)
 ARCH=all
@@ -24,19 +24,21 @@
 dinstall: deb
 	dpkg -i ${DEB}
 
-install: pvesm Storage.pm API2Storage.pm
+.PHONY: install
+install:
 	install -d ${DESTDIR}${SBINDIR}
 	install -m 0755 pvesm ${DESTDIR}${SBINDIR}
 	install -D -m 0644 Storage.pm ${DESTDIR}${PERLDIR}/PVE/Storage.pm
-	install -D -m 0644 API2Storage.pm ${DESTDIR}${PERLDIR}/PVE/API2/Storage.pm
+	make -C PVE install
+#	install -D -m 0644 API2Storage.pm ${DESTDIR}${PERLDIR}/PVE/API2/Storage.pm
 	install -d ${DESTDIR}/usr/share/man/man1
 	pod2man -n pvesm -s 1 -r "proxmox 1.0" -c "Proxmox Documentation" <pvesm | gzip -9 > ${DESTDIR}/usr/share/man/man1/pvesm.1.gz
 
-.PHONY: deb
-deb ${DEB}: pvesm Storage.pm API2Storage.pm control.in copyright changelog.Debian ChangeLog
+.PHONY: deb ${DEB}
+deb ${DEB}:
 	rm -rf debian
 	mkdir debian
-	make DESTDIR=debian install
+	make DESTDIR=${CURDIR}/debian install
 	install -d -m 0755 debian/DEBIAN
 	sed -e s/@@VERSION@@/${VERSION}/ -e s/@@PKGRELEASE@@/${PKGREL}/ -e s/@@ARCH@@/${ARCH}/ <control.in >debian/DEBIAN/control
 	install -D -m 0644 copyright debian/${DOCDIR}/${PACKAGE}/copyright

Added: pve-storage/pve2/PVE/API2/Makefile
===================================================================
--- pve-storage/pve2/PVE/API2/Makefile	                        (rev 0)
+++ pve-storage/pve2/PVE/API2/Makefile	2010-08-19 08:51:35 UTC (rev 5030)
@@ -0,0 +1,6 @@
+
+
+.PHONY: install
+install:
+	install -D -m 0644 Storage.pm ${DESTDIR}${PERLDIR}/PVE/API2/Storage.pm
+	make -C Storage install
\ No newline at end of file

Added: pve-storage/pve2/PVE/API2/Storage/Config.pm
===================================================================
--- pve-storage/pve2/PVE/API2/Storage/Config.pm	                        (rev 0)
+++ pve-storage/pve2/PVE/API2/Storage/Config.pm	2010-08-19 08:51:35 UTC (rev 5030)
@@ -0,0 +1,319 @@
+package PVE::API2::Storage::Config;
+
+use strict;
+use warnings;
+
+use PVE::SafeSyslog;
+use PVE::INotify qw(read_file write_file);;
+use PVE::Storage;
+use HTTP::Status qw(:constants);
+use Storable qw(dclone);
+
+use Data::Dumper; # fixme: remove
+
+use PVE::RESTHandler;
+
+use base qw(PVE::RESTHandler);
+
+my @ctypes = qw(images vztmpl iso backup);
+
+my $storage_type_enum = ['dir', 'nfs', 'lvm', 'iscsi'];
+
+my $api_storage_config = sub {
+    my ($cfg, $storeid) = @_;
+
+    my $scfg = dclone(PVE::Storage::storage_config ($cfg, $storeid));
+    $scfg->{storage} = $storeid;
+    delete $scfg->{priority};
+    $scfg->{digest} = $cfg->{digest};
+    $scfg->{content} = PVE::Storage::content_hash_to_string($scfg->{content});
+
+    return $scfg;
+};
+
+__PACKAGE__->register_method ({
+    name => 'index', 
+    path => '',
+    method => 'GET',
+    description => "Storage index.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {
+	    type => { 
+		description => "Only list storage of specific type",
+		type => 'string', 
+		enum => $storage_type_enum,
+		optional => 1,
+	    },
+
+	},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => { storage => { type => 'string'} },
+	},
+	links => [ { rel => 'child', href => "{storage}" } ],
+    },
+    code => sub {
+	my ($conn, $param) = @_;
+
+	my $cfg = read_file ("storagecfg");
+
+	my @sids =  PVE::Storage::storage_ids ($cfg);
+
+	my $res = [];
+	foreach my $storeid (@sids) {
+	    my $scfg = &$api_storage_config($cfg, $storeid);
+	    next if $param->{type} && $param->{type} ne $scfg->{type};
+	    push @$res, $scfg;
+	}
+
+	return $res;
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'read', 
+    path => '{storage}',
+    method => 'GET',
+    description => "Read storage configuration.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {
+	    storage => { type => 'string', format => 'pve-storage-id' },
+	},
+    },
+    returns => {},
+    code => sub {
+	my ($conn, $param) = @_;
+
+	my $cfg = read_file ("storagecfg");
+
+	return &$api_storage_config($cfg, $param->{storage});
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'create',
+    protected => 1,
+    path => '{storage}', 
+    method => 'POST',
+    description => "Create a new storage.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => { 
+	    storage => { type => 'string', format => 'pve-storage-id' },
+	    type => { 
+		type => 'string', 
+		enum => $storage_type_enum,
+	    },
+	    path => {
+		type => 'string', format => 'pve-storage-path',
+		optional => 1,
+	    },
+	    export => {
+		type => 'string', format => 'pve-storage-path',
+		optional => 1,
+	    },
+            server => {
+		type => 'string', format => 'pve-storage-server',
+		optional => 1,
+            },
+	    options => {
+		type => 'string',  format => 'pve-storage-options',
+		optional => 1,
+	    },
+            target => {
+		type => 'string', format => 'pve-storage-server',
+		optional => 1,
+            },
+            vgname => {
+		type => 'string', format => 'pve-storage-vgname',
+		optional => 1,
+            },
+            portal => {
+		type => 'string', format => 'pve-storage-portal',
+		optional => 1,
+            },
+	    content => {
+		type => 'string', format => 'pve-storage-content-list',
+		optional => 1,
+	    },
+	    disable => {
+		type => 'boolean',
+		optional => 1,
+	    },
+	    shared => {
+		type => 'boolean',
+		optional => 1,
+	    },
+	    'format' => { 
+		type => 'string', format => 'pve-storage-format',
+		optional => 1,
+	    },
+	},
+    },
+    returns => { type => 'null' },
+    code => sub {
+	my ($conn, $param) = @_;
+
+	my $type = $param->{type};
+	delete $param->{type};
+
+	my $storeid = $param->{storage};
+	delete $param->{storage};
+
+	my $opts = PVE::Storage::parse_options_new($storeid, $type, $param, 1);
+
+        PVE::Storage::lock_storage_config(
+	    sub {
+
+		my $cfg = read_file('storagecfg');
+
+		if (my $scfg = PVE::Storage::storage_config ($cfg, $storeid, 1)) {
+		    die "storage ID '$storeid' already defined\n";
+		}
+
+		$cfg->{ids}->{$storeid} = $opts;
+
+		if ($type eq 'lvm' && $opts->{base}) {
+
+		    my ($baseid, $volname) = PVE::Storage::parse_volume_id ($opts->{base});
+
+		    my $basecfg = PVE::Storage::storage_config ($cfg, $baseid, 1);
+		    die "base storage ID '$baseid' does not exist\n" if !$basecfg;
+       
+		    # we only support iscsi for now
+		    if (!($basecfg->{type} eq 'iscsi')) {
+			die "unsupported base type '$basecfg->{type}'";
+		    }
+
+		    my $path =  PVE::Storage::path ($cfg, $opts->{base});
+
+		    PVE::Storage::lvm_create_volume_group ($path, $opts->{vgname}, $opts->{shared});
+		}
+	
+		PVE::Storage::activate_storage ($cfg, $storeid) if !$opts->{disable};
+
+		write_file('storagecfg', $cfg);
+	    
+	    }, "create storage failed");
+
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'update',
+    protected => 1,
+    path => '{storage}',
+    method => 'PUT',
+    description => "Update storage configuration.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => { 
+	    storage => { type => 'string', format => 'pve-storage-id' },
+	    content => {
+		type => 'string', format => 'pve-storage-content-list',
+		optional => 1,
+	    },
+	    'format' => { 
+		type => 'string', format => 'pve-storage-format',
+		optional => 1,
+	    },
+	    disable => {
+		type => 'boolean',
+		optional => 1,
+	    },
+	    shared => {
+		type => 'boolean',
+		optional => 1,
+	    },
+	    options => {
+		type => 'string', format => 'pve-storage-options',
+		optional => 1,
+	    },
+	    digest => {
+		type => 'string',
+		optional => 1,
+	    }
+	},
+    },
+    returns => { type => 'null' },
+    code => sub {
+	my ($conn, $param) = @_;
+
+	my $storeid = $param->{storage};
+	delete($param->{storage});
+ 
+	my $digest = $param->{digest};
+	delete($param->{digest});
+
+        PVE::Storage::lock_storage_config(
+	 sub {
+
+	    my $cfg = read_file('storagecfg');
+
+	    PVE::Storage::assert_if_modified ($cfg, $digest);
+
+	    my $scfg = PVE::Storage::storage_config ($cfg, $storeid);
+
+	    my $opts = PVE::Storage::parse_options_new($storeid, $scfg->{type}, $param);
+
+	    foreach my $k (%$opts) {
+		$scfg->{$k} = $opts->{$k};
+	    }
+
+	    if (defined($opts->{disable})) {
+		if ($opts->{disable}) {
+		    PVE::Storage::deactivate_storage ($cfg, $storeid);
+		} else {
+		    delete $scfg->{disable};
+		    PVE::Storage::activate_storage ($cfg, $storeid);	
+		}
+	    }
+
+	    write_file('storagecfg', $cfg);
+
+	    }, "update storage failed");
+
+	return undef;
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'delete',
+    protected => 1,
+    path => '{storage}', # /storage/config/{storage}
+    method => 'DELETE',
+    description => "Delete storage configuration.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => { 
+	    storage => { type => 'string', format => 'pve-storage-id' },
+	},
+    },
+    returns => { type => 'null' },
+    code => sub {
+	my ($conn, $param) = @_;
+
+	my $storeid = $param->{storage};
+	delete($param->{storage});
+ 
+        PVE::Storage::lock_storage_config(
+	    sub {
+
+		my $cfg = read_file('storagecfg');
+
+		die "can't remove storage - storage is used as base of another storage\n"
+		    if PVE::Storage::storage_is_used ($cfg, $storeid);
+
+		PVE::Storage::deactivate_storage ($cfg, $storeid);
+
+		delete ($cfg->{ids}->{$storeid});
+
+		write_file('storagecfg', $cfg);
+
+	    }, "delete storage failed");
+  
+	return undef;
+    }});
+
+1;


Property changes on: pve-storage/pve2/PVE/API2/Storage/Config.pm
___________________________________________________________________
Added: svn:executable
   + *

Added: pve-storage/pve2/PVE/API2/Storage/Content.pm
===================================================================
--- pve-storage/pve2/PVE/API2/Storage/Content.pm	                        (rev 0)
+++ pve-storage/pve2/PVE/API2/Storage/Content.pm	2010-08-19 08:51:35 UTC (rev 5030)
@@ -0,0 +1,215 @@
+package PVE::API2::Storage::Content;
+
+use strict;
+use warnings;
+
+use PVE::INotify qw(read_file write_file);;
+use PVE::Storage;
+
+use PVE::RESTHandler;
+
+use base qw(PVE::RESTHandler);
+
+my @ctypes = qw(images vztmpl iso backup);
+
+__PACKAGE__->register_method ({
+    name => 'index', 
+    path => '',  
+    method => 'GET',
+    description => "List cluster nodes.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => { node => { type => 'string' } },
+	},
+	links => [ { rel => 'child', href => "{node}" } ],
+    },
+    code => sub {
+	my ($conn, $param) = @_;
+
+	# fixme: use the real list
+	my $nodes = [ 
+	    { node => 'node-0'},
+	    { node => 'node-1'},
+	    { node => 'node-2'},
+	    { node => 'node-3'},
+	    ];
+
+	return $nodes;
+
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'list_ids', 
+    path => '{node}', 
+    method => 'GET',
+    description => "List storage IDs.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {
+	    node => {
+		type => 'string',		
+	    },
+	},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => { storage => { type => 'string' } },
+	},
+	links => [ { rel => 'child', href => "{storage}" } ],
+    },
+    code => sub {
+	my ($conn, $param) = @_;
+
+	my $cfg = read_file ("storagecfg");
+
+	my $node = $param->{node};
+
+	# fixme: verify node (node exists)?
+
+	my @sids =  PVE::Storage::storage_ids ($cfg);
+
+	my $res = [];
+	foreach my $storeid (@sids) {
+	    # fixme: check if storeage exists on node ?
+	    push @$res, { storage => $storeid };
+	}
+
+	return $res;
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'content', 
+    protected => 1,
+    path => '{node}/{storage}',
+    method => 'GET',
+    description => "List storage content.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => { 
+	    node => {
+		type => 'string',		
+	    },
+	    storage => {
+		type => 'string',		
+	    },
+	    content => {
+		type => 'string',
+		enum => [ @ctypes  ],
+		optional => 1,
+	    }
+	},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => { 
+		volname => { 
+		    type => 'string' 
+		} 
+	    },
+	},
+	links => [ { rel => 'child', href => "{volname}" } ],
+    },
+    code => sub {
+	my ($conn, $param) = @_;
+
+	my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
+
+	my $node = $param->{node};
+	my $storeid = $param->{storage};
+
+	# fixme: verify $node
+
+	my $cfg = read_file ("storagecfg");
+
+	my $scfg = PVE::Storage::storage_config ($cfg, $storeid);
+
+	my $res = [];
+	foreach my $ct (@$cts) {
+	    my $data;
+	    if ($ct eq 'images') {
+		$data = PVE::Storage::vdisk_list ($cfg, $storeid);
+	    } elsif ($ct eq 'iso') {
+		$data = PVE::Storage::template_list ($cfg, $storeid, 'iso');
+	    } elsif ($ct eq 'vztmpl') {
+		$data = PVE::Storage::template_list ($cfg, $storeid, 'vztmpl');
+	    } elsif ($ct eq 'backup') {
+		$data = PVE::Storage::template_list ($cfg, $storeid, 'backup');
+	    }
+
+	    next if !$data || !$data->{$storeid};
+
+	    foreach my $item (@{$data->{$storeid}}) {
+		push @$res, $item;
+	    }
+	}
+
+	return $res;    
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'upload', 
+    path => '{node}/{storage}',
+    method => 'POST',
+    description => "Upload content.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => { 
+	    node => {
+		type => 'string',		
+	    },
+	    storage => {
+		type => 'string',		
+	    },
+	    upload => {
+		type => 'string',		
+	    },
+	},
+    },
+    returns => { type => 'null' },
+    code => sub {
+	my ($conn, $param) = @_;
+
+	my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
+
+	my $node = $param->{node};
+	my $storeid = $param->{storage};
+	my $filename = $param->{upload};
+	my $fh = CGI::upload('upload') || die "unable to get file handle\n";
+
+	syslog ('info', "UPLOAD $filename to $node $storeid");
+	
+	die "upload not implemented\n";
+
+	my $buffer = "";
+	my $tmpname = "/tmp/proxmox_upload-$$.bin";
+
+	eval {
+	    open FILE, ">$tmpname" || die "can't open temporary file '$tmpname' - $!\n";
+	    while (read($fh, $buffer, 32768)) {
+		die "write failed - $!" unless print FILE $buffer;
+	    }
+	    close FILE || die " can't close temporary file '$tmpname' - $!\n";
+	};
+	my $err = $@;
+
+	if ($err) {
+	    unlink $tmpname;
+	    die $err;
+	}
+
+	unlink $tmpname; # fixme: proxy to local host import
+
+	return undef;
+    }});
+
+1;

Added: pve-storage/pve2/PVE/API2/Storage/Makefile
===================================================================
--- pve-storage/pve2/PVE/API2/Storage/Makefile	                        (rev 0)
+++ pve-storage/pve2/PVE/API2/Storage/Makefile	2010-08-19 08:51:35 UTC (rev 5030)
@@ -0,0 +1,6 @@
+
+SOURCES= Content.pm Status.pm Config.pm Scan.pm
+
+.PHONY: install
+install:
+	for i in ${SOURCES}; do install -D -m 0644 $$i ${DESTDIR}${PERLDIR}/PVE/API2/Storage/$$i; done

Added: pve-storage/pve2/PVE/API2/Storage/Scan.pm
===================================================================
--- pve-storage/pve2/PVE/API2/Storage/Scan.pm	                        (rev 0)
+++ pve-storage/pve2/PVE/API2/Storage/Scan.pm	2010-08-19 08:51:35 UTC (rev 5030)
@@ -0,0 +1,65 @@
+package PVE::API2::Storage::Scan;
+
+use strict;
+use warnings;
+
+use PVE::SafeSyslog;
+use PVE::INotify qw(read_file write_file);;
+use PVE::Storage;
+use HTTP::Status qw(:constants);
+
+use PVE::RESTHandler;
+
+use base qw(PVE::RESTHandler);
+
+__PACKAGE__->register_method ({
+    name => 'index', 
+    path => '', 
+    method => 'GET',
+    description => "Index of available scan methods",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => { method => { type => 'string'} },
+	},
+	links => [ { rel => 'child', href => "{method}" } ],
+    },
+    code => sub {
+	my ($conn, $param) = @_;
+
+	my $res = [ 
+	    { method => 'lvm' },
+	    { method => 'iscsi' },
+	    { method => 'nfs' },
+	    ];
+
+	return $res;
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'scan', 
+    path => '{method}', 
+    method => 'GET',
+    description => "Scan remote storage server.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {
+	    method => { 
+		type => 'string',
+		enum => [ 'lvm', 'nfs', 'iscsi' ],
+	    }
+	},
+    },
+    returns => {},
+    code => sub {
+	my ($conn, $param) = @_;
+
+	return [];
+    }});
+
+1;

Added: pve-storage/pve2/PVE/API2/Storage/Status.pm
===================================================================
--- pve-storage/pve2/PVE/API2/Storage/Status.pm	                        (rev 0)
+++ pve-storage/pve2/PVE/API2/Storage/Status.pm	2010-08-19 08:51:35 UTC (rev 5030)
@@ -0,0 +1,126 @@
+package PVE::API2::Storage::Status;
+
+use strict;
+use warnings;
+
+use PVE::INotify qw(read_file write_file);;
+use PVE::Storage;
+
+use PVE::RESTHandler;
+
+use base qw(PVE::RESTHandler);
+
+my @ctypes = qw(images vztmpl iso backup);
+
+__PACKAGE__->register_method ({
+    name => 'index', 
+    path => '',  
+    method => 'GET',
+    description => "List cluster nodes.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => { node => { type => 'string' } },
+	},
+	links => [ { rel => 'child', href => "{node}" } ],
+    },
+    code => sub {
+	my ($conn, $param) = @_;
+
+	# fixme: use the real list
+	my $nodes = [ 
+	    { node => 'node-0'},
+	    { node => 'node-1'},
+	    { node => 'node-2'},
+	    { node => 'node-3'},
+	    ];
+
+	return $nodes;
+
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'list_status', 
+    protected => 1,
+    # /storage/status/{nodeid}
+    path => 'status/{node}',
+    method => 'GET',
+    description => "Get status for all datastores.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {
+	    node => {
+		type => 'string',
+	    }
+	},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => { storage => { type => 'string' } },
+	},
+	links => [ { rel => 'child', href => "{storage}" } ],
+    },
+    code => sub {
+	my ($conn, $param) = @_;
+
+	my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
+	
+	my $node = $param->{node};
+
+	# fixme: verify $node
+
+	my $cfg = read_file ("storagecfg");
+
+	# fixme: connect to correct node
+
+	my $info = PVE::Storage::storage_info ($cfg);
+
+	return PVE::RESTHandler::hash_to_array($info, 'storage');
+    }});
+
+__PACKAGE__->register_method ({
+    name => 'get_status', 
+    protected => 1,
+    # /storage/status/{nodeid}/{storeid}
+    path => 'status/{node}/{storage}',
+    method => 'GET',
+    description => "Get status for specific datastore.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {
+	    node => {
+		type => 'string',		
+	    },
+	    storage => {
+		type => 'string',		
+	    },
+	},
+    },
+    returns => {},
+    code =>  sub {
+	my ($conn, $param) = @_;
+
+	my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
+
+	my $node = $param->{node};
+	my $storeid = $param->{storage};
+
+	# fixme: verify $node
+
+	my $cfg = read_file ("storagecfg");
+
+	# fixme: connect to correct node
+
+	my $info = PVE::Storage::storage_info ($cfg);
+	
+	return $info->{$storeid};
+    }});
+
+1;

Added: pve-storage/pve2/PVE/API2/Storage.pm
===================================================================
--- pve-storage/pve2/PVE/API2/Storage.pm	                        (rev 0)
+++ pve-storage/pve2/PVE/API2/Storage.pm	2010-08-19 08:51:35 UTC (rev 5030)
@@ -0,0 +1,121 @@
+package PVE::API2::Storage;
+
+use strict;
+use warnings;
+
+use PVE::SafeSyslog;
+use PVE::INotify qw(read_file write_file);;
+use PVE::Storage;
+use HTTP::Status qw(:constants);
+use Storable qw(dclone);
+
+use Data::Dumper; # fixme: remove
+
+use PVE::RESTHandler;
+
+use base qw(PVE::RESTHandler);
+
+my @ctypes = qw(images vztmpl iso backup);
+
+my $storage_type_enum = ['dir', 'nfs', 'lvm', 'iscsi'];
+
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::Storage::Config",  
+    path => 'config',
+});
+
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::Storage::Scan",  
+    path => 'scan',
+});
+
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::Storage::Content",  
+    path => 'content',
+});
+
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::Storage::Status",  
+    path => 'status',
+});
+
+# fixme: use subclass to generate index
+__PACKAGE__->register_method ({
+    name => 'index', 
+    path => '',
+    method => 'GET',
+    description => "Storage index.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => { subdir => { type => 'string'} },
+	},
+	links => [ { rel => 'child', href => "{subdir}" } ],
+    },
+    code => sub {
+	my ($conn, $param) = @_;
+
+	my $res = [
+	    { subdir => 'config' },
+	    { subdir => 'status' },
+	    { subdir => 'content' },
+	    { subdir => 'index' },
+	    { subdir => 'scan' },
+	    ];
+	return $res;
+    }});
+
+# fixme: choose a better name/path ?
+__PACKAGE__->register_method ({
+    name => 'cluster_index', 
+    path => 'index', 
+    method => 'GET',
+    description => "Cluster wide storage status.",
+    parameters => {
+    	additionalProperties => 0,
+	properties => {},
+    },
+    returns => {
+	type => 'array',
+	items => {
+	    type => "object",
+	    properties => {},
+	},
+#	links => [ { rel => 'child', href => "{storage}" } ],
+    },
+    code => sub {
+	my ($conn, $param) = @_;
+
+	my $nodes = [ 'node-0', 'node-1', 'node-2', 'node-3' ]; # fixme: use the real list
+
+	my $cfg = 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;
+    }});
+
+1;

Added: pve-storage/pve2/PVE/Makefile
===================================================================
--- pve-storage/pve2/PVE/Makefile	                        (rev 0)
+++ pve-storage/pve2/PVE/Makefile	2010-08-19 08:51:35 UTC (rev 5030)
@@ -0,0 +1,5 @@
+
+
+.PHONY: install
+install:
+	make -C API2 install
\ No newline at end of file

Modified: pve-storage/pve2/Storage.pm
===================================================================
--- pve-storage/pve2/Storage.pm	2010-08-19 07:00:48 UTC (rev 5029)
+++ pve-storage/pve2/Storage.pm	2010-08-19 08:51:35 UTC (rev 5030)
@@ -17,6 +17,8 @@
 use Digest::SHA1;
 use PVE::Tools qw(run_command lock_file safe_print file_read_firstline trim);
 use PVE::INotify qw(register_file read_file write_file);
+use PVE::Exception qw(raise_param_exc);
+use PVE::JSONSchema;
 
 my $ISCSIADM = '/usr/bin/iscsiadm';
 my $UDEVADM = '/sbin/udevadm';
@@ -293,7 +295,7 @@
     base   => 'volume',
     portal => 'portal',
     target => 'target',
-    options => 'string',
+    options => 'options',
 };
 
 my $required_config = {
@@ -357,43 +359,145 @@
     return $def->{content}->[0];
 }
 
+sub content_hash_to_string {
+    my $hash = shift;
+
+    my @cta;
+    foreach my $ct (keys %$hash) {
+	push @cta, $ct if $hash->{$ct};
+    } 
+
+    return join(',', @cta);
+}
+
+PVE::JSONSchema::register_format('pve-storage-path', \&verify_path);
+sub verify_path {
+    my ($path, $noerr) = @_;
+
+    # fixme: exclude more shell meta characters?
+    # we need absolute paths
+    if ($path !~ m|^/[^;\(\)]+|) {
+	return undef if $noerr;
+	die "value does not look like a valid absolute path\n";
+    }
+    return $path;
+}
+
+PVE::JSONSchema::register_format('pve-storage-server', \&verify_server);
+sub verify_server {
+    my ($server, $noerr) = @_;
+
+    # fixme: use better regex ?
+    # IP or DNS name
+    if ($server !~ m/^[[:alnum:]\-\.]+$/) {
+	return undef if $noerr;
+	die "value does not look like a valid server name or IP address\n";
+    }
+    return $server;
+}
+
+PVE::JSONSchema::register_format('pve-storage-portal', \&verify_portal);
+sub verify_portal {
+    my ($portal, $noerr) = @_;
+
+    # IP with optional port
+    if ($portal !~ m/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(:\d+)?$/) {
+	return undef if $noerr;
+	die "value does not look like a valid portal address\n";
+    }
+    return $portal;
+}
+
+PVE::JSONSchema::register_format('pve-storage-content', \&verify_content);
+sub verify_content {
+    my ($ct, $noerr) = @_;
+
+    my $valid_content = valid_content_types('dir'); # dir includes all types
+ 
+    if (!$valid_content->{$ct}) {
+	return undef if $noerr;
+	die "invalid content type '$ct'\n";
+    }
+
+    return $ct;
+}
+
+PVE::JSONSchema::register_format('pve-storage-format', \&verify_format);
+sub verify_format {
+    my ($fmt, $noerr) = @_;
+
+    if ($fmt !~ m/(raw|qcow2|vmdk)/) {
+	return undef if $noerr;
+	die "invalid format '$fmt'\n";
+    }
+
+    return $fmt;
+}
+
+PVE::JSONSchema::register_format('pve-storage-options', \&verify_options);
+sub verify_options {
+    my ($value, $noerr) = @_;
+
+    # mount options (see man fstab)
+    if ($value !~ m/^\S+$/) {
+	return undef if $noerr;
+	die "invalid options '$value'\n";
+    }
+
+    return $value;
+}
+
 sub check_type {
-    my ($stype, $ct, $key, $value, $storeid) = @_;
+    my ($stype, $ct, $key, $value, $storeid, $noerr) = @_;
 
     my $def = $default_config->{$stype};
 
-    return undef if !defined($def);
-    return undef if !defined($def->{$key});
+    if (!$def) { # should not happen
+	return undef if $noerr;	
+	die "unknown storage type '$stype'\n"; 
+    }
 
-    return undef if !defined ($value);
-    return undef if $value =~ m/[\n\r]/;
+    if (!defined($def->{$key})) {
+	return undef if $noerr;
+	die "unexpected property\n";
+    }
 
+    if (!defined ($value)) {
+	return undef if $noerr;
+	die "got undefined value\n";
+    }
+
+    if ($value =~ m/[\n\r]/) {
+	return undef if $noerr;
+	die "property contains a line feed\n";
+    }
+
     if ($ct eq 'bool') {
 	return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i); 
 	return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i); 
+	return undef if $noerr;
+	die "type check ('boolean') failed - got '$value'\n";	
+    } elsif ($ct eq 'options') {
+	return verify_options($value, $noerr);
     } elsif ($ct eq 'path') {
-	return undef if $value !~ m|^/.+|; # we need absolute paths
-	return $value;
+	return verify_path($value, $noerr);
     } elsif ($ct eq 'server') {
-	return undef if $value =~ m/^\s*$/; # no emtpy strings
-	return undef if $value =~ m/\s/; # no white space
-	return $value; # fixme
+	return verify_server($value, $noerr);
     } elsif ($ct eq 'vgname') {
-	return undef if !parse_lvm_name ($value, 1);
-	return $value;
+	return parse_lvm_name ($value, $noerr);
     } elsif ($ct eq 'portal') {
-	return undef if $value !~ m/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(:\d+)?$/;
-	return $value;
-    } elsif ($ct eq 'target') {
-	return undef if $value =~ m/^\s*$/; # no emtpy strings
-	return undef if $value =~ m/\s/; # no white space
-	return $value;
+	return verify_portal($value, $noerr);
+   } elsif ($ct eq 'target') {
+	return verify_server($value, $noerr);
     } elsif ($ct eq 'string') {
 	return $value;
     } elsif ($ct eq 'format') {
 	my $valid_formats = $def->{format}->[0];
 
-	return undef if !$valid_formats->{$value};
+	if (!$valid_formats->{$value}) {
+	    return undef if $noerr;
+	    die "storage does not support format '$value'\n";
+	}
 
 	return $value;
 
@@ -403,24 +507,34 @@
 	my $res = {};
 
 	foreach my $c (PVE::Tools::split_list($value)) {
-	    return undef if !$valid_content->{$c};
+	    if (!$valid_content->{$c}) {
+		return undef if $noerr;
+		die "storage does not support content type '$c'\n";
+	    }
 	    $res->{$c} = 1;
 	} 
 
 	# only local storage may have several content types
 	if ($res->{none} || !($storeid && $storeid eq 'local')) {
-	    return undef if scalar (keys %$res) > 1;
+	    if (scalar (keys %$res) > 1) {
+		return undef if $noerr;
+		die "storage does not support multiple content types\n";
+	    }
 	}
 
 	# no backup to local storage
-	return undef if $storeid && $storeid eq 'local' && $res->{backup};
+	if ($storeid && $storeid eq 'local' && $res->{backup}) {
+		return undef if $noerr;
+		die "storage 'local' does not support backups\n";
+	}
 
 	return $res;	
     } elsif ($ct eq 'volume') {
-	return $value if parse_volume_id ($value, 1);
+	return $value if parse_volume_id ($value, $noerr);
     }
 
-    return undef;
+    return undef if $noerr;
+    die "type check not implemented - internal error\n";
 }
 
 sub parse_config {
@@ -467,12 +581,10 @@
 		    my ($k, $v) = ($1, $3);
 		    if (my $ct = $confvars->{$k}) {
 			$v = 1 if $ct eq 'bool' && !defined($v);
-			if (defined($v) &&
-			    defined (my $res = check_type ($type, $ct, $k, $v, $storeid))) {
-			    $ids->{$storeid}->{$k} = $res;
-			} else {
-			    warn "storage '$storeid' - unable to parse value of '$k'\n";
-			}
+			eval {
+			    $ids->{$storeid}->{$k} = check_type ($type, $ct, $k, $v, $storeid);
+			};
+			warn "storage '$storeid' - unable to parse value of '$k': $@" if $@;
 		    } else {
 			warn "storage '$storeid' - unable to parse value of '$k'\n";
 		    }
@@ -534,6 +646,7 @@
     return $cfg;
 }
 
+# fixme: remove
 sub parse_options {
     my ($storeid, $stype, $param, $create) = @_;
 
@@ -548,8 +661,14 @@
 	my ($opt, $value) = @_;
 
 	my $ct = $confvars->{$opt};
-	if (defined($value) && defined (my $res = check_type ($stype, $ct, $opt, $value, $storeid))) {
-	    $settings->{$opt} = $res;
+	if (defined($value)) {
+	    eval {
+		$settings->{$opt} = check_type ($stype, $ct, $opt, $value, $storeid);
+	    };
+	    if ($@) {
+		$errmsg = "unable to parse value for '$opt': $@";
+		die("!FINISH"); # abort GetOption
+	    }
 	} else {
 	    $errmsg = "unable to parse value for '$opt'";
 	    die("!FINISH"); # abort GetOption
@@ -594,10 +713,11 @@
 	    }
 
 	    # check if we have a value for all required options
-	    die "missing value for required option '$k'\n"
-		if !defined ($settings->{$k});
+	    if (!defined ($settings->{$k})) {
+		raise_param_exc({ $k => "property is missing and it is not optional" });
+	    }
 	}
-    } else {
+     } else {
 	my $fixed_keys = $fixed_config->{$stype};
 	foreach my $k (@$fixed_keys) {
 
@@ -611,6 +731,56 @@
 
 }
 
+sub parse_options_new {
+    my ($storeid, $stype, $param, $create) = @_;
+
+    my $settings = { type => $stype };
+
+    die "unknown storage type '$stype'\n"
+	if !$default_config->{$stype};
+
+    foreach my $opt (keys %$param) {
+	my $value = $param->{$opt};
+
+	my $ct = $confvars->{$opt};
+	if (defined($value)) {
+	    eval {
+		$settings->{$opt} = check_type ($stype, $ct, $opt, $value, $storeid);
+	    };
+	    raise_param_exc({ $opt => $@ }) if $@;
+	} else {
+	    raise_param_exc({ $opt => "got undefined value" });
+	}
+    }
+
+    if ($create) {
+	my $req_keys = $required_config->{$stype};
+	foreach my $k (@$req_keys) {
+
+	    if ($stype eq 'nfs' && !$settings->{path}) {
+		$settings->{path} = "/mnt/pve/$storeid";
+	    }
+
+	    # check if we have a value for all required options
+	    if (!defined ($settings->{$k})) {
+		raise_param_exc({ $k => "property is missing and it is not optional" });
+	    }
+	}
+    } else {
+	my $fixed_keys = $fixed_config->{$stype};
+	foreach my $k (@$fixed_keys) {
+
+	    # only allow to change non-fixed values
+	    
+	    if (defined ($settings->{$k})) {
+		raise_param_exc({$k => "can't change value (fixed parameter)"});
+	    }
+	}
+    }
+
+    return $settings;
+}
+
 sub fork_command_pipe {
     my ($cmd) = @_;
     
@@ -791,7 +961,7 @@
     return @sa;
 }
 
-sub __assert_if_modified {
+sub assert_if_modified {
     my ($cfg, $digest) = @_;
 
     if ($digest && ($cfg->{digest} ne $digest)) {
@@ -861,7 +1031,7 @@
 	    }
 	}
 
-	safe_print($filename, $fh, $data);
+	safe_print($filename, $fh, "$data\n");
     }
 }
 
@@ -1039,6 +1209,8 @@
 
 # library implementation
 
+
+PVE::JSONSchema::register_format('pve-storage-id', \&parse_storage_id);
 sub parse_storage_id {
     my ($storeid, $noerr) = @_;
 
@@ -1049,6 +1221,7 @@
     return $storeid;
 }
 
+PVE::JSONSchema::register_format('pve-storage-vgname', \&parse_lvm_name);
 sub parse_lvm_name {
     my ($name, $noerr) = @_;
 
@@ -2341,134 +2514,6 @@
     return undef;
 }
 
-
-sub storage_add {
-    my ($storeid, $type, $param) = @_;
-
-    my $opts = parse_options ($storeid, $type, $param, 1);
-
-    lock_storage_config (
-	sub {
-
-	    my $cfg = read_file('storagecfg');
-
-	    if (my $scfg = storage_config ($cfg, $storeid, 1)) {
-		die "storage ID '$storeid' already defined\n";
-	    }
-
-	    $cfg->{ids}->{$storeid} = $opts;
-
-	    if ($type eq 'lvm' && $opts->{base}) {
-
-		my ($baseid, $volname) = parse_volume_id ($opts->{base});
-
-		my $basecfg = storage_config ($cfg, $baseid, 1);
-		die "base storage ID '$baseid' does not exist\n" if !$basecfg;
-       
-		# we only support iscsi for now
-		if (!($basecfg->{type} eq 'iscsi')) {
-		    die "unsupported base type '$basecfg->{type}'";
-		}
-
-		my $path = path ($cfg, $opts->{base});
-
-		lvm_create_volume_group ($path, $opts->{vgname}, $opts->{shared});
-	    }
-	
-	    activate_storage ($cfg, $storeid) if !$opts->{disable};
-
-	    write_file('storagecfg', $cfg);
-	    
-	}, "create storage failed");
-}
-
-sub storage_set {
-    my ($storeid, $param, $digest) = @_;
-
-    lock_storage_config (
-	sub {
-
-	    my $cfg = read_file('storagecfg');
-
-	    __assert_if_modified ($cfg, $digest);
-
-	    my $scfg = storage_config ($cfg, $storeid);
-
-	    my $opts = parse_options ($storeid, $scfg->{type}, $param);
-
-	    foreach my $k (%$opts) {
-		$scfg->{$k} = $opts->{$k};
-	    }
-
-	    write_file('storagecfg', $cfg);
-
-	}, "update storage failed");
-}
-
-sub storage_remove {
-    my ($storeid, $digest) = @_;
-
-    lock_storage_config (
-	sub {
-
-	    my $cfg = read_file('storagecfg');
-
-	    __assert_if_modified ($cfg, $digest);
-
-	    die "can't remove storage - storage is used as base of another storage\n"
-		if storage_is_used ($cfg, $storeid);
-
-	    deactivate_storage ($cfg, $storeid);
-
-	    delete ($cfg->{ids}->{$storeid});
-
-	    write_file('storagecfg', $cfg);
-
-	}, "delete storage failed");
-}
-
-sub storage_enable {
-    my ($storeid, $digest) = @_;
-
-    lock_storage_config (
-	sub {
-
-	    my $cfg = read_file('storagecfg');
-
-	    __assert_if_modified ($cfg, $digest);
-
-	    my $scfg = storage_config ($cfg, $storeid);
-
-	    delete $scfg->{disable};
-
-	    activate_storage ($cfg, $storeid);	
-
-	    write_file('storagecfg', $cfg);
-
-	}, "enable storage failed");
-}
-
-sub storage_disable {
-    my ($storeid, $digest) = @_;
-
-    lock_storage_config (
-	sub {
-
-	    my $cfg = read_file('storagecfg');
-
-	    __assert_if_modified ($cfg, $digest);
-
-	    my $scfg = storage_config ($cfg, $storeid);
-	    
-	    $scfg->{disable} = 1;
-
-	    deactivate_storage ($cfg, $storeid);	
-
-	    write_file('storagecfg', $cfg);
-
-	}, "disable storage failed");
-}
-
 sub foreach_volid {
     my ($list, $func) = @_;
 

Modified: pve-storage/pve2/changelog.Debian
===================================================================
--- pve-storage/pve2/changelog.Debian	2010-08-19 07:00:48 UTC (rev 5029)
+++ pve-storage/pve2/changelog.Debian	2010-08-19 08:51:35 UTC (rev 5030)
@@ -1,3 +1,9 @@
+libpve-storage-perl (2.0-1) unstable; urgency=low
+
+  * change copyright to AGPL
+
+ -- Proxmox Support Team <support at proxmox.com>  Thu, 19 Aug 2010 10:15:46 +0200
+
 libpve-storage-perl (1.0-10) unstable; urgency=low
 
   * fix used space compute

Modified: pve-storage/pve2/copyright
===================================================================
--- pve-storage/pve2/copyright	2010-08-19 07:00:48 UTC (rev 5029)
+++ pve-storage/pve2/copyright	2010-08-19 08:51:35 UTC (rev 5030)
@@ -1,20 +1,16 @@
-Copyright (C) 2009 Proxmox Server Solutions GmbH
+Copyright (C) 2010 Proxmox Server Solutions GmbH
 
 This software is written by Proxmox Server Solutions GmbH <support at proxmox.com>
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; version 2 dated June, 1991.
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GNU Affero General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
-MA 02110-1301, USA.
-
-The complete text of the GNU General
-Public License can be found in `/usr/share/common-licenses/GPL'.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.

Modified: pve-storage/pve2/pvesm
===================================================================
--- pve-storage/pve2/pvesm	2010-08-19 07:00:48 UTC (rev 5029)
+++ pve-storage/pve2/pvesm	2010-08-19 08:51:35 UTC (rev 5030)
@@ -4,6 +4,7 @@
 use Getopt::Long;
 use PVE::INotify qw(read_file);
 use PVE::Storage;
+use PVE::API2::Storage::Config;
 use Fcntl ':flock';
 use File::Path;
 
@@ -114,43 +115,54 @@
 
 if ($cmd eq 'add') {
 
-    if (scalar (@ARGV) < 2) {
-	die "wrong number of arguments\n";
-    }
+    my $opts = {};
 
-    my $storeid = shift;
-    my $type = shift;
+    $opts->{storage} = shift;
 
-    PVE::Storage::parse_storage_id ($storeid);
+    PVE::API2::Storage::Config->cli_handler('create', \@ARGV, $opts);
 
-    PVE::Storage::storage_add ($storeid, $type, \@ARGV);
-
 } elsif ($cmd eq 'set') {
 
-    if (scalar (@ARGV) < 1) {
-	die "wrong number of arguments\n";
-    }
+    my $opts = {};
 
-    my $storeid = shift;
-  
-    PVE::Storage::parse_storage_id ($storeid);
-    
-    PVE::Storage::storage_set ($storeid, \@ARGV);
+    $opts->{storage} = shift;
 
-    die $@ if $@;
+    PVE::API2::Storage::Config->cli_handler('update', \@ARGV, $opts);
 
 } elsif ($cmd eq 'remove') {
 
     my $opts = {};
 
-    if (scalar (@ARGV) != 1) {
+    $opts->{storage} = shift;
+
+    PVE::API2::Storage::Config->cli_handler('delete', \@ARGV, $opts);
+
+} elsif ($cmd eq 'enable') {
+
+    my $opts = {};
+
+    $opts->{storage} = shift;
+    $opts->{disable} = 0;
+
+    if (scalar (@ARGV) != 0) {
 	die "wrong number of arguments\n";
     }
 
-    my $storeid = shift;
+    PVE::API2::Storage::Config->cli_handler('update', \@ARGV, $opts);
 
-    PVE::Storage::storage_remove ($storeid);
+} elsif ($cmd eq 'disable') {
 
+    my $opts = {};
+
+    $opts->{storage} = shift;
+    $opts->{disable} = 1;
+
+    if (scalar (@ARGV) != 0) {
+	die "wrong number of arguments\n";
+    }
+
+    PVE::API2::Storage::Config->cli_handler('update', \@ARGV, $opts);
+
 } elsif ($cmd eq 'alloc') {
 
     my $opts = {};
@@ -277,30 +289,6 @@
 
     }
 
-} elsif ($cmd eq 'enable') {
-
-    if (scalar (@ARGV) != 1) {
-	die "wrong number of arguments\n";
-    }
-
-    my $storeid = shift;
-
-    PVE::Storage::parse_storage_id ($storeid);
-
-    PVE::Storage::storage_enable ($storeid);
-
-} elsif ($cmd eq 'disable') {
-
-    if (scalar (@ARGV) != 1) {
-	die "wrong number of arguments\n";
-    }
-
-    my $storeid = shift;
-
-    PVE::Storage::parse_storage_id ($storeid);
-
-    PVE::Storage::storage_disable ($storeid);
-
 } elsif ($cmd eq 'path') {
 
     my $opts = {};



More information about the pve-devel mailing list