[pve-devel] [PATCH 11/13] add clone_disks sub

Alexandre Derumier aderumier at odiso.com
Tue Jan 29 17:13:51 CET 2013


Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
 PVE/API2/Qemu.pm |  100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 924af26..ed6da19 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -133,6 +133,106 @@ my $create_disks = sub {
     return $vollist;
 };
 
+my $clone_disks = sub {
+    my ($rpcenv, $authuser, $conf, $storecfg, $vmid, $pool, $settings, $snap, $mode, $clonefrom, $running, $onlysettings) = @_;
+
+    my $vollist = [];
+    my $voliddst = undef;
+    my $currentdrive = undef;
+    my $res = {};
+
+    eval {
+        local $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = sub {die "interrupted by signal\n";};
+
+	PVE::QemuServer::foreach_drive($conf, sub {
+	    my ($ds, $disk) = @_;
+
+	    $currentdrive = $ds;
+
+	    return if ($onlysettings && !$settings->{$ds});
+
+	    my $volid = $disk->{file};
+	    if (PVE::QemuServer::drive_is_cdrom($disk)) {
+		$res->{$ds} = PVE::QemuServer::print_drive($vmid, $disk);
+	    } else{
+
+		if($mode eq 'clone'){
+		    print "clone volume $volid\n";
+		    #if we clone from a template and we need to use the snapshot
+		    if(PVE::Storage::volume_has_feature($storecfg, 'clone', $volid, 1, $running) && PVE::QemuServer::is_template($conf)){
+			$snap = "base";
+		    }
+		    $voliddst = PVE::Storage::volume_clone($storecfg, $volid, $snap, $vmid);
+	            push @$vollist, $voliddst;
+
+		}elsif($mode eq 'copy'){
+
+		    my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
+		    die "no storage ID specified (and no default storage)\n" if !$storeid;
+
+		    my $fmt = undef;
+		    if ($volname =~ m/\.(raw|qcow2|vmdk)$/){
+			$fmt = $1;
+		    }
+
+		    #target storage is different ? (ex: -virtio0:storeid:fmt)
+		    if($settings->{$ds} && $settings->{$ds} =~ m/^(\S+):(raw|qcow2|vmdk)?$/){
+			($storeid, $fmt) = ($1, $2);
+		    }
+
+		    $rpcenv->check($authuser, "/storage/$storeid", ['Datastore.AllocateSpace']);
+		    print "activate volume source $volid\n";
+		    PVE::Storage::activate_volumes($storecfg, [ $volid ]);
+
+		    my ($size) = PVE::Storage::volume_size_info($storecfg, $volid, 1);
+		    print "create target volume\n";
+		    $voliddst = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $fmt, undef, ($size/1024));
+
+		    push @$vollist, $voliddst;
+
+		    print "activate volume $voliddst\n";
+		    PVE::Storage::activate_volumes($storecfg, [ $voliddst ]);
+
+		    print "copy $volid to $voliddst\n";
+		    if(!$running || $snap){
+			PVE::QemuServer::qemu_img_convert($volid, $voliddst, $snap);
+		    }else{
+			PVE::QemuServer::qemu_drive_mirror($clonefrom, $ds, $voliddst, $vmid);
+		    }
+		}
+
+		$disk->{file} = $voliddst;
+		$disk->{size} = PVE::Storage::volume_size_info($storecfg, $voliddst, 1);
+
+		delete $disk->{format}; # no longer needed
+		$res->{$ds} = PVE::QemuServer::print_drive($vmid, $disk);
+	    }
+	});
+    };
+    # free allocated images on error
+    if (my $err = $@) {
+	syslog('err', "VM $vmid clone disks failed");
+
+	eval {
+	    PVE::QemuServer::vm_mon_cmd($vmid, "block-job-cancel", device => "drive-$currentdrive") if ($mode eq 'copy' && $running);
+	};
+
+	sleep 1; #some storage like rbd need to wait before release volume
+	foreach my $volid (@$vollist) {
+	    eval { PVE::Storage::vdisk_free($storecfg, $volid); };
+	    warn $@ if $@;
+	}
+	die $err;
+    }
+
+    # modify vm config if everything went well
+    foreach my $ds (keys %$res) {
+	$conf->{$ds} = $res->{$ds};
+    }
+
+    return $vollist;
+};
+
 my $check_vm_modify_config_perm = sub {
     my ($rpcenv, $authuser, $vmid, $pool, $key_list) = @_;
 
-- 
1.7.10.4




More information about the pve-devel mailing list