Compare commits
10 commits
202446cd37
...
b74b43f930
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b74b43f930 | ||
|
|
b344b2e7d8 | ||
|
|
e2a17571e6 | ||
|
|
073a98b4c7 | ||
|
|
68c3142605 | ||
|
|
c10e73d93b | ||
|
|
6e5a42052c | ||
|
|
9eb914de16 | ||
|
|
02acde02b6 | ||
|
|
0f7a4d2d84 |
17 changed files with 1121 additions and 2522 deletions
|
|
@ -9,6 +9,7 @@ all:
|
|||
install: PVE bin udev-rbd
|
||||
$(MAKE) -C bin install
|
||||
$(MAKE) -C PVE install
|
||||
$(MAKE) -C services install
|
||||
$(MAKE) -C udev-rbd install
|
||||
|
||||
.PHONY: test
|
||||
|
|
|
|||
|
|
@ -218,13 +218,13 @@ __PACKAGE__->register_method({
|
|||
enum => $storage_type_enum,
|
||||
},
|
||||
config => {
|
||||
description => "Partial, possible server generated, configuration properties.",
|
||||
description => "Partial, possibly server generated, configuration properties.",
|
||||
type => 'object',
|
||||
optional => 1,
|
||||
additionalProperties => 1,
|
||||
properties => {
|
||||
'encryption-key' => {
|
||||
description => "The, possible auto-generated, encryption-key.",
|
||||
description => "The, possibly auto-generated, encryption-key.",
|
||||
optional => 1,
|
||||
type => 'string',
|
||||
},
|
||||
|
|
@ -318,13 +318,13 @@ __PACKAGE__->register_method({
|
|||
enum => $storage_type_enum,
|
||||
},
|
||||
config => {
|
||||
description => "Partial, possible server generated, configuration properties.",
|
||||
description => "Partial, possibly server generated, configuration properties.",
|
||||
type => 'object',
|
||||
optional => 1,
|
||||
additionalProperties => 1,
|
||||
properties => {
|
||||
'encryption-key' => {
|
||||
description => "The, possible auto-generated, encryption-key.",
|
||||
description => "The, possibly auto-generated, encryption-key.",
|
||||
optional => 1,
|
||||
type => 'string',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -300,7 +300,50 @@ __PACKAGE__->register_method({
|
|||
},
|
||||
returns => {
|
||||
type => "object",
|
||||
properties => {},
|
||||
properties => {
|
||||
type => {
|
||||
description => "Storage type.",
|
||||
type => 'string',
|
||||
},
|
||||
content => {
|
||||
description => "Allowed storage content types.",
|
||||
type => 'string',
|
||||
format => 'pve-storage-content-list',
|
||||
},
|
||||
enabled => {
|
||||
description => "Set when storage is enabled (not disabled).",
|
||||
type => 'boolean',
|
||||
optional => 1,
|
||||
},
|
||||
active => {
|
||||
description => "Set when storage is accessible.",
|
||||
type => 'boolean',
|
||||
optional => 1,
|
||||
},
|
||||
shared => {
|
||||
description => "Shared flag from storage configuration.",
|
||||
type => 'boolean',
|
||||
optional => 1,
|
||||
},
|
||||
total => {
|
||||
description => "Total storage space in bytes.",
|
||||
type => 'integer',
|
||||
renderer => 'bytes',
|
||||
optional => 1,
|
||||
},
|
||||
used => {
|
||||
description => "Used storage space in bytes.",
|
||||
type => 'integer',
|
||||
renderer => 'bytes',
|
||||
optional => 1,
|
||||
},
|
||||
avail => {
|
||||
description => "Available storage space in bytes.",
|
||||
type => 'integer',
|
||||
renderer => 'bytes',
|
||||
optional => 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
code => sub {
|
||||
my ($param) = @_;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ install:
|
|||
make -C API2 install
|
||||
make -C BackupProvider install
|
||||
make -C CLI install
|
||||
make -C Service install
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
|
|
|
|||
10
src/PVE/Service/Makefile
Normal file
10
src/PVE/Service/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
SOURCES=pvestord.pm
|
||||
|
||||
all:
|
||||
|
||||
.PHONY: install
|
||||
install: $(SOURCES)
|
||||
install -d -m 0755 $(DESTDIR)$(PERLDIR)/PVE/Service
|
||||
for i in $(SOURCES); do install -D -m 0644 $$i $(DESTDIR)$(PERLDIR)/PVE/Service/$$i; done
|
||||
|
||||
clean:
|
||||
193
src/PVE/Service/pvestord.pm
Normal file
193
src/PVE/Service/pvestord.pm
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
package PVE::Service::pvestord;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Time::HiRes qw (gettimeofday);
|
||||
use PVE::SafeSyslog;
|
||||
use PVE::Daemon;
|
||||
use PVE::Cluster qw(cfs_read_file);
|
||||
use PVE::Storage;
|
||||
use PVE::QemuConfig;
|
||||
use PVE::QemuServer;
|
||||
use PVE::QemuServer::Drive;
|
||||
use PVE::QemuServer::Blockdev;
|
||||
use PVE::QemuServer::Helpers;
|
||||
use PVE::INotify;
|
||||
|
||||
use base qw(PVE::Daemon);
|
||||
|
||||
my $cmdline = [$0, @ARGV];
|
||||
|
||||
my %daemon_options = (restart_on_error => 5, stop_wait_time => 15);
|
||||
my $daemon = __PACKAGE__->new('pvestord', $cmdline, %daemon_options);
|
||||
|
||||
my $nodename = PVE::INotify::nodename();
|
||||
|
||||
sub init {
|
||||
my ($self) = @_;
|
||||
PVE::Cluster::cfs_update();
|
||||
}
|
||||
|
||||
my sub get_drive_id {
|
||||
my ($block_stats, $blockdev_nodename) = @_;
|
||||
foreach my $drive_id (keys %$block_stats) {
|
||||
my $entry = $block_stats->{$drive_id};
|
||||
my $file_blockdev = $entry->{parent}->{parent};
|
||||
return $drive_id
|
||||
if ($file_blockdev->{'node-name'} eq $blockdev_nodename);
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
my sub dequeue {
|
||||
my ($queue) = @_;
|
||||
PVE::Storage::lock_extend_queue(
|
||||
sub {
|
||||
# TODO: This will have to have some sort of mechanism
|
||||
# to make sure that the element that is removed is the one
|
||||
# that this node is handling
|
||||
shift @$queue;
|
||||
|
||||
PVE::Storage::write_extend_queue($queue);
|
||||
},
|
||||
"Could not lock extend queue file",
|
||||
);
|
||||
}
|
||||
|
||||
sub perform_extend {
|
||||
my $storecfg = PVE::Storage::config();
|
||||
my $queue = PVE::Storage::extend_queue();
|
||||
|
||||
my $first_extend_request = @$queue[0];
|
||||
return if !$first_extend_request;
|
||||
|
||||
my ($vmid, $blockdev_nodename) = @$first_extend_request;
|
||||
|
||||
my $vmlist = PVE::Cluster::get_vmlist();
|
||||
my $owner_nodename = $vmlist->{ids}->{$vmid}->{node};
|
||||
|
||||
if ($owner_nodename eq $nodename) {
|
||||
my $running = PVE::QemuServer::Helpers::vm_running_locally($vmid);
|
||||
# NOTE: The block device node name is currently generated using a SHA-256 hash,
|
||||
# which makes it impossible to reverse-engineer and identify the original disk.
|
||||
# As a result, we must rely on `blockstats` to determine which disk corresponds
|
||||
# to a given node name — but these statistics are only available when the machine is running.
|
||||
# Consider updating the `get_node_name()` function to use a reversible encoding
|
||||
# (e.g., Base64) instead of a SHA-256 digest to simplify disk identification.
|
||||
|
||||
my $extend_function = sub {
|
||||
dequeue($queue);
|
||||
syslog("info", "Processsing extend request $vmid: $blockdev_nodename\n");
|
||||
|
||||
my $block_stats = PVE::QemuServer::Blockdev::get_block_stats($vmid);
|
||||
|
||||
my $drive_id = get_drive_id($block_stats, $blockdev_nodename);
|
||||
if (!$drive_id) {
|
||||
syslog("err", "Couldn't find drive_id for blockdev $blockdev_nodename");
|
||||
return;
|
||||
}
|
||||
my $vm_conf = PVE::QemuConfig->load_config($vmid);
|
||||
my $drive = PVE::QemuServer::parse_drive($drive_id, $vm_conf->{$drive_id});
|
||||
my $volid = $drive->{file};
|
||||
|
||||
PVE::QemuServer::Blockdev::underlay_resize(
|
||||
$storecfg, $vmid, $drive_id, $volid
|
||||
);
|
||||
};
|
||||
PVE::QemuConfig->lock_config($vmid, $extend_function);
|
||||
}
|
||||
}
|
||||
|
||||
my $next_update = 0;
|
||||
my $cycle = 0;
|
||||
my $restart_request = 0;
|
||||
|
||||
my $initial_memory_usage = 0;
|
||||
|
||||
# 1 second cycles
|
||||
my $updatetime = 1;
|
||||
|
||||
sub run {
|
||||
my ($self) = @_;
|
||||
syslog("info", "Running on node $nodename\n");
|
||||
|
||||
for (;;) { # forever
|
||||
# get next extend request
|
||||
$next_update = time() + $updatetime;
|
||||
|
||||
if ($cycle) {
|
||||
my ($ccsec, $cusec) = gettimeofday();
|
||||
eval {
|
||||
# syslog('info', "start status update");
|
||||
PVE::Cluster::cfs_update();
|
||||
perform_extend();
|
||||
};
|
||||
my $err = $@;
|
||||
|
||||
if ($err) {
|
||||
syslog('err', "status update error: $err");
|
||||
}
|
||||
|
||||
my ($ccsec_end, $cusec_end) = gettimeofday();
|
||||
my $cptime = ($ccsec_end - $ccsec) + ($cusec_end - $cusec) / 1000000;
|
||||
|
||||
syslog('info', sprintf("extend process time (%.3f seconds)", $cptime))
|
||||
if ($cptime > 1);
|
||||
}
|
||||
|
||||
$cycle++;
|
||||
|
||||
my $mem = PVE::ProcFSTools::read_memory_usage();
|
||||
my $resident_kb = $mem->{resident} / 1024;
|
||||
|
||||
if (!defined($initial_memory_usage) || ($cycle < 10)) {
|
||||
$initial_memory_usage = $resident_kb;
|
||||
} else {
|
||||
my $diff = $resident_kb - $initial_memory_usage;
|
||||
if ($diff > 15 * 1024) {
|
||||
syslog(
|
||||
'info',
|
||||
"restarting server after $cycle cycles to "
|
||||
. "reduce memory usage (free $resident_kb ($diff) KB)",
|
||||
);
|
||||
$self->restart_daemon();
|
||||
}
|
||||
}
|
||||
|
||||
my $wcount = 0;
|
||||
while (
|
||||
(time() < $next_update)
|
||||
&& ($wcount < $updatetime)
|
||||
&& # protect against time wrap
|
||||
!$restart_request
|
||||
) {
|
||||
$wcount++;
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
$self->restart_daemon() if $restart_request;
|
||||
}
|
||||
}
|
||||
|
||||
sub shutdown {
|
||||
my ($self) = @_;
|
||||
|
||||
syslog('info', "server closing");
|
||||
|
||||
$self->exit_daemon(0);
|
||||
}
|
||||
|
||||
$daemon->register_start_command();
|
||||
$daemon->register_restart_command(1);
|
||||
$daemon->register_stop_command();
|
||||
$daemon->register_status_command();
|
||||
|
||||
our $cmddef = {
|
||||
start => [__PACKAGE__, 'start', []],
|
||||
restart => [__PACKAGE__, 'restart', []],
|
||||
stop => [__PACKAGE__, 'stop', []],
|
||||
status => [__PACKAGE__, 'status', [], undef, sub { print shift . "\n"; }],
|
||||
};
|
||||
|
||||
1;
|
||||
|
|
@ -15,7 +15,7 @@ use Socket;
|
|||
use Time::Local qw(timelocal);
|
||||
|
||||
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::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file cfs_register_file);
|
||||
use PVE::DataCenterConfig;
|
||||
use PVE::Exception qw(raise_param_exc raise);
|
||||
use PVE::JSONSchema;
|
||||
|
|
@ -239,6 +239,76 @@ sub write_config {
|
|||
cfs_write_file('storage.cfg', $cfg);
|
||||
}
|
||||
|
||||
cfs_register_file("extend-queue", \&parser_extend_queue, \&writer_extend_queue);
|
||||
|
||||
sub extend_queue {
|
||||
return cfs_read_file("extend-queue");
|
||||
}
|
||||
|
||||
sub write_extend_queue {
|
||||
my ($extend_queue) = @_;
|
||||
return cfs_write_file("extend-queue",$extend_queue);
|
||||
}
|
||||
|
||||
sub lock_extend_queue {
|
||||
my ($code, $errmsg) = @_;
|
||||
|
||||
cfs_lock_file("extend-queue", undef, $code);
|
||||
my $err = $@;
|
||||
if ($err) {
|
||||
$errmsg ? die "$errmsg: $err" : die $err;
|
||||
}
|
||||
}
|
||||
|
||||
sub parser_extend_queue {
|
||||
my ($filename, $raw) = @_;
|
||||
|
||||
my @queue;
|
||||
|
||||
my $lineno = 0;
|
||||
my @lines = split(/\n/, $raw);
|
||||
my $nextline = sub {
|
||||
while (defined(my $line = shift @lines)) {
|
||||
$lineno++;
|
||||
return $line if ($line !~ /^\s*#/);
|
||||
}
|
||||
};
|
||||
|
||||
while (@lines) {
|
||||
my $line = $nextline->();
|
||||
next if !$line;
|
||||
print "Current line $line\n";
|
||||
|
||||
# vmid: nodename
|
||||
if ($line =~ '[1-9][0-9]{2,8}+: [aefz][0-9a-f]{30}') {
|
||||
print "Extend request is valid\n";
|
||||
my ($vmid, $nodename) = split(/:\s/, $line, 2);
|
||||
push @queue, [$vmid, $nodename];
|
||||
}
|
||||
}
|
||||
return \@queue;
|
||||
}
|
||||
|
||||
sub writer_extend_queue {
|
||||
my ($filename, $queue) = @_;
|
||||
|
||||
my $out = "";
|
||||
foreach my $entry (@$queue) {
|
||||
my ($vmid, $nodename) = @$entry;
|
||||
$out .= format_extend_request($vmid, $nodename) . "\n";
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
sub format_extend_request {
|
||||
my ($vmid, $node_name) = @_;
|
||||
|
||||
my $request = $vmid . ': ' . $node_name;
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
sub lock_storage_config {
|
||||
my ($code, $errmsg) = @_;
|
||||
|
||||
|
|
@ -410,6 +480,34 @@ sub volume_resize {
|
|||
}
|
||||
}
|
||||
|
||||
sub volume_underlay_size_info {
|
||||
my ($cfg, $volid, $timeout) = @_;
|
||||
|
||||
my ($storeid, $volname) = parse_volume_id($volid, 1);
|
||||
if ($storeid) {
|
||||
my $scfg = storage_config($cfg, $storeid);
|
||||
my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
|
||||
return $plugin->volume_underlay_size_info($scfg, $storeid, $volname, $timeout);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub volume_underlay_resize {
|
||||
my ($cfg, $volid, $size, $running, $backing_snap) = @_;
|
||||
|
||||
my ($storeid, $volname) = parse_volume_id($volid, 1);
|
||||
if ($storeid) {
|
||||
my $scfg = storage_config($cfg, $storeid);
|
||||
my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
|
||||
return $plugin->volume_underlay_resize($scfg, $storeid, $volname, $size, $running, $backing_snap);
|
||||
} elsif ($volid =~ m|^(/.+)$| && -e $volid) {
|
||||
die "resize file/device '$volid' is not possible\n";
|
||||
} else {
|
||||
die "unable to parse volume ID '$volid'\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub volume_rollback_is_possible {
|
||||
my ($cfg, $volid, $snap, $blockers) = @_;
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ C<$options> currently allows setting the C<preallocation> value.
|
|||
=cut
|
||||
|
||||
sub qemu_img_create_qcow2_backed {
|
||||
my ($path, $backing_path, $backing_format, $options) = @_;
|
||||
my ($path, $backing_path, $backing_format, $options, $thin) = @_;
|
||||
|
||||
my $cmd = [
|
||||
'/usr/bin/qemu-img',
|
||||
|
|
@ -188,7 +188,7 @@ sub qemu_img_create_qcow2_backed {
|
|||
my $opts = ['extended_l2=on', 'cluster_size=128k'];
|
||||
|
||||
push @$opts, "preallocation=$options->{preallocation}"
|
||||
if defined($options->{preallocation});
|
||||
if defined($options->{preallocation}) && !$thin;
|
||||
push @$cmd, '-o', join(',', @$opts) if @$opts > 0;
|
||||
|
||||
run_command($cmd, errmsg => "unable to create image");
|
||||
|
|
|
|||
|
|
@ -48,9 +48,7 @@ sub iscsi_session_list {
|
|||
outfunc => sub {
|
||||
my $line = shift;
|
||||
# example: tcp: [1] 192.168.122.252:3260,1 iqn.2003-01.org.linux-iscsi.proxmox-nfs.x8664:sn.00567885ba8f (non-flash)
|
||||
if ($line =~
|
||||
m/^tcp:\s+\[(\S+)\]\s+(\S+:\d+)\,\S+\s+(\S+)\s+\S+?\s*$/
|
||||
) {
|
||||
if ($line =~ m/^tcp:\s+\[(\S+)\]\s+(\S+:\d+)\,\S+\s+(\S+)\s+\S+?\s*$/) {
|
||||
my ($session_id, $portal, $target) = ($1, $2, $3);
|
||||
# there can be several sessions per target (multipath)
|
||||
push @{ $res->{$target} }, { session_id => $session_id, portal => $portal };
|
||||
|
|
|
|||
|
|
@ -400,6 +400,8 @@ sub options {
|
|||
tagged_only => { optional => 1 },
|
||||
bwlimit => { optional => 1 },
|
||||
'snapshot-as-volume-chain' => { optional => 1 },
|
||||
chunksize => { optional => 1 },
|
||||
'chunk-percentage' => { optional => 1 },
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -575,7 +577,7 @@ sub lvrename {
|
|||
}
|
||||
|
||||
my sub lvm_qcow2_format {
|
||||
my ($class, $storeid, $scfg, $name, $fmt, $backing_snap, $size) = @_;
|
||||
my ($class, $storeid, $scfg, $name, $fmt, $backing_snap, $size, $thin) = @_;
|
||||
|
||||
$class->activate_volume($storeid, $scfg, $name);
|
||||
my $path = $class->path($scfg, $name, $storeid);
|
||||
|
|
@ -585,7 +587,9 @@ my sub lvm_qcow2_format {
|
|||
};
|
||||
if ($backing_snap) {
|
||||
my $backing_volname = get_snap_name($class, $name, $backing_snap);
|
||||
PVE::Storage::Common::qemu_img_create_qcow2_backed($path, $backing_volname, $fmt, $options);
|
||||
PVE::Storage::Common::qemu_img_create_qcow2_backed(
|
||||
$path, $backing_volname, $fmt, $options, $thin,
|
||||
);
|
||||
} else {
|
||||
PVE::Storage::Common::qemu_img_create($fmt, $size, $path, $options);
|
||||
}
|
||||
|
|
@ -629,7 +633,16 @@ my sub alloc_lvm_image {
|
|||
die "no such volume group '$vg'\n" if !defined($vgs->{$vg});
|
||||
|
||||
my $free = int($vgs->{$vg}->{free});
|
||||
my $lvmsize = calculate_lvm_size($size, $fmt, $backing_snap);
|
||||
my $lvmsize;
|
||||
|
||||
# FIX: make this variable a check box when taking a snapshot
|
||||
# right now all snapshots are created thin for testing purposes
|
||||
my $thin = $backing_snap ? 1 : 0;
|
||||
if ($thin) {
|
||||
$lvmsize = 2 * 1024 * 1024;
|
||||
} else {
|
||||
$lvmsize = calculate_lvm_size($size, $fmt, $backing_snap);
|
||||
}
|
||||
|
||||
die "not enough free space ($free < $size)\n" if $free < $size;
|
||||
|
||||
|
|
@ -641,7 +654,7 @@ my sub alloc_lvm_image {
|
|||
return if $fmt ne 'qcow2';
|
||||
|
||||
#format the lvm volume with qcow2 format
|
||||
eval { lvm_qcow2_format($class, $storeid, $scfg, $name, $fmt, $backing_snap, $size) };
|
||||
eval { lvm_qcow2_format($class, $storeid, $scfg, $name, $fmt, $backing_snap, $size, $thin) };
|
||||
if ($@) {
|
||||
my $err = $@;
|
||||
#no need to safe cleanup as the volume is still empty
|
||||
|
|
@ -928,6 +941,44 @@ sub volume_resize {
|
|||
$lvmsize = "${lvmsize}k";
|
||||
|
||||
my $path = $class->path($scfg, $volname);
|
||||
lv_extend($class, $scfg, $storeid, $lvmsize, $path);
|
||||
|
||||
if (!$running && $format eq 'qcow2') {
|
||||
my $preallocation = PVE::Storage::Plugin::preallocation_cmd_opt($scfg, $format);
|
||||
PVE::Storage::Common::qemu_img_resize($path, $format, $size, $preallocation, 10);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub volume_underlay_resize {
|
||||
my ($class, $scfg, $storeid, $volname, $backing_snap) = @_;
|
||||
|
||||
my ($format) = ($class->parse_volname($volname))[6];
|
||||
|
||||
my $path = $class->filesystem_path($scfg, $volname);
|
||||
my $json = PVE::Storage::Common::qemu_img_info($path, undef, 10, 0);
|
||||
my $json_decode = eval { decode_json($json) };
|
||||
if ($@) {
|
||||
die "Can't decode qemu snapshot list. Invalid JSON: $@\n";
|
||||
}
|
||||
|
||||
my $virtual_size = $json_decode->{'virtual-size'} / 1024;
|
||||
|
||||
my $underlay_size = lv_size($path, 10);
|
||||
|
||||
my $updated_underlay_size = ($underlay_size + $scfg->{chunksize}) / 1024;
|
||||
$updated_underlay_size = calculate_lvm_size($virtual_size, $format, $backing_snap)
|
||||
if $updated_underlay_size >= $virtual_size;
|
||||
|
||||
my $lvmsize = "${updated_underlay_size}k";
|
||||
lv_extend($class, $scfg, $storeid, $lvmsize, $path);
|
||||
|
||||
return $updated_underlay_size;
|
||||
}
|
||||
|
||||
sub lv_extend {
|
||||
my ($class, $scfg, $storeid, $lvmsize, $path) = @_;
|
||||
my $cmd = ['/sbin/lvextend', '-L', $lvmsize, $path];
|
||||
|
||||
$class->cluster_lock_storage(
|
||||
|
|
@ -938,13 +989,6 @@ sub volume_resize {
|
|||
run_command($cmd, errmsg => "error resizing volume '$path'");
|
||||
},
|
||||
);
|
||||
|
||||
if (!$running && $format eq 'qcow2') {
|
||||
my $preallocation = PVE::Storage::Plugin::preallocation_cmd_opt($scfg, $format);
|
||||
PVE::Storage::Common::qemu_img_resize($path, $format, $size, $preallocation, 10);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub volume_size_info {
|
||||
|
|
@ -955,6 +999,22 @@ sub volume_size_info {
|
|||
|
||||
return PVE::Storage::Plugin::file_size_info($path, $timeout, $format) if $format eq 'qcow2';
|
||||
|
||||
my $size = lv_size($path, $timeout);
|
||||
return wantarray ? ($size, 'raw', 0, undef) : $size;
|
||||
}
|
||||
|
||||
sub volume_underlay_size_info {
|
||||
my ($class, $scfg, $storeid, $volname, $timeout) = @_;
|
||||
|
||||
my ($format) = ($class->parse_volname($volname))[6];
|
||||
my $path = $class->filesystem_path($scfg, $volname);
|
||||
|
||||
return lv_size($path, $timeout);
|
||||
}
|
||||
|
||||
sub lv_size {
|
||||
my ($path, $timeout) = @_;
|
||||
|
||||
my $cmd = [
|
||||
'/sbin/lvs',
|
||||
'--separator',
|
||||
|
|
@ -978,7 +1038,7 @@ sub volume_size_info {
|
|||
$size = int(shift);
|
||||
},
|
||||
);
|
||||
return wantarray ? ($size, 'raw', 0, undef) : $size;
|
||||
return $size;
|
||||
}
|
||||
|
||||
sub volume_snapshot {
|
||||
|
|
|
|||
|
|
@ -228,6 +228,20 @@ my $defaultData = {
|
|||
default => 0,
|
||||
optional => 1,
|
||||
},
|
||||
chunksize => {
|
||||
type => 'integer',
|
||||
description => 'The chunksize in Bytes to define the write threshold'
|
||||
. 'of thin disks on thick storage.',
|
||||
default => 1073741824, # 1 GiB
|
||||
optional => 1,
|
||||
},
|
||||
'chunk-percentage' => {
|
||||
type => 'number',
|
||||
description => 'The percentage of written disk to define the write'
|
||||
. 'threshold.',
|
||||
default => 0.5,
|
||||
optional => 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -1265,7 +1279,6 @@ sub volume_size_info {
|
|||
my $format = ($class->parse_volname($volname))[6];
|
||||
my $path = $class->filesystem_path($scfg, $volname);
|
||||
return file_size_info($path, $timeout, $format);
|
||||
|
||||
}
|
||||
|
||||
sub volume_resize {
|
||||
|
|
@ -1285,6 +1298,20 @@ sub volume_resize {
|
|||
return undef;
|
||||
}
|
||||
|
||||
sub volume_underlay_size_info {
|
||||
my ($class, $scfg, $storeid, $volname, $timeout) = @_;
|
||||
|
||||
# Only supported by LVM for now
|
||||
die "volume underlay is not supported for storage type '$scfg->{type}'\n";
|
||||
}
|
||||
|
||||
sub volume_underlay_resize {
|
||||
my ($class, $scfg, $storeid, $volname, $backing_snap) = @_;
|
||||
|
||||
# Only supported by LVM for now
|
||||
die "volume underlay is not supported for storage type '$scfg->{type}'\n";
|
||||
}
|
||||
|
||||
sub volume_snapshot {
|
||||
my ($class, $scfg, $storeid, $volname, $snap) = @_;
|
||||
|
||||
|
|
@ -2450,7 +2477,7 @@ sub new_backup_provider {
|
|||
|
||||
=head3 volume_qemu_snapshot_method
|
||||
|
||||
$blockdev = $plugin->volume_qemu_snapshot_method($storeid, $scfg, $volname)
|
||||
$method = $plugin->volume_qemu_snapshot_method($storeid, $scfg, $volname);
|
||||
|
||||
Returns a string with the type of snapshot that qemu can do for a specific volume
|
||||
|
||||
|
|
|
|||
|
|
@ -368,9 +368,9 @@ sub zfs_delete_zvol {
|
|||
|
||||
eval { $class->zfs_request($scfg, undef, 'destroy', '-r', "$scfg->{pool}/$zvol"); };
|
||||
if ($err = $@) {
|
||||
if ($err =~ m/^zfs error:(.*): dataset is busy.*/) {
|
||||
if ($err =~ m/dataset is busy/) {
|
||||
sleep(1);
|
||||
} elsif ($err =~ m/^zfs error:.*: dataset does not exist.*$/) {
|
||||
} elsif ($err =~ m/dataset does not exist/) {
|
||||
$err = undef;
|
||||
last;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
DESTDIR=
|
||||
PREFIX=/usr
|
||||
BINDIR=$(PREFIX)/bin
|
||||
SBINDIR=$(PREFIX)/sbin
|
||||
MANDIR=$(PREFIX)/share/man
|
||||
MAN1DIR=$(MANDIR)/man1/
|
||||
|
|
@ -30,6 +31,8 @@ install: pvesm.1 pvesm.bash-completion pvesm.zsh-completion
|
|||
gzip -9 -n $(DESTDIR)$(MAN1DIR)/pvesm.1
|
||||
install -m 0644 -D pvesm.bash-completion $(DESTDIR)$(BASHCOMPLDIR)/pvesm
|
||||
install -m 0644 -D pvesm.zsh-completion $(DESTDIR)$(ZSHCOMPLDIR)/_pvesm
|
||||
install -d $(DESTDIR)$(BINDIR)
|
||||
install -m 0755 pvestord $(DESTDIR)$(BINDIR)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
|
|
|
|||
24
src/bin/pvestord
Executable file
24
src/bin/pvestord
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use PVE::INotify;
|
||||
use PVE::RPCEnvironment;
|
||||
use PVE::SafeSyslog;
|
||||
use PVE::Service::pvestord;
|
||||
|
||||
$SIG{'__WARN__'} = sub {
|
||||
my $err = $@;
|
||||
my $t = $_[0];
|
||||
chomp $t;
|
||||
print STDERR "$t\n";
|
||||
syslog('warning', "%s", $t);
|
||||
$@ = $err;
|
||||
};
|
||||
|
||||
my $prepare = sub {
|
||||
|
||||
};
|
||||
|
||||
PVE::Service::pvestord->run_cli_handler(prepare => $prepare);
|
||||
14
src/services/Makefile
Normal file
14
src/services/Makefile
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
SERVICEDIR=$(DESTDIR)/usr/lib/systemd/system
|
||||
|
||||
all:
|
||||
|
||||
SERVICES= pvestord.service
|
||||
|
||||
.PHONY: install
|
||||
install: $(SERVICES)
|
||||
install -d $(SERVICEDIR)
|
||||
install -m 0644 $(SERVICES) $(SERVICEDIR)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *~
|
||||
15
src/services/pvestord.service
Normal file
15
src/services/pvestord.service
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[Unit]
|
||||
Description=PVE Storage Monitor Daemon
|
||||
ConditionPathExists=/usr/bin/pvestord
|
||||
Wants=pve-cluster.service
|
||||
After=pve-cluster.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/pvestord start
|
||||
ExecStop=/usr/bin/pvestord stop
|
||||
ExecReload=/usr/bin/pvestord restart
|
||||
PIDFile=/run/pvestord.pid
|
||||
Type=forking
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue