]> git.proxmox.com Git - qemu-server.git/commitdiff
copy_vm: new option to move final VM to other node (option target)
authorDietmar Maurer <dietmar@proxmox.com>
Tue, 30 Apr 2013 09:44:39 +0000 (11:44 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Tue, 30 Apr 2013 09:44:39 +0000 (11:44 +0200)
This only works if the VM is on shared storage.

PVE/API2/Qemu.pm

index 713ee549a59f806eaea6c0f7fc8b6f2f566ee7cb..d33af929ffb6ba9e63ad76977198d8408bdee9d3 100644 (file)
@@ -62,6 +62,8 @@ my $check_storage_access = sub {
 my $check_storage_access_copy = sub {
    my ($rpcenv, $authuser, $storecfg, $conf, $storage) = @_;
 
+   my $sharedvm = 1;
+
    PVE::QemuServer::foreach_drive($conf, sub {
        my ($ds, $drive) = @_;
 
@@ -76,14 +78,22 @@ my $check_storage_access_copy = sub {
                $rpcenv->check($authuser, "/", ['Sys.Console']);
            } else {
                # we simply allow access 
+               my ($sid, $volname) = PVE::Storage::parse_volume_id($volid);
+               my $scfg = PVE::Storage::storage_config($storecfg, $sid);
+               $sharedvm = 0 if !$scfg->{shared};
+
            }
        } else {
-           my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
-           die "unable to copy arbitrary files\n" if !$sid;
+           my ($sid, $volname) = PVE::Storage::parse_volume_id($volid);
+           my $scfg = PVE::Storage::storage_config($storecfg, $sid);
+           $sharedvm = 0 if !$scfg->{shared};
+
            $sid = $storage if $storage;
            $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
        }
     });
+
+   return $sharedvm;
 };
 
 # Note: $pool is only needed when creating a VM, because pool permissions
@@ -1823,21 +1833,25 @@ __PACKAGE__->register_method({
                requires => 'full',
                optional => 1,
            }),
-           format => {
+           'format' => {
                description => "Target format for file storage.",
                requires => 'full',
                type => 'string',
                optional => 1,
-               enum => [ 'raw', 'qcow2', 'vmdk'],
+               enum => [ 'raw', 'qcow2', 'vmdk'],
            },
            full => {
                optional => 1,
-               type => 'boolean',
-               description => "Create a full copy of all disk. This is always done when " .
+               type => 'boolean',
+               description => "Create a full copy of all disk. This is always done when " .
                    "you copy a normal VM. For VM templates, we try to create a linked copy by default.",
                default => 0,
            },
-       },
+           target => get_standard_option('pve-node', { 
+               description => "Target node. Only allowed if the original VM is on shared storage.",
+               optional => 1,
+           }),
+        },
     },
     returns => {
        type => 'string',
@@ -1847,7 +1861,7 @@ __PACKAGE__->register_method({
 
        my $rpcenv = PVE::RPCEnvironment::get();
 
-       my $authuser = $rpcenv->get_user();
+        my $authuser = $rpcenv->get_user();
 
        my $node = extract_param($param, 'node');
 
@@ -1862,15 +1876,23 @@ __PACKAGE__->register_method({
            $rpcenv->check_pool_exist($pool);
        }
 
-       my $snapname = extract_param($param, 'snapname');
+        my $snapname = extract_param($param, 'snapname');
 
        my $storage = extract_param($param, 'storage');
 
        my $format = extract_param($param, 'format');
 
+       my $target = extract_param($param, 'target');
+
+        my $localnode = PVE::INotify::nodename();
+
+        undef $target if $target eq $localnode || $target eq 'localhost';
+
+       PVE::Cluster::check_node_exists($target) if $target;
+
        my $storecfg = PVE::Storage::config();
 
-       PVE::Cluster::check_cfs_quorum();
+        PVE::Cluster::check_cfs_quorum();
 
        my $running = PVE::QemuServer::check_running($vmid) || 0;
 
@@ -1899,8 +1921,10 @@ __PACKAGE__->register_method({
 
            my $oldconf = $snapname ? $conf->{snapshots}->{$snapname} : $conf; 
 
-           &$check_storage_access_copy($rpcenv, $authuser, $storecfg, $oldconf, $storage);
+           my $sharedvm = &$check_storage_access_copy($rpcenv, $authuser, $storecfg, $oldconf, $storage);
 
+           die "can't copy VM to node '$target' (VM uses local storage)\n" if $target && !$sharedvm;
+           
            my $conffile = PVE::QemuServer::config_file($newid);
 
            die "unable to create VM $newid: config file already exists\n"
@@ -2000,6 +2024,12 @@ __PACKAGE__->register_method({
 
                    delete $newconf->{lock};
                    PVE::QemuServer::update_config_nolock($newid, $newconf, 1);
+
+                    if ($target) {
+                       my $newconffile = PVE::QemuServer::config_file($newid, $target);
+                       die "Failed to move config to node '$target' - rename failed: $!\n"
+                           if !rename($conffile, $newconffile);
+                   }
                };
                if (my $err = $@) { 
                    unlink $conffile;