},
};
+my $watchdog_fmt = {
+ model => {
+ default_key => 1,
+ type => 'string',
+ enum => [qw(i6300esb ib700)],
+ description => "Watchdog type to emulate.",
+ default => 'i6300esb',
+ optional => 1,
+ },
+ action => {
+ type => 'string',
+ enum => [qw(reset shutdown poweroff pause debug none)],
+ description => "The action to perform if after activation the guest fails to poll the watchdog in time.",
+ optional => 1,
+ },
+};
+PVE::JSONSchema::register_format('pve-qm-watchdog', $watchdog_fmt);
+
my $confdesc = {
onboot => {
optional => 1,
watchdog => {
optional => 1,
type => 'string', format => 'pve-qm-watchdog',
- typetext => '[[model=]i6300esb|ib700] [,[action=]reset|shutdown|poweroff|pause|debug|none]',
description => "Create a virtual hardware watchdog device. Once enabled" .
" (by a guest action), the watchdog must be periodically polled " .
"by an agent inside the guest or else the watchdog will reset " .
optional => 1,
type => 'string',
description => <<EODESCR,
-NOTE: this option is for experts only. It allows you to pass arbitrary arguments to kvm, for example:
+Arbitrary arguments passed to kvm, for example:
args: -no-reboot -no-hpet
+
+NOTE: this option is for experts only.
EODESCR
},
tablet => {
$confdesc->{"net$i"} = $netdesc;
}
-PVE::JSONSchema::register_format('pve-volume-id-or-none', \&verify_volume_id_or_none);
-sub verify_volume_id_or_none {
+PVE::JSONSchema::register_format('pve-volume-id-or-qm-path', \&verify_volume_id_or_qm_path);
+sub verify_volume_id_or_qm_path {
my ($volid, $noerr) = @_;
- return $volid if $volid eq 'none';
+ if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m|^/|) {
+ return $volid;
+ }
+
+ # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
$volid = eval { PVE::JSONSchema::check_format('pve-volume-id', $volid, '') };
if ($@) {
return undef if $noerr;
volume => { alias => 'file' },
file => {
type => 'string',
- format => 'pve-volume-id-or-none',
+ format => 'pve-volume-id-or-qm-path',
default_key => 1,
format_description => 'volume',
description => "The drive's backing volume.",
die "unable to parse network options\n";
}
-PVE::JSONSchema::register_format('pve-qm-watchdog', \&verify_watchdog);
-sub verify_watchdog {
- my ($value, $noerr) = @_;
-
- return $value if parse_watchdog($value);
-
- return undef if $noerr;
-
- die "unable to parse watchdog options\n";
-}
-
sub parse_watchdog {
my ($value) = @_;
return undef if !$value;
- my $res = {};
-
- foreach my $p (split(/,/, $value)) {
- next if $p =~ m/^\s*$/;
-
- if ($p =~ m/^(model=)?(i6300esb|ib700)$/) {
- $res->{model} = $2;
- } elsif ($p =~ m/^(action=)?(reset|shutdown|poweroff|pause|debug|none)$/) {
- $res->{action} = $2;
- } else {
- return undef;
- }
- }
-
+ my $res = eval { PVE::JSONSchema::parse_property_string($watchdog_fmt, $value) };
+ warn $@ if $@;
return $res;
}
print "drive mirror is starting (scanning bitmap) : this step can take some minutes/hours, depend of disk size and storage speed\n";
+ my $finish_job = sub {
+ while (1) {
+ my $stats = vm_mon_cmd($vmid, "query-block-jobs");
+ my $stat = @$stats[0];
+ last if !$stat;
+ sleep 1;
+ }
+ };
+
eval {
vm_mon_cmd($vmid, "drive-mirror", %$opts);
while (1) {
# try to switch the disk if source and destination are on the same guest
eval { vm_mon_cmd($vmid, "block-job-complete", device => "drive-$drive") };
- last if !$@;
+ if (!$@) {
+ &$finish_job();
+ last;
+ }
die $@ if $@ !~ m/cannot be completed/;
}
sleep 1;
my $cancel_job = sub {
vm_mon_cmd($vmid, "block-job-cancel", device => "drive-$drive");
- while (1) {
- my $stats = vm_mon_cmd($vmid, "query-block-jobs");
- my $stat = @$stats[0];
- last if !$stat;
- sleep 1;
- }
+ &$finish_job();
};
if ($err) {