#!/usr/bin/perl -w use strict; 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::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', ['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}; } }], 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"; } }], 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 scan iscsi # scan nfs server for available exports pvesm scan nfs # 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