$timeout = 60*60; # 1 hour
} elsif ($cmd->{execute} =~ m/^(eject|change)/) {
$timeout = 60; # note: cdrom mount command is slow
+ } elsif ($cmd->{execute} eq 'guest-fsfreeze-freeze' ||
+ $cmd->{execute} eq 'guest-fsfreeze-thaw') {
+ $timeout = 10;
} elsif ($cmd->{execute} eq 'savevm-start' ||
$cmd->{execute} eq 'savevm-end' ||
$cmd->{execute} eq 'query-backup' ||
}
}
- $self->queue_execute($timeout);
-
+ $self->queue_execute($timeout, 2);
die "VM $vmid qmp command '$cmd->{execute}' failed - $queue_info->{error}"
if defined($queue_info->{error});
if (my $fh = delete $queue_info->{fh}) {
delete $self->{queue_lookup}->{$fh};
- $self->{mux}->close($fh);
+ $self->{mux}->close($fh);
}
};
if ($qga) {
- $qmpcmd = to_json({ execute => 'guest-sync', arguments => { id => int($cmd->{id})}}) .
+ $qmpcmd = to_json({ execute => 'guest-sync-delimited',
+ arguments => { id => int($cmd->{id})}}) .
to_json({ execute => $cmd->{execute}, arguments => $cmd->{arguments}});
} else {
};
# execute all queued command
+
sub queue_execute {
- my ($self, $timeout) = @_;
+ my ($self, $timeout, $noerr) = @_;
$timeout = 3 if !$timeout;
}
};
if (my $err = $@) {
- warn $err;
$queue_info->{error} = $err;
}
}
}
# make sure we close everything
+ my $errors = '';
foreach my $sname (keys %{$self->{queue_info}}) {
- &$close_connection($self, $self->{queue_info}->{$sname});
+ my $queue_info = $self->{queue_info}->{$sname};
+ &$close_connection($self, $queue_info);
+ if ($queue_info->{error}) {
+ if ($noerr) {
+ warn $queue_info->{error} if $noerr < 2;
+ } else {
+ $errors .= $queue_info->{error}
+ }
+ }
}
$self->{queue_info} = $self->{queue_lookup} = {};
+
+ die $errors if $errors;
}
sub mux_close {
if !$queue_info->{error};
}
-# mux_input is called when input is available on one of
-# the descriptors.
+# mux_input is called when input is available on one of the descriptors.
sub mux_input {
my ($self, $mux, $fh, $input) = @_;
my $raw;
if ($qga) {
- return if $$input !~ s/^([^\n]+}\n[^\n]+})\n(.*)$/$2/so;
+ return if $$input !~ s/^.*\xff([^\n]+}\r?\n[^\n]+})\r?\n(.*)$/$2/so;
$raw = $1;
} else {
- return if $$input !~ s/^([^\n]+})\r?\n(.*)$/$2/so;
+ return if $$input !~ s/^(.*})\r?\n(.*)$/$2/so;
$raw = $1;
}
die "response is not complete" if @jsons != 2 ;
my $obj = from_json($jsons[0]);
+
my $cmdid = $obj->{'return'};
die "received responsed without command id\n" if !$cmdid;
-
- delete $queue_info->{current};
+ # skip results fro previous commands
+ return if $cmdid < $curcmd->{id};
+
if ($curcmd->{id} ne $cmdid) {
die "got wrong command id '$cmdid' (expected $curcmd->{id})\n";
}
+ delete $queue_info->{current};
+
$obj = from_json($jsons[1]);
if (my $callback = $curcmd->{callback}) {
my $cmdid = $obj->{id};
die "received responsed without command id\n" if !$cmdid;
- delete $queue_info->{current};
-
if ($curcmd->{id} ne $cmdid) {
die "got wrong command id '$cmdid' (expected $curcmd->{id})\n";
}
+ delete $queue_info->{current};
+
if (my $callback = $curcmd->{callback}) {
&$callback($vmid, $obj);
}
if (my $queue_info = &$lookup_queue_info($self, $fh)) {
$queue_info->{error} = "got timeout\n";
+ $self->{mux}->inbuffer($fh, ''); # clear to avoid warnings
}
&$check_queue($self);
sub mux_eof {
my ($self, $mux, $fh, $input) = @_;
-
+
my $queue_info = &$lookup_queue_info($self, $fh);
return if !$queue_info;
if ($qga && $qga_allow_close_cmds->{$curcmd->{execute}}) {
- return if $$input !~ s/^([^\n]+})\n(.*)$/$2/so;
+ return if $$input !~ s/^.*\xff([^\n]+})\r?\n(.*)$/$2/so;
- my @jsons = split("\n", $1);
+ my $raw = $1;
- my $obj = from_json($jsons[0]);
+ eval {
+ my $obj = from_json($raw);
- my $cmdid = $obj->{'return'};
- die "received responsed without command id\n" if !$cmdid;
+ my $cmdid = $obj->{'return'};
+ die "received responsed without command id\n" if !$cmdid;
- delete $queue_info->{current};
+ delete $queue_info->{current};
+
+ if (my $callback = $curcmd->{callback}) {
+ &$callback($vmid, undef);
+ }
+ };
+ if (my $err = $@) {
+ $queue_info->{error} = $err;
+ }
&$close_connection($self, $queue_info);
+
+ if (scalar(@{$queue_info->{cmds}}) && !$queue_info->{error}) {
+ $queue_info->{error} = "Got EOF but command queue is not empty.\n";
+ }
}
}