[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