restore: implement rate limiting

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2018-02-22 17:15:24 +01:00 committed by Thomas Lamprecht
parent b20df606a1
commit 7c536e11c4
3 changed files with 78 additions and 18 deletions

View File

@ -430,6 +430,12 @@ __PACKAGE__->register_method({
type => 'string', format => 'pve-poolid',
description => "Add the VM to the specified pool.",
},
bwlimit => {
description => "Override io bandwidth.",
optional => 1,
type => 'integer',
minimum => '0',
}
}),
},
returns => {
@ -456,6 +462,8 @@ __PACKAGE__->register_method({
my $pool = extract_param($param, 'pool');
my $bwlimit = extract_param($param, 'bwlimit');
my $filename = PVE::QemuConfig->config_file($vmid);
my $storecfg = PVE::Storage::config();
@ -543,7 +551,8 @@ __PACKAGE__->register_method({
PVE::QemuServer::restore_archive($archive, $vmid, $authuser, {
storage => $storage,
pool => $pool,
unique => $unique });
unique => $unique,
bwlimit => $bwlimit, });
PVE::AccessControl::add_vm_to_pool($vmid, $pool) if $pool;
};

View File

@ -53,6 +53,12 @@ __PACKAGE__->register_method({
type => 'string', format => 'pve-poolid',
description => "Add the VM to the specified pool.",
},
bwlimit => {
description => "Override io bandwidth.",
optional => 1,
type => 'number',
minimum => '0',
}
},
},
returns => {

View File

@ -5635,21 +5635,52 @@ sub rescan {
sub restore_vma_archive {
my ($archive, $vmid, $user, $opts, $comp) = @_;
my $input = $archive eq '-' ? "<&STDIN" : undef;
my $readfrom = $archive;
my $uncomp = '';
if ($comp) {
my $cfg = PVE::Storage::config();
my $commands = [];
my $bwlimit = $opts->{bwlimit};
my $dbg_cmdstring = '';
my $add_pipe = sub {
my ($cmd) = @_;
push @$commands, $cmd;
$dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
$dbg_cmdstring .= PVE::Tools::cmd2string($cmd);
$readfrom = '-';
my $qarchive = PVE::Tools::shellquote($archive);
};
my $input = undef;
if ($archive eq '-') {
$input = '<&STDIN';
} else {
# If we use a backup from a PVE defined storage we also consider that
# storage's rate limit:
my (undef, $volid) = PVE::Storage::path_to_volume_id($cfg, $archive);
if (defined($volid)) {
my ($sid, undef) = PVE::Storage::parse_volume_id($volid);
my $readlimit = PVE::Storage::get_bandwidth_limit('restore', [$sid], $bwlimit);
if ($readlimit) {
print STDERR "applying read rate limit: $readlimit\n";
my $cstream = ['cstream', '-t', $readlimit*1024];
if ($readfrom ne '-') {
push @$cstream, '--', $readfrom;
}
$add_pipe->($cstream);
}
}
}
if ($comp) {
my $cmd;
if ($comp eq 'gzip') {
$uncomp = "zcat $qarchive|";
$cmd = ['zcat', $readfrom];
} elsif ($comp eq 'lzop') {
$uncomp = "lzop -d -c $qarchive|";
$cmd = ['lzop', '-d', '-c', $readfrom];
} else {
die "unknown compression method '$comp'\n";
}
$add_pipe->($cmd);
}
my $tmpdir = "/var/tmp/vzdumptmp$$";
@ -5669,7 +5700,7 @@ sub restore_vma_archive {
open($fifofh, '>', $mapfifo) || die $!;
};
my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
$add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
my $oldtimeout;
my $timeout = 5;
@ -5685,6 +5716,8 @@ sub restore_vma_archive {
my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
my %storage_limits;
my $print_devmap = sub {
my $virtdev_hash = {};
@ -5723,17 +5756,24 @@ sub restore_vma_archive {
$rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
}
$storage_limits{$storeid} = $bwlimit;
$virtdev_hash->{$virtdev} = $devinfo->{$devname};
}
}
foreach my $key (keys %storage_limits) {
my $limit = PVE::Storage::get_bandwidth_limit('restore', [$key], $bwlimit);
next if !$limit;
print STDERR "rate limit for storage $key: $limit KiB/s\n";
$storage_limits{$key} = $limit * 1024;
}
foreach my $devname (keys %$devinfo) {
die "found no device mapping information for device '$devname'\n"
if !$devinfo->{$devname}->{virtdev};
}
my $cfg = PVE::Storage::config();
# create empty/temp config
if ($oldconf) {
PVE::Tools::file_set_contents($conffile, "memory: 128\n");
@ -5776,14 +5816,20 @@ sub restore_vma_archive {
foreach my $virtdev (sort keys %$virtdev_hash) {
my $d = $virtdev_hash->{$virtdev};
my $alloc_size = int(($d->{size} + 1024 - 1)/1024);
my $scfg = PVE::Storage::storage_config($cfg, $d->{storeid});
my $storeid = $d->{storeid};
my $scfg = PVE::Storage::storage_config($cfg, $storeid);
my $map_opts = '';
if (my $limit = $storage_limits{$storeid}) {
$map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
}
# test if requested format is supported
my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($cfg, $d->{storeid});
my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($cfg, $storeid);
my $supported = grep { $_ eq $d->{format} } @$validFormats;
$d->{format} = $defFormat if !$supported;
my $volid = PVE::Storage::vdisk_alloc($cfg, $d->{storeid}, $vmid,
my $volid = PVE::Storage::vdisk_alloc($cfg, $storeid, $vmid,
$d->{format}, undef, $alloc_size);
print STDERR "new volume ID is '$volid'\n";
$d->{volid} = $volid;
@ -5796,7 +5842,7 @@ sub restore_vma_archive {
$write_zeros = 0;
}
print $fifofh "format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
$map->{$virtdev} = $volid;
@ -5849,8 +5895,8 @@ sub restore_vma_archive {
}
};
print "restore vma archive: $cmd\n";
run_command($cmd, input => $input, outfunc => $parser, afterfork => $openfifo);
print "restore vma archive: $dbg_cmdstring\n";
run_command($commands, input => $input, outfunc => $parser, afterfork => $openfifo);
};
my $err = $@;
@ -5862,7 +5908,6 @@ sub restore_vma_archive {
push @$vollist, $volid if $volid;
}
my $cfg = PVE::Storage::config();
PVE::Storage::deactivate_volumes($cfg, $vollist);
unlink $mapfifo;