mirror of
https://git.proxmox.com/git/qemu-server
synced 2025-06-15 16:22:57 +00:00
move_vm: make it work with PVE::QemuServer:::clone_disk
- use POST instead of PUT (this is not idempotent). - return task ID - use declarative permission check
This commit is contained in:
parent
586bfa78d1
commit
e2cd75fa65
@ -2075,28 +2075,30 @@ __PACKAGE__->register_method({
|
|||||||
__PACKAGE__->register_method({
|
__PACKAGE__->register_method({
|
||||||
name => 'move_vm',
|
name => 'move_vm',
|
||||||
path => '{vmid}/move',
|
path => '{vmid}/move',
|
||||||
method => 'PUT',
|
method => 'POST',
|
||||||
protected => 1,
|
protected => 1,
|
||||||
proxyto => 'node',
|
proxyto => 'node',
|
||||||
description => "Move volume to different storage.",
|
description => "Move volume to different storage.",
|
||||||
permissions => {
|
permissions => {
|
||||||
check => ['perm', '/vms/{vmid}', [ 'VM.Config.Disk' ]],
|
description => "You need 'VM.Config.Disk' permissions on /vms/{vmid}, " .
|
||||||
|
"and 'Datastore.AllocateSpace' permissions on the storage.",
|
||||||
|
check =>
|
||||||
|
[ 'and',
|
||||||
|
['perm', '/vms/{vmid}', [ 'VM.Config.Disk' ]],
|
||||||
|
['perm', '/storage/{storage}', [ 'Datastore.AllocateSpace' ]],
|
||||||
|
],
|
||||||
},
|
},
|
||||||
parameters => {
|
parameters => {
|
||||||
additionalProperties => 0,
|
additionalProperties => 0,
|
||||||
properties => {
|
properties => {
|
||||||
node => get_standard_option('pve-node'),
|
node => get_standard_option('pve-node'),
|
||||||
vmid => get_standard_option('pve-vmid'),
|
vmid => get_standard_option('pve-vmid'),
|
||||||
skiplock => get_standard_option('skiplock'),
|
|
||||||
disk => {
|
disk => {
|
||||||
type => 'string',
|
type => 'string',
|
||||||
description => "The disk you want to move.",
|
description => "The disk you want to move.",
|
||||||
enum => [PVE::QemuServer::disknames()],
|
enum => [ PVE::QemuServer::disknames() ],
|
||||||
},
|
},
|
||||||
storage => {
|
storage => get_standard_option('pve-storage-id', { description => "Target Storage." }),
|
||||||
type => 'string',
|
|
||||||
description => "Target Storage.",
|
|
||||||
},
|
|
||||||
format => {
|
format => {
|
||||||
type => 'string',
|
type => 'string',
|
||||||
description => "Target Format.",
|
description => "Target Format.",
|
||||||
@ -2111,7 +2113,10 @@ __PACKAGE__->register_method({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
returns => { type => 'null'},
|
returns => {
|
||||||
|
type => 'string',
|
||||||
|
description => "the task ID.",
|
||||||
|
},
|
||||||
code => sub {
|
code => sub {
|
||||||
my ($param) = @_;
|
my ($param) = @_;
|
||||||
|
|
||||||
@ -2131,10 +2136,6 @@ __PACKAGE__->register_method({
|
|||||||
|
|
||||||
my $format = extract_param($param, 'format');
|
my $format = extract_param($param, 'format');
|
||||||
|
|
||||||
my $skiplock = extract_param($param, 'skiplock');
|
|
||||||
raise_param_exc({ skiplock => "Only root may use this option." })
|
|
||||||
if $skiplock && $authuser ne 'root@pam';
|
|
||||||
|
|
||||||
my $storecfg = PVE::Storage::config();
|
my $storecfg = PVE::Storage::config();
|
||||||
|
|
||||||
my $updatefn = sub {
|
my $updatefn = sub {
|
||||||
@ -2143,39 +2144,30 @@ __PACKAGE__->register_method({
|
|||||||
|
|
||||||
die "checksum missmatch (file change by other user?)\n"
|
die "checksum missmatch (file change by other user?)\n"
|
||||||
if $digest && $digest ne $conf->{digest};
|
if $digest && $digest ne $conf->{digest};
|
||||||
PVE::QemuServer::check_lock($conf) if !$skiplock;
|
|
||||||
|
|
||||||
die "disk '$disk' does not exist\n" if !$conf->{$disk};
|
die "disk '$disk' does not exist\n" if !$conf->{$disk};
|
||||||
|
|
||||||
my $drive = PVE::QemuServer::parse_drive($disk, $conf->{$disk});
|
my $drive = PVE::QemuServer::parse_drive($disk, $conf->{$disk});
|
||||||
|
|
||||||
my $volid = $drive->{file};
|
my $volid = $drive->{file} || die "disk '$disk' has no associated volume\n";
|
||||||
|
|
||||||
die "disk '$disk' has no associated volume\n" if !$volid;
|
|
||||||
|
|
||||||
die "you can't move a cdrom\n" if PVE::QemuServer::drive_is_cdrom($drive);
|
die "you can't move a cdrom\n" if PVE::QemuServer::drive_is_cdrom($drive);
|
||||||
|
|
||||||
my $oldfmt = undef;
|
my $oldfmt;
|
||||||
my ($oldstoreid, $oldvolname) = PVE::Storage::parse_volume_id($volid);
|
my ($oldstoreid, $oldvolname) = PVE::Storage::parse_volume_id($volid);
|
||||||
if ($oldvolname =~ m/\.(raw|qcow2|vmdk)$/){
|
if ($oldvolname =~ m/\.(raw|qcow2|vmdk)$/){
|
||||||
$oldfmt = $1;
|
$oldfmt = $1;
|
||||||
}
|
}
|
||||||
|
|
||||||
die "you can't move on the same storage with same format" if ($oldstoreid eq $storeid && (!$format || $oldfmt eq $format));
|
die "you can't move on the same storage with same format\n" if $oldstoreid eq $storeid &&
|
||||||
|
(!$format || !$oldfmt || $oldfmt eq $format);
|
||||||
$rpcenv->check($authuser, "/storage/$storeid", ['Datastore.AllocateSpace']);
|
|
||||||
|
|
||||||
$drive->{full} = 1;
|
|
||||||
|
|
||||||
my $drives = {};
|
|
||||||
my $vollist = [];
|
|
||||||
|
|
||||||
$drives->{$disk} = $drive;
|
|
||||||
push @$vollist, $drive->{file};
|
|
||||||
|
|
||||||
PVE::Cluster::log_msg('info', $authuser, "move disk VM $vmid: move --disk $disk --storage $storeid");
|
PVE::Cluster::log_msg('info', $authuser, "move disk VM $vmid: move --disk $disk --storage $storeid");
|
||||||
|
|
||||||
my $running = PVE::QemuServer::check_running($vmid);
|
my $running = PVE::QemuServer::check_running($vmid);
|
||||||
|
|
||||||
|
PVE::Storage::activate_volumes($storecfg, [ $drive->{file} ]);
|
||||||
|
|
||||||
my $realcmd = sub {
|
my $realcmd = sub {
|
||||||
|
|
||||||
my $newvollist = [];
|
my $newvollist = [];
|
||||||
@ -2183,7 +2175,12 @@ __PACKAGE__->register_method({
|
|||||||
eval {
|
eval {
|
||||||
local $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = sub { die "interrupted by signal\n"; };
|
local $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = sub { die "interrupted by signal\n"; };
|
||||||
|
|
||||||
&$clone_disks($storecfg, $storeid, $vollist, $newvollist, $drives, undef, $format, $vmid, $vmid, $conf, $running);
|
my $newdrive = PVE::QemuServer::clone_disk($storecfg, $vmid, $running, $disk, $drive, undef,
|
||||||
|
$vmid, $storeid, $format, 1, $newvollist);
|
||||||
|
|
||||||
|
$conf->{$disk} = PVE::QemuServer::print_drive($vmid, $newdrive);
|
||||||
|
|
||||||
|
PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
|
||||||
};
|
};
|
||||||
if (my $err = $@) {
|
if (my $err = $@) {
|
||||||
|
|
||||||
@ -2197,8 +2194,8 @@ __PACKAGE__->register_method({
|
|||||||
|
|
||||||
return $rpcenv->fork_worker('qmmove', $vmid, $authuser, $realcmd);
|
return $rpcenv->fork_worker('qmmove', $vmid, $authuser, $realcmd);
|
||||||
};
|
};
|
||||||
PVE::QemuServer::lock_config($vmid, $updatefn);
|
|
||||||
return undef;
|
return PVE::QemuServer::lock_config($vmid, $updatefn);
|
||||||
}});
|
}});
|
||||||
|
|
||||||
__PACKAGE__->register_method({
|
__PACKAGE__->register_method({
|
||||||
|
2
qm
2
qm
@ -359,7 +359,7 @@ my $cmddef = {
|
|||||||
|
|
||||||
resize => [ "PVE::API2::Qemu", 'resize_vm', ['vmid', 'disk', 'size'], { node => $nodename } ],
|
resize => [ "PVE::API2::Qemu", 'resize_vm', ['vmid', 'disk', 'size'], { node => $nodename } ],
|
||||||
|
|
||||||
move => [ "PVE::API2::Qemu", 'move_vm', ['vmid', 'disk', 'storage'], { node => $nodename } ],
|
move => [ "PVE::API2::Qemu", 'move_vm', ['vmid', 'disk', 'storage'], { node => $nodename }, $upid_exit ],
|
||||||
|
|
||||||
unlink => [ "PVE::API2::Qemu", 'unlink', ['vmid', 'idlist'], { node => $nodename } ],
|
unlink => [ "PVE::API2::Qemu", 'unlink', ['vmid', 'idlist'], { node => $nodename } ],
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user