use Cwd 'abs_path';
use Socket;
-use PVE::Tools qw(run_command file_read_firstline $IPV6RE);
+use PVE::Tools qw(run_command file_read_firstline dir_glob_foreach $IPV6RE);
use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
use PVE::Exception qw(raise_param_exc);
use PVE::JSONSchema;
use PVE::Storage::ZFSPlugin;
use PVE::Storage::DRBDPlugin;
-# load and initialize all plugins
+# Storage API version. Icrement it on changes in storage API interface.
+use constant APIVER => 1;
+
+# load standard plugins
PVE::Storage::DirPlugin->register();
PVE::Storage::LVMPlugin->register();
PVE::Storage::LvmThinPlugin->register();
PVE::Storage::ZFSPoolPlugin->register();
PVE::Storage::ZFSPlugin->register();
PVE::Storage::DRBDPlugin->register();
+
+# load third-party plugins
+if ( -d '/usr/share/perl5/PVE/Storage/Custom' ) {
+ dir_glob_foreach('/usr/share/perl5/PVE/Storage/Custom', '.*\.pm$', sub {
+ my ($file) = @_;
+ my $modname = 'PVE::Storage::Custom::' . $file;
+ $modname =~ s!\.pm$!!;
+ $file = 'PVE/Storage/Custom/' . $file;
+
+ eval {
+ require $file;
+ };
+ if ($@) {
+ warn $@;
+ # Check storage API version and that file is really storage plugin.
+ } elsif ($modname->isa('PVE::Storage::Plugin') && $modname->can('api') && $modname->api() == APIVER) {
+ eval {
+ import $file;
+ $modname->register();
+ };
+ warn $@ if $@;
+ } else {
+ warn "Error loading storage plugin \"$modname\" because of API version mismatch. Please, update it.\n"
+ }
+ });
+}
+
+# initialize all plugins
PVE::Storage::Plugin->init();
my $UDEVADM = '/sbin/udevadm';
sub storage_config {
my ($cfg, $storeid, $noerr) = @_;
- die "no storage id specified\n" if !$storeid;
+ die "no storage ID specified\n" if !$storeid;
my $scfg = $cfg->{ids}->{$storeid};
if ($tcfg->{type} eq 'zfspool') {
- die "$errstr - pool on target has not same name as source!"
+ die "$errstr - pool on target does not have the same name as on source!"
if $tcfg->{pool} ne $scfg->{pool};
my (undef, $volname) = parse_volname($cfg, $volid);
} elsif ($scfg->{type} eq 'lvmthin' || $scfg->{type} eq 'lvm') {
- if ($tcfg->{type} eq 'lvmthin' || $tcfg->{type} eq 'lvm') {
-
- die "$errstr - pool on target has not same name as source!"
- if $tcfg->{type} ne $scfg->{type};
+ if (($scfg->{type} eq $tcfg->{type}) &&
+ ($tcfg->{type} eq 'lvmthin' || $tcfg->{type} eq 'lvm')) {
- my (undef, $volname) = parse_volname($cfg, $volid);
+ my (undef, $volname, $vmid) = parse_volname($cfg, $volid);
my $size = volume_size_info($cfg, $volid, 5);
- my $path = path($cfg, $volid);
-
- $volname =~ m/^vm-(\d+)-/;
- my $vmid = $1;
+ my $src = path($cfg, $volid);
+ my $dst = path($cfg, $target_volid);
run_command(['/usr/bin/ssh', "root\@${target_host}",
'pvesm', 'alloc', $target_storeid, $vmid,
- $volname, $size/1024]);
+ $target_volname, int($size/1024)]);
eval {
- run_command([["dd", "if=$path"],
- ["/usr/bin/ssh", "root\@${target_host}", "-C",
- "dd", 'conv=sparse', "of=$path"]]);
+ if ($tcfg->{type} eq 'lvmthin') {
+ run_command([["dd", "if=$src"],["/usr/bin/ssh", "root\@${target_host}",
+ "dd", 'conv=sparse', "of=$dst"]]);
+ } else {
+ run_command([["dd", "if=$src"],["/usr/bin/ssh", "root\@${target_host}",
+ "dd", "of=$dst"]]);
+ }
};
if (my $err = $@) {
run_command(['/usr/bin/ssh', "root\@${target_host}",
- 'pvesm', 'free', $volid]);
- } else {
- vdisk_free($cfg, $volid);
+ 'pvesm', 'free', $target_volid]);
+ die $err;
}
} else {
- die "$errstr - target type $tcfg->{type} is not valid\n";
+ die "$errstr - migrate from source type '$scfg->{type}' to '$tcfg->{type}' not implemented\n";
}
} else {
die "$errstr - source type '$scfg->{type}' not implemented\n";
sub vdisk_alloc {
my ($cfg, $storeid, $vmid, $fmt, $name, $size) = @_;
- die "no storage id specified\n" if !$storeid;
+ die "no storage ID specified\n" if !$storeid;
PVE::JSONSchema::parse_storage_id($storeid);
if ($basename && defined($basevmid) && $basevmid == $vmid && $basename eq $name) {
die "base volume '$volname' is still in use " .
- "(use by '$tmpvolname')\n";
+ "(used by '$tmpvolname')\n";
}
}
}
}
}
- die "volume deativation failed: " . join(' ', @errlist)
+ die "volume deactivation failed: " . join(' ', @errlist)
if scalar(@errlist);
}