use base qw(PVE::CLIHandler);
+my $KNOWN_EXPORT_FORMATS = ['zfs'];
+
my $nodename = PVE::INotify::nodename();
+sub setup_environment {
+ PVE::RPCEnvironment->setup_default_cli_env();
+}
+
__PACKAGE__->register_method ({
name => 'path',
path => 'path',
volume => {
description => "Volume identifier",
type => 'string', format => 'pve-volume-id',
+ completion => \&PVE::Storage::complete_volume,
},
},
},
}});
+__PACKAGE__->register_method ({
+ name => 'extractconfig',
+ path => 'extractconfig',
+ method => 'GET',
+ description => "Extract configuration from vzdump backup archive.",
+ permissions => {
+ description => "The user needs 'VM.Backup' permissions on the backed up guest ID, and 'Datastore.AllocateSpace' on the backup storage.",
+ user => 'all',
+ },
+ protected => 1,
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ volume => {
+ description => "Volume identifier",
+ type => 'string',
+ completion => \&PVE::Storage::complete_volume,
+ },
+ },
+ },
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+ my $volume = $param->{volume};
+
+ my $rpcenv = PVE::RPCEnvironment::get();
+ my $authuser = $rpcenv->get_user();
+
+ my $storage_cfg = PVE::Storage::config();
+ PVE::Storage::check_volume_access($rpcenv, $authuser, $storage_cfg, undef, $volume);
+
+ my $config_raw = PVE::Storage::extract_vzdump_config($storage_cfg, $volume);
+
+ print "$config_raw\n";
+ return;
+ }});
+
my $print_content = sub {
my ($list) = @_;
}
};
+__PACKAGE__->register_method ({
+ name => 'export',
+ path => 'export',
+ method => 'GET',
+ description => "Export a volume.",
+ protected => 1,
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ volume => {
+ description => "Volume identifier",
+ type => 'string',
+ completion => \&PVE::Storage::complete_volume,
+ },
+ format => {
+ description => "Export stream format",
+ type => 'string',
+ enum => $KNOWN_EXPORT_FORMATS,
+ },
+ filename => {
+ description => "Destination file name",
+ type => 'string',
+ },
+ base => {
+ description => "Snapshot to start an incremental stream from",
+ type => 'string',
+ pattern => qr/[a-z0-9_\-]{1,40}/,
+ maxLength => 40,
+ optional => 1,
+ },
+ snapshot => {
+ description => "Snapshot to export",
+ type => 'string',
+ pattern => qr/[a-z0-9_\-]{1,40}/,
+ maxLength => 40,
+ optional => 1,
+ },
+ 'with-snapshots' => {
+ description =>
+ "Whether to include intermediate snapshots in the stream",
+ type => 'boolean',
+ optional => 1,
+ default => 0,
+ },
+ },
+ },
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $filename = $param->{filename};
+
+ my $outfh;
+ if ($filename eq '-') {
+ $outfh = \*STDOUT;
+ } else {
+ open($outfh, '>', $filename)
+ or die "open($filename): $!\n";
+ }
+
+ eval {
+ my $cfg = PVE::Storage::config();
+ PVE::Storage::volume_export($cfg, $outfh, $param->{volume}, $param->{format},
+ $param->{snapshot}, $param->{base}, $param->{'with-snapshots'});
+ };
+ my $err = $@;
+ if ($filename ne '-') {
+ close($outfh);
+ unlink($filename) if $err;
+ }
+ die $err if $err;
+ return;
+ }
+});
+
+__PACKAGE__->register_method ({
+ name => 'import',
+ path => 'import',
+ method => 'PUT',
+ description => "Import a volume.",
+ protected => 1,
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ volume => {
+ description => "Volume identifier",
+ type => 'string',
+ completion => \&PVE::Storage::complete_volume,
+ },
+ format => {
+ description => "Import stream format",
+ type => 'string',
+ enum => $KNOWN_EXPORT_FORMATS,
+ },
+ filename => {
+ description => "Source file name",
+ type => 'string',
+ },
+ base => {
+ description => "Base snapshot of an incremental stream",
+ type => 'string',
+ pattern => qr/[a-z0-9_\-]{1,40}/,
+ maxLength => 40,
+ optional => 1,
+ },
+ 'with-snapshots' => {
+ description =>
+ "Whether the stream includes intermediate snapshots",
+ type => 'boolean',
+ optional => 1,
+ default => 0,
+ },
+ 'delete-snapshot' => {
+ description => "A snapshot to delete on success",
+ type => 'string',
+ pattern => qr/[a-z0-9_\-]{1,80}/,
+ maxLength => 80,
+ optional => 1,
+ },
+ },
+ },
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $filename = $param->{filename};
+
+ my $infh;
+ if ($filename eq '-') {
+ $infh = \*STDIN;
+ } else {
+ open($infh, '<', $filename)
+ or die "open($filename): $!\n";
+ }
+
+ my $cfg = PVE::Storage::config();
+ my $volume = $param->{volume};
+ my $delete = $param->{'delete-snapshot'};
+ PVE::Storage::volume_import($cfg, $infh, $volume, $param->{format},
+ $param->{base}, $param->{'with-snapshots'});
+ PVE::Storage::volume_snapshot_delete($cfg, $volume, $delete)
+ if defined($delete);
+ return;
+ }
+});
+
our $cmddef = {
add => [ "PVE::API2::Storage::Config", 'create', ['type', 'storage'] ],
set => [ "PVE::API2::Storage::Config", 'update', ['storage'] ],
alloc => [ "PVE::API2::Storage::Content", 'create', ['storage', 'vmid', 'filename', 'size'],
{ node => $nodename }, sub {
my $volid = shift;
- print "sucessfuly created '$volid'\n";
+ print "successfully created '$volid'\n";
}],
free => [ "PVE::API2::Storage::Content", 'delete', ['volume'],
{ node => $nodename } ],
printf "$rec->{vg}\n";
}
}],
+ lvmthinscan => [ "PVE::API2::Storage::Scan", 'lvmthinscan', ['vg'],
+ { node => $nodename }, sub {
+ my $res = shift;
+ foreach my $rec (@$res) {
+ printf "$rec->{lv}\n";
+ }
+ }],
zfsscan => [ "PVE::API2::Storage::Scan", 'zfsscan', [],
{ node => $nodename }, sub {
my $res = shift;
}
}],
path => [ __PACKAGE__, 'path', ['volume']],
+ extractconfig => [__PACKAGE__, 'extractconfig', ['volume']],
+ export => [ __PACKAGE__, 'export', ['volume', 'format', 'filename']],
+ import => [ __PACKAGE__, 'import', ['volume', 'format', 'filename']],
};
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 <STORAGE_ID>.
-
-=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<images>, C<iso>, C<vztmpl>, C<rootdir>).
-
-=head2 Volumes
-
-A volume is identified by the <STORAGE_ID>, followed by a storage type
-dependent volume name, separated by colon. A valid <VOLUME_ID> 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 <VOLUME_ID> use:
-
- pvesm path <VOLUME_ID>
-
-
-=head1 EXAMPLES
-
- # scan iscsi host for available targets
- pvesm iscsiscan -portal <HOST[:PORT]>
-
- # scan nfs server for available exports
- pvesm nfsscan <HOST>
-
- # add storage pools
- pvesm add <TYPE> <STORAGE_ID> <OPTIONS>
- pvesm add dir <STORAGE_ID> --path <PATH>
- pvesm add nfs <STORAGE_ID> --path <PATH> --server <SERVER> --export <EXPORT>
- pvesm add lvm <STORAGE_ID> --vgname <VGNAME>
- pvesm add iscsi <STORAGE_ID> --portal <HOST[:PORT]> --target <TARGET>
-
- # disable storage pools
- pvesm set <STORAGE_ID> --disable 1
-
- # enable storage pools
- pvesm set <STORAGE_ID> --disable 0
-
- # change/set storage options
- pvesm set <STORAGE_ID> <OPTIONS>
- pvesm set <STORAGE_ID> --shared 1
- pvesm set local --format qcow2
- pvesm set <STORAGE_ID> --content iso
-
- # remove storage pools - does not delete any data
- pvesm remove <STORAGE_ID>
-
- # alloc volumes
- pvesm alloc <STORAGE_ID> <VMID> <name> <size> [--format <raw|qcow2>]
-
- # alloc 4G volume in local storage - use auto generated name
- pvesm alloc local <VMID> '' 4G
-
- # free volumes (warning: destroy/deletes all volume data)
- pvesm free <VOLUME_ID>
-
- # list storage status
- pvesm status
-
- # list storage contents
- pvesm list <STORAGE_ID> [--vmid <VMID>]
-
- # list volumes allocated by VMID
- pvesm list <STORAGE_ID> --vmid <VMID>
-
- # list iso images
- pvesm list <STORAGE_ID> --iso
-
- # list openvz templates
- pvesm list <STORAGE_ID> --vztmpl
-
- # show filesystem path for a volume
- pvesm path <VOLUME_ID>
-
-=include pve_copyright