From c669f42d4e53933947628ec93e9dcfbd44e38e24 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Fri, 18 Sep 2015 08:21:17 +0200 Subject: [PATCH] convert pvesm into a PVE::CLI class --- Makefile | 21 +++- PVE/CLI/Makefile | 9 ++ PVE/CLI/pvesm.pm | 271 ++++++++++++++++++++++++++++++++++++++++++++ PVE/Makefile | 3 +- pvesm | 285 +---------------------------------------------- 5 files changed, 299 insertions(+), 290 deletions(-) create mode 100644 PVE/CLI/Makefile create mode 100755 PVE/CLI/pvesm.pm diff --git a/Makefile b/Makefile index 26911b5..e5b2a8e 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,8 @@ MANDIR=${PREFIX}/share/man DOCDIR=${PREFIX}/share/doc/${PACKAGE} PODDIR=${DOCDIR}/pod MAN1DIR=${MANDIR}/man1/ +BASHCOMPLDIR=${PREFIX}/share/bash-completion/completions/ + export PERLDIR=${PREFIX}/share/perl5 #ARCH:=$(shell dpkg-architecture -qDEB_BUILD_ARCH) @@ -29,13 +31,19 @@ dinstall: deb %.1.gz: %.1.pod rm -f $@ - cat $<|pod2man -n $* -s 1 -r ${VERSION} -c "Proxmox Documentation"|gzip -c9 >$@ + cat $<|pod2man -n $* -s 1 -r ${VERSION} -c "Proxmox Documentation"|gzip -c9 >$@.tmp + mv $@.tmp $@ + +pvesm.1.pod: PVE/CLI/pvesm.pm PVE/Storage.pm + perl -I. -T -e "use PVE::CLI::pvesm; PVE::CLI::pvesm->generate_pod_manpage();" >$@.tmp + mv $@.tmp $@ -pvesm.1.pod: pvesm PVE/Storage.pm - perl -I. ./pvesm printmanpod >$@ +pvesm.bash-completion: + perl -I. -T -e "use PVE::CLI::pvesm; PVE::CLI::pvesm->generate_bash_completions();" >$@.tmp + mv $@.tmp $@ .PHONY: install -install: pvesm.1.pod pvesm.1.gz +install: pvesm.1.pod pvesm.1.gz pvesm.bash-completion install -d ${DESTDIR}${SBINDIR} install -m 0755 pvesm ${DESTDIR}${SBINDIR} make -C PVE install @@ -43,13 +51,14 @@ install: pvesm.1.pod pvesm.1.gz install -d ${DESTDIR}${PODDIR} install -m 0644 pvesm.1.gz ${DESTDIR}/usr/share/man/man1/ install -m 0644 pvesm.1.pod ${DESTDIR}/${PODDIR} + install -m 0644 -D pvesm.bash-completion ${DESTDIR}${BASHCOMPLDIR}/pvesm .PHONY: deb ${DEB} deb ${DEB}: rm -rf debian mkdir debian make DESTDIR=${CURDIR}/debian install - perl -I. ./pvesm verifyapi + perl -I. -T -e "use PVE::CLI::pvesm; PVE::CLI::pvesm->verify_api();" install -d -m 0755 debian/DEBIAN sed -e s/@@VERSION@@/${VERSION}/ -e s/@@PKGRELEASE@@/${PKGREL}/ -e s/@@ARCH@@/${ARCH}/ debian/DEBIAN/control install -D -m 0644 copyright debian/${DOCDIR}/copyright @@ -64,7 +73,7 @@ deb ${DEB}: .PHONY: clean clean: - rm -rf debian *.deb ${PACKAGE}-*.tar.gz dist *.1.pod *.1.gz + rm -rf debian *.deb ${PACKAGE}-*.tar.gz dist *.1.pod *.1.gz *.tmp pvesm.bash-completion find . -name '*~' -exec rm {} ';' .PHONY: distclean diff --git a/PVE/CLI/Makefile b/PVE/CLI/Makefile new file mode 100644 index 0000000..6c6e258 --- /dev/null +++ b/PVE/CLI/Makefile @@ -0,0 +1,9 @@ +SOURCES=pvesm.pm + +.PHONY: install +install: ${SOURCES} + install -d -m 0755 ${DESTDIR}${PERLDIR}/PVE/CLI + for i in ${SOURCES}; do install -D -m 0644 $$i ${DESTDIR}${PERLDIR}/PVE/CLI/$$i; done + + +clean: diff --git a/PVE/CLI/pvesm.pm b/PVE/CLI/pvesm.pm new file mode 100755 index 0000000..bb122ce --- /dev/null +++ b/PVE/CLI/pvesm.pm @@ -0,0 +1,271 @@ +package PVE::CLI::pvesm; + +use strict; +use warnings; + +use Fcntl ':flock'; +use File::Path; + +use PVE::SafeSyslog; +use PVE::Cluster; +use PVE::INotify; +use PVE::RPCEnvironment; +use PVE::Storage; +use PVE::API2::Storage::Config; +use PVE::API2::Storage::Content; +use PVE::API2::Storage::Status; +use PVE::API2::Storage::Scan; +use PVE::JSONSchema qw(get_standard_option); + +use PVE::CLIHandler; + +use base qw(PVE::CLIHandler); + +my $nodename = PVE::INotify::nodename(); + +__PACKAGE__->register_method ({ + name => 'path', + path => 'path', + method => 'GET', + description => "Get filesystem path for specified volume", + parameters => { + additionalProperties => 0, + properties => { + volume => { + description => "Volume identifier", + type => 'string', format => 'pve-volume-id', + }, + }, + }, + returns => { type => 'null' }, + + code => sub { + my ($param) = @_; + + my $cfg = PVE::Storage::config(); + + my $path = PVE::Storage::path ($cfg, $param->{volume}); + + print "$path\n"; + + return undef; + + }}); + +my $print_content = sub { + my ($list) = @_; + + my $maxlenname = 0; + foreach my $info (@$list) { + + my $volid = $info->{volid}; + my $sidlen = length ($volid); + $maxlenname = $sidlen if $sidlen > $maxlenname; + } + + foreach my $info (@$list) { + next if !$info->{vmid}; + my $volid = $info->{volid}; + + printf "%-${maxlenname}s %5s %10d %d\n", $volid, + $info->{format}, $info->{size}, $info->{vmid}; + } + + foreach my $info (sort { $a->{format} cmp $b->{format} } @$list) { + next if $info->{vmid}; + my $volid = $info->{volid}; + + printf "%-${maxlenname}s %5s %10d\n", $volid, + $info->{format}, $info->{size}; + } +}; + +my $print_status = sub { + my $res = shift; + + my $maxlen = 0; + foreach my $res (@$res) { + my $storeid = $res->{storage}; + $maxlen = length ($storeid) if length ($storeid) > $maxlen; + } + $maxlen+=1; + + foreach my $res (sort { $a->{storage} cmp $b->{storage} } @$res) { + my $storeid = $res->{storage}; + + my $sum = $res->{used} + $res->{avail}; + my $per = $sum ? (0.5 + ($res->{used}*100)/$sum) : 100; + + printf "%-${maxlen}s %5s %1d %15d %15d %15d %.2f%%\n", $storeid, + $res->{type}, $res->{active}, + $res->{total}/1024, $res->{used}/1024, $res->{avail}/1024, $per; + } +}; + +our $cmddef = { + add => [ "PVE::API2::Storage::Config", 'create', ['type', 'storage'] ], + set => [ "PVE::API2::Storage::Config", 'update', ['storage'] ], + remove => [ "PVE::API2::Storage::Config", 'delete', ['storage'] ], + status => [ "PVE::API2::Storage::Status", 'index', [], + { node => $nodename }, $print_status ], + list => [ "PVE::API2::Storage::Content", 'index', ['storage'], + { node => $nodename }, $print_content ], + alloc => [ "PVE::API2::Storage::Content", 'create', ['storage', 'vmid', 'filename', 'size'], + { node => $nodename }, sub { + my $volid = shift; + print "sucessfuly created '$volid'\n"; + }], + free => [ "PVE::API2::Storage::Content", 'delete', ['volume'], + { node => $nodename } ], + nfsscan => [ "PVE::API2::Storage::Scan", 'nfsscan', ['server'], + { node => $nodename }, sub { + my $res = shift; + + my $maxlen = 0; + foreach my $rec (@$res) { + my $len = length ($rec->{path}); + $maxlen = $len if $len > $maxlen; + } + foreach my $rec (@$res) { + printf "%-${maxlen}s %s\n", $rec->{path}, $rec->{options}; + } + }], + glusterfsscan => [ "PVE::API2::Storage::Scan", 'glusterfsscan', ['server'], + { node => $nodename }, sub { + my $res = shift; + + foreach my $rec (@$res) { + printf "%s\n", $rec->{volname}; + } + }], + iscsiscan => [ "PVE::API2::Storage::Scan", 'iscsiscan', ['server'], + { node => $nodename }, sub { + my $res = shift; + + my $maxlen = 0; + foreach my $rec (@$res) { + my $len = length ($rec->{target}); + $maxlen = $len if $len > $maxlen; + } + foreach my $rec (@$res) { + printf "%-${maxlen}s %s\n", $rec->{target}, $rec->{portal}; + } + }], + lvmscan => [ "PVE::API2::Storage::Scan", 'lvmscan', [], + { node => $nodename }, sub { + my $res = shift; + foreach my $rec (@$res) { + printf "$rec->{vg}\n"; + } + }], + zfsscan => [ "PVE::API2::Storage::Scan", 'zfsscan', [], + { node => $nodename }, sub { + my $res = shift; + + foreach my $rec (@$res) { + printf "$rec->{pool}\n"; + } + }], + path => [ __PACKAGE__, 'path', ['volume']], +}; + +1; + +__END__ + +=head1 NAME + +pvesm - PVE Storage Manager + +=head1 SYNOPSIS + +=include synopsis + +=head1 DESCRIPTION + +=head2 Storage pools + +Each storage pool is uniquely identified by its . + +=head3 Storage content + +A storage can support several content types, for example virtual disk +images, cdrom iso images, openvz templates or openvz root directories +(C, C, C, C). + +=head2 Volumes + +A volume is identified by the , followed by a storage type +dependent volume name, separated by colon. A valid looks like: + + local:230/example-image.raw + + local:iso/debian-501-amd64-netinst.iso + + local:vztmpl/debian-5.0-joomla_1.5.9-1_i386.tar.gz + + iscsi-storage:0.0.2.scsi-14f504e46494c4500494b5042546d2d646744372d31616d61 + +To get the filesystem path for a use: + + pvesm path + + +=head1 EXAMPLES + + # scan iscsi host for available targets + pvesm iscsiscan -portal + + # scan nfs server for available exports + pvesm nfsscan + + # add storage pools + pvesm add + pvesm add dir --path + pvesm add nfs --path --server --export + pvesm add lvm --vgname + pvesm add iscsi --portal --target + + # disable storage pools + pvesm set --disable 1 + + # enable storage pools + pvesm set --disable 0 + + # change/set storage options + pvesm set + pvesm set --shared 1 + pvesm set local --format qcow2 + pvesm set --content iso + + # remove storage pools - does not delete any data + pvesm remove + + # alloc volumes + pvesm alloc [--format ] + + # alloc 4G volume in local storage - use auto generated name + pvesm alloc local '' 4G + + # free volumes (warning: destroy/deletes all volume data) + pvesm free + + # list storage status + pvesm status + + # list storage contents + pvesm list [--vmid ] + + # list volumes allocated by VMID + pvesm list --vmid + + # list iso images + pvesm list --iso + + # list openvz templates + pvesm list --vztmpl + + # show filesystem path for a volume + pvesm path + +=include pve_copyright diff --git a/PVE/Makefile b/PVE/Makefile index 83cb51e..655cad8 100644 --- a/PVE/Makefile +++ b/PVE/Makefile @@ -4,4 +4,5 @@ install: install -D -m 0644 Storage.pm ${DESTDIR}${PERLDIR}/PVE/Storage.pm make -C Storage install - make -C API2 install \ No newline at end of file + make -C API2 install + make -C CLI install diff --git a/pvesm b/pvesm index 6c16568..c5c2b19 100755 --- a/pvesm +++ b/pvesm @@ -2,288 +2,7 @@ use strict; use warnings; -use Getopt::Long; -use Fcntl ':flock'; -use File::Path; -use PVE::SafeSyslog; -use PVE::Cluster; -use PVE::INotify; -use PVE::RPCEnvironment; -use PVE::Storage; -use PVE::API2::Storage::Config; -use PVE::API2::Storage::Content; -use PVE::API2::Storage::Status; -use PVE::API2::Storage::Scan; -use PVE::JSONSchema qw(get_standard_option); +use PVE::CLI::pvesm; -use PVE::CLIHandler; - -use base qw(PVE::CLIHandler); - -$ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin'; - -initlog ('pvesm'); - -die "please run as root\n" if $> != 0; - -PVE::INotify::inotify_init(); - -my $rpcenv = PVE::RPCEnvironment->init('cli'); - -$rpcenv->init_request(); -$rpcenv->set_language($ENV{LANG}); -$rpcenv->set_user('root@pam'); - -__PACKAGE__->register_method ({ - name => 'path', - path => 'path', - method => 'GET', - description => "Get filesystem path for specified volume", - parameters => { - additionalProperties => 0, - properties => { - volume => { - description => "Volume identifier", - type => 'string', format => 'pve-volume-id', - }, - }, - }, - returns => { type => 'null' }, - - code => sub { - my ($param) = @_; - - my $cfg = PVE::Storage::config(); - - my $path = PVE::Storage::path ($cfg, $param->{volume}); - - print "$path\n"; - - return undef; - - }}); - -my $print_content = sub { - my ($list) = @_; - - my $maxlenname = 0; - foreach my $info (@$list) { - - my $volid = $info->{volid}; - my $sidlen = length ($volid); - $maxlenname = $sidlen if $sidlen > $maxlenname; - } - - foreach my $info (@$list) { - next if !$info->{vmid}; - my $volid = $info->{volid}; - - printf "%-${maxlenname}s %5s %10d %d\n", $volid, - $info->{format}, $info->{size}, $info->{vmid}; - } - - foreach my $info (sort { $a->{format} cmp $b->{format} } @$list) { - next if $info->{vmid}; - my $volid = $info->{volid}; - - printf "%-${maxlenname}s %5s %10d\n", $volid, - $info->{format}, $info->{size}; - } -}; - -my $print_status = sub { - my $res = shift; - - my $maxlen = 0; - foreach my $res (@$res) { - my $storeid = $res->{storage}; - $maxlen = length ($storeid) if length ($storeid) > $maxlen; - } - $maxlen+=1; - - foreach my $res (sort { $a->{storage} cmp $b->{storage} } @$res) { - my $storeid = $res->{storage}; - - my $sum = $res->{used} + $res->{avail}; - my $per = $sum ? (0.5 + ($res->{used}*100)/$sum) : 100; - - printf "%-${maxlen}s %5s %1d %15d %15d %15d %.2f%%\n", $storeid, - $res->{type}, $res->{active}, - $res->{total}/1024, $res->{used}/1024, $res->{avail}/1024, $per; - } -}; - -my $nodename = PVE::INotify::nodename(); - -my $cmddef = { - add => [ "PVE::API2::Storage::Config", 'create', ['type', 'storage'] ], - set => [ "PVE::API2::Storage::Config", 'update', ['storage'] ], - remove => [ "PVE::API2::Storage::Config", 'delete', ['storage'] ], - status => [ "PVE::API2::Storage::Status", 'index', [], - { node => $nodename }, $print_status ], - list => [ "PVE::API2::Storage::Content", 'index', ['storage'], - { node => $nodename }, $print_content ], - alloc => [ "PVE::API2::Storage::Content", 'create', ['storage', 'vmid', 'filename', 'size'], - { node => $nodename }, sub { - my $volid = shift; - print "sucessfuly created '$volid'\n"; - }], - free => [ "PVE::API2::Storage::Content", 'delete', ['volume'], - { node => $nodename } ], - nfsscan => [ "PVE::API2::Storage::Scan", 'nfsscan', ['server'], - { node => $nodename }, sub { - my $res = shift; - - my $maxlen = 0; - foreach my $rec (@$res) { - my $len = length ($rec->{path}); - $maxlen = $len if $len > $maxlen; - } - foreach my $rec (@$res) { - printf "%-${maxlen}s %s\n", $rec->{path}, $rec->{options}; - } - }], - glusterfsscan => [ "PVE::API2::Storage::Scan", 'glusterfsscan', ['server'], - { node => $nodename }, sub { - my $res = shift; - - foreach my $rec (@$res) { - printf "%s\n", $rec->{volname}; - } - }], - iscsiscan => [ "PVE::API2::Storage::Scan", 'iscsiscan', ['server'], - { node => $nodename }, sub { - my $res = shift; - - my $maxlen = 0; - foreach my $rec (@$res) { - my $len = length ($rec->{target}); - $maxlen = $len if $len > $maxlen; - } - foreach my $rec (@$res) { - printf "%-${maxlen}s %s\n", $rec->{target}, $rec->{portal}; - } - }], - lvmscan => [ "PVE::API2::Storage::Scan", 'lvmscan', [], - { node => $nodename }, sub { - my $res = shift; - foreach my $rec (@$res) { - printf "$rec->{vg}\n"; - } - }], - zfsscan => [ "PVE::API2::Storage::Scan", 'zfsscan', [], - { node => $nodename }, sub { - my $res = shift; - - foreach my $rec (@$res) { - printf "$rec->{pool}\n"; - } - }], - path => [ __PACKAGE__, 'path', ['volume']], -}; - -my $cmd = shift; - -PVE::CLIHandler::handle_cmd($cmddef, "pvesm", $cmd, \@ARGV, undef, $0); - -exit 0; - -__END__ - -=head1 NAME - -pvesm - PVE Storage Manager - -=head1 SYNOPSIS - -=include synopsis - -=head1 DESCRIPTION - -=head2 Storage pools - -Each storage pool is uniquely identified by its . - -=head3 Storage content - -A storage can support several content types, for example virtual disk -images, cdrom iso images, openvz templates or openvz root directories -(C, C, C, C). - -=head2 Volumes - -A volume is identified by the , followed by a storage type -dependent volume name, separated by colon. A valid looks like: - - local:230/example-image.raw - - local:iso/debian-501-amd64-netinst.iso - - local:vztmpl/debian-5.0-joomla_1.5.9-1_i386.tar.gz - - iscsi-storage:0.0.2.scsi-14f504e46494c4500494b5042546d2d646744372d31616d61 - -To get the filesystem path for a use: - - pvesm path - - -=head1 EXAMPLES - - # scan iscsi host for available targets - pvesm iscsiscan -portal - - # scan nfs server for available exports - pvesm nfsscan - - # add storage pools - pvesm add - pvesm add dir --path - pvesm add nfs --path --server --export - pvesm add lvm --vgname - pvesm add iscsi --portal --target - - # disable storage pools - pvesm set --disable 1 - - # enable storage pools - pvesm set --disable 0 - - # change/set storage options - pvesm set - pvesm set --shared 1 - pvesm set local --format qcow2 - pvesm set --content iso - - # remove storage pools - does not delete any data - pvesm remove - - # alloc volumes - pvesm alloc [--format ] - - # alloc 4G volume in local storage - use auto generated name - pvesm alloc local '' 4G - - # free volumes (warning: destroy/deletes all volume data) - pvesm free - - # list storage status - pvesm status - - # list storage contents - pvesm list [--vmid ] - - # list volumes allocated by VMID - pvesm list --vmid - - # list iso images - pvesm list --iso - - # list openvz templates - pvesm list --vztmpl - - # show filesystem path for a volume - pvesm path - -=include pve_copyright +PVE::CLI::pvesm->run_cli(); -- 2.39.2