Discussion:
[pve-devel] [PATCH] add qemu guest agent client
Alexandre Derumier
2012-09-04 07:04:35 UTC
Permalink
This implement qemu guest agent client.

I Have take the qmp client code and try to adapt it.

We cannot pass id in the quest agent client,so I always execute

{ "execute": "guest-sync", "arguments": { "id": sequenceid } }
before each command

exemple:
sending commands
---------------
{ "execute": "guest-sync", "arguments": { "id": 123456 } }
{"execute":"guest-ping"}

parse result
------------
{ "return": 123456}\n{"return": {}}

I don't know if it's the right way, so please review code.

Signed-off-by: Alexandre Derumier <***@odiso.com>
---
PVE/Makefile | 5 +-
PVE/QGAClient.pm | 279 +++++++++++++++++++++++++++++++++++++++++++++++++++++
PVE/QemuServer.pm | 38 +++++++
3 files changed, 320 insertions(+), 2 deletions(-)
create mode 100755 PVE/QGAClient.pm

diff --git a/PVE/Makefile b/PVE/Makefile
index 232c881..8a70aeb 100644
--- a/PVE/Makefile
+++ b/PVE/Makefile
@@ -1,11 +1,12 @@
PERLSOURCE = \
QemuServer.pm \
QemuMigrate.pm \
- QMPClient.pm
+ QMPClient.pm \
+ QGAClient.pm

.PHONY: install
install:
install -d ${DESTDIR}${PERLDIR}/PVE
install -m 0644 ${PERLSOURCE} ${DESTDIR}${PERLDIR}/PVE/
make -C VZDump install
- make -C API2 install
\ No newline at end of file
+ make -C API2 install
diff --git a/PVE/QGAClient.pm b/PVE/QGAClient.pm
new file mode 100755
index 0000000..8880b5a
--- /dev/null
+++ b/PVE/QGAClient.pm
@@ -0,0 +1,279 @@
+package PVE::QGAClient;
+
+use strict;
+use PVE::QemuServer;
+use IO::Multiplex;
+use POSIX qw(EINTR EAGAIN);
+use JSON;
+use Time::HiRes qw(usleep gettimeofday tv_interval);
+
+use Data::Dumper;
+
+# Qemu Guest Agent client.
+#
+# This implementation uses IO::Multiplex (libio-multiplex-perl) and
+# allows you to issue quest agent commands to different VMs in parallel.
+
+# Note: kvm can onyl handle 1 connection, so we close connections asap
+
+sub new {
+ my ($class, $eventcb) = @_;
+
+ my $mux = new IO::Multiplex;
+
+ my $self = bless {
+ mux => $mux,
+ fhs => {}, # $vmid => fh
+ fhs_lookup => {}, # $fh => $vmid
+ queue => {},
+ current => {},
+ errors => {},
+ }, $class;
+
+ $self->{eventcb} = $eventcb if $eventcb;
+
+ $mux->set_callback_object($self);
+
+ return $self;
+}
+
+# add a single command to the queue for later execution
+# with queue_execute()
+sub queue_cmd {
+ my ($self, $vmid, $callback, $execute, %params) = @_;
+
+ my $cmd = {};
+ $cmd->{execute} = $execute;
+ $cmd->{arguments} = \%params;
+ $cmd->{callback} = $callback;
+
+ push @{$self->{queue}->{$vmid}}, $cmd;
+}
+
+# execute a single command
+sub cmd {
+ my ($self, $vmid, $cmd, $timeout) = @_;
+
+ my $result;
+
+ my $callback = sub {
+ my ($vmid, $resp) = @_;
+ $result = $resp->{'return'};
+ };
+
+ die "no command specified" if !($cmd && $cmd->{execute});
+
+ $cmd->{callback} = $callback;
+ $cmd->{arguments} = {} if !defined($cmd->{arguments});
+
+ $self->{queue}->{$vmid} = [ $cmd ];
+
+ if (!$timeout) {
+ $timeout = 3; # default
+ }
+
+ $self->queue_execute($timeout);
+
+ my $cmdstr = $cmd->{execute} || '';
+ die "VM $vmid qmp command '$cmdstr' failed - $self->{errors}->{$vmid}"
+ if defined($self->{errors}->{$vmid});
+
+ return $result;
+};
+
+my $cmdid_seq = 0;
+my $next_cmdid = sub {
+ $cmdid_seq++;
+ return "$cmdid_seq";
+};
+
+my $close_connection = sub {
+ my ($self, $vmid) = @_;
+
+ my $fh = $self->{fhs}->{$vmid};
+ return if !$fh;
+
+ delete $self->{fhs}->{$vmid};
+ delete $self->{fhs_lookup}->{$fh};
+
+ $self->{mux}->close($fh);
+};
+
+my $open_connection = sub {
+ my ($self, $vmid) = @_;
+
+ my $sname = PVE::QemuServer::qga_socket($vmid);
+
+ my $fh;
+ my $starttime = [gettimeofday];
+ my $count = 0;
+ for (;;) {
+ $count++;
+ $fh = IO::Socket::UNIX->new(Peer => $sname, Blocking => 0, Timeout => 1);
+ last if $fh;
+ if ($! != EINTR && $! != EAGAIN) {
+ die "unable to connect to VM $vmid socket - $!\n";
+ }
+ my $elapsed = tv_interval($starttime, [gettimeofday]);
+ if ($elapsed > 1) {
+ die "unable to connect to VM $vmid socket - timeout after $count retries\n";
+ }
+ usleep(100000);
+ }
+
+ $self->{fhs}->{$vmid} = $fh;
+ $self->{fhs_lookup}->{$fh} = $vmid;
+ $self->{mux}->add($fh);
+
+ return $fh;
+};
+
+my $check_queue = sub {
+ my ($self) = @_;
+
+ my $running = 0;
+
+ foreach my $vmid (keys %{$self->{queue}}) {
+ my $fh = $self->{fhs}->{$vmid};
+ next if !$fh;
+
+ if ($self->{errors}->{$vmid}) {
+ &$close_connection($self, $vmid);
+ next;
+ }
+
+ if ($self->{current}->{$vmid}) { # command running, waiting for response
+ $running++;
+ next;
+ }
+
+ if (!scalar(@{$self->{queue}->{$vmid}})) { # no more commands for the VM
+ &$close_connection($self, $vmid);
+ next;
+ }
+
+ eval {
+
+ my $cmd = $self->{current}->{$vmid} = shift @{$self->{queue}->{$vmid}};
+ $cmd->{id} = &$next_cmdid();
+
+ my $qmpcmdid =to_json({
+ execute => 'guest-sync',
+ arguments => { id => int($cmd->{id}) } });
+
+ my $qmpcmd = to_json({
+ execute => $cmd->{execute},
+ arguments => $cmd->{arguments}});
+
+ $self->{mux}->write($fh, $qmpcmdid.$qmpcmd);
+ };
+ if (my $err = $@) {
+ $self->{errors}->{$vmid} = $err;
+ } else {
+ $running++;
+ }
+ }
+
+ $self->{mux}->endloop() if !$running;
+
+ return $running;
+};
+
+# execute all queued command
+sub queue_execute {
+ my ($self, $timeout) = @_;
+
+ $timeout = 3 if !$timeout;
+
+ $self->{current} = {};
+ $self->{errors} = {};
+
+ # open all necessary connections
+ foreach my $vmid (keys %{$self->{queue}}) {
+ next if !scalar(@{$self->{queue}->{$vmid}}); # no commands for the VM
+
+ eval {
+ my $fh = &$open_connection($self, $vmid);
+ $self->{mux}->set_timeout($fh, $timeout);
+ };
+ if (my $err = $@) {
+ warn $err;
+ $self->{errors}->{$vmid} = $err;
+ }
+ }
+
+ my $running;
+ for (;;) {
+
+ $running = &$check_queue($self);
+
+ last if !$running;
+
+ $self->{mux}->loop;
+ }
+
+ # make sure we close everything
+ foreach my $vmid (keys %{$self->{fhs}}) {
+ &$close_connection($self, $vmid);
+ }
+
+ $self->{queue} = $self->{current} = $self->{fhs} = $self->{fhs_lookup} = {};
+}
+
+# mux_input is called when input is available on one of
+# the descriptors.
+sub mux_input {
+ my ($self, $mux, $fh, $input) = @_;
+
+ return if $$input !~ m/}\n(.+)}\n$/;
+ my $raw = $$input;
+ # Remove the input from the input buffer.
+ $$input = '';
+ my $vmid = $self->{fhs_lookup}->{$fh};
+ if (!$vmid) {
+ warn "internal error - unable to lookup vmid";
+ return;
+ }
+ eval {
+ my @jsons = split("\n", $raw);
+
+ my $obj = from_json($jsons[0]);
+
+ my $curcmd = $self->{current}->{$vmid};
+ die "unable to lookup current command for VM $vmid\n" if (!$curcmd);
+
+ my $cmdid = $obj->{return};
+ die "received responsed without command id\n" if !$cmdid;
+
+ if ($curcmd->{id} ne $cmdid) {
+ die "got wrong command id '$cmdid' (expected $curcmd->{id})\n";
+ }
+
+ delete $self->{current}->{$vmid};
+
+ $obj = from_json($jsons[1]);
+
+ if (my $callback = $curcmd->{callback}) {
+ &$callback($vmid, $obj);
+ }
+
+ };
+ if (my $err = $@) {
+ $self->{errors}->{$vmid} = $err;
+ }
+
+ &$check_queue($self);
+}
+
+# This gets called every second to update player info, etc...
+sub mux_timeout {
+ my ($self, $mux, $fh) = @_;
+
+ if (my $vmid = $self->{fhs_lookup}->{$fh}) {
+ $self->{errors}->{$vmid} = "got timeout\n";
+ }
+
+ &$check_queue($self);
+}
+
+1;
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index bb0be42..c412283 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -26,6 +26,7 @@ use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file
use PVE::INotify;
use PVE::ProcFSTools;
use PVE::QMPClient;
+use PVE::QGAClient;
use Time::HiRes qw(gettimeofday);

my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
@@ -2840,6 +2841,13 @@ sub vm_start {
});
}

+sub vm_qga_cmd {
+ my ($vmid, $execute, %params) = @_;
+
+ my $cmd = { execute => $execute, arguments => \%params };
+ vm_qga_command($vmid, $cmd);
+}
+
sub vm_mon_cmd {
my ($vmid, $execute, %params) = @_;

@@ -2888,6 +2896,36 @@ sub vm_qmp_command {
return $res;
}

+sub vm_qga_command {
+ my ($vmid, $cmd) = @_;
+
+ my $res;
+
+ my $timeout;
+ if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
+ $timeout = $cmd->{arguments}->{timeout};
+ delete $cmd->{arguments}->{timeout};
+ }
+
+ eval {
+ die "VM $vmid not running\n" if !check_running($vmid);
+ my $sname = PVE::QemuServer::qga_socket($vmid);
+ if (-e $sname) {
+ my $qgaclient = PVE::QGAClient->new();
+
+ $res = $qgaclient->cmd($vmid, $cmd, $timeout);
+ } else {
+ die "unable to open qga socket\n";
+ }
+ };
+ if (my $err = $@) {
+ syslog("err", "VM $vmid qga command failed - $err");
+ die $err;
+ }
+
+ return $res;
+}
+
sub vm_human_monitor_command {
my ($vmid, $cmdline) = @_;
--
1.7.2.5
Dietmar Maurer
2012-09-04 12:24:43 UTC
Permalink
Documentation states that we can do all those thing via qmp in future! So why
do we want to add all that code now?
-----Original Message-----
Sent: Dienstag, 04. September 2012 09:05
Subject: [pve-devel] [PATCH] add qemu guest agent client
This implement qemu guest agent client.
Alexandre DERUMIER
2012-09-04 13:28:27 UTC
Permalink
Oh I miss that !

"
When QAPI-based QMP is available (somewhere around the QEMU 0.16 timeframe), a different host-side invocation that doesn't involve access to the guest agent outside of QMP will be used. Something like:

qemu \
...
-chardev qga_proxy,id=qga0 \
-device virtio-serial \
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
-qmp tcp:localhost:4444,server
"


So we just need to reuse qmp socket.
Is it already implemented ? (wiki is old, qemu 0.16....).

I'll do some tests


----- Mail original -----

De: "Dietmar Maurer" <***@proxmox.com>
À: "Alexandre Derumier" <***@odiso.com>, pve-***@pve.proxmox.com
Envoyé: Mardi 4 Septembre 2012 14:24:43
Objet: RE: [pve-devel] [PATCH] add qemu guest agent client

Documentation states that we can do all those thing via qmp in future! So why
do we want to add all that code now?
-----Original Message-----
Sent: Dienstag, 04. September 2012 09:05
Subject: [pve-devel] [PATCH] add qemu guest agent client
This implement qemu guest agent client.
Alexandre DERUMIER
2012-09-05 03:57:26 UTC
Permalink
just tested with -chardev qga_proxy,id=qga0

chardev: backend "qga_proxy" not found

so it's not implemented yet.
(I don't know if it's on the qemu roamap, I didn't find any info)

So Do you need to implemented the current procotol ?
(We need guest agent to freeze filesystem for snapshots

----- Mail original -----

De: "Alexandre DERUMIER" <***@odiso.com>
À: "Dietmar Maurer" <***@proxmox.com>
Cc: pve-***@pve.proxmox.com
Envoyé: Mardi 4 Septembre 2012 15:28:27
Objet: Re: [pve-devel] [PATCH] add qemu guest agent client

Oh I miss that !

"
When QAPI-based QMP is available (somewhere around the QEMU 0.16 timeframe), a different host-side invocation that doesn't involve access to the guest agent outside of QMP will be used. Something like:

qemu \
...
-chardev qga_proxy,id=qga0 \
-device virtio-serial \
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
-qmp tcp:localhost:4444,server
"


So we just need to reuse qmp socket.
Is it already implemented ? (wiki is old, qemu 0.16....).

I'll do some tests


----- Mail original -----

De: "Dietmar Maurer" <***@proxmox.com>
À: "Alexandre Derumier" <***@odiso.com>, pve-***@pve.proxmox.com
Envoyé: Mardi 4 Septembre 2012 14:24:43
Objet: RE: [pve-devel] [PATCH] add qemu guest agent client

Documentation states that we can do all those thing via qmp in future! So why
do we want to add all that code now?
-----Original Message-----
Sent: Dienstag, 04. September 2012 09:05
Subject: [pve-devel] [PATCH] add qemu guest agent client
This implement qemu guest agent client.
_______________________________________________
pve-devel mailing list
pve-***@pve.proxmox.com
http://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
Dietmar Maurer
2012-09-05 04:57:20 UTC
Permalink
Post by Alexandre DERUMIER
chardev: backend "qga_proxy" not found
so it's not implemented yet.
(I don't know if it's on the qemu roamap, I didn't find any info)
So Do you need to implemented the current procotol ?
(We need guest agent to freeze filesystem for snapshots
I just want to avoid unnecessary work. So please can you ask on
the qemu-devel mailing list if they plan to implement qga_proxy soon?
Dietmar Maurer
2012-09-05 07:47:40 UTC
Permalink
Subject: [pve-devel] [PATCH] add qemu guest agent client
This implement qemu guest agent client.
I Have take the qmp client code and try to adapt it.
Isn't there a way to reuse the qmp code? What exactly is the difference between
QMP and QGA protocol? Can't we use a common base class?
Alexandre DERUMIER
2012-09-05 08:29:54 UTC
Permalink
yes, It should be possible


main differences :

- we can't send "id" to a qmp comamnd. (so I sent guest-sync with sequence id before each command)
note that this id must be a integer, for in my code, I don't sent the vmid $$:$cmdid_seq, but only $cmdid_seq
- the returned json finish by "}\n" and not "}\r\n"
- we don't need to send qmp_capabilities at the connection opening


you can make a diff between qgaclient and qmpclient, I didn't have make too much changes.



----- Mail original -----

De: "Dietmar Maurer" <***@proxmox.com>
À: "Alexandre Derumier" <***@odiso.com>, pve-***@pve.proxmox.com
Envoyé: Mercredi 5 Septembre 2012 09:47:40
Objet: RE: [pve-devel] [PATCH] add qemu guest agent client
Subject: [pve-devel] [PATCH] add qemu guest agent client
This implement qemu guest agent client.
I Have take the qmp client code and try to adapt it.
Isn't there a way to reuse the qmp code? What exactly is the difference between
QMP and QGA protocol? Can't we use a common base class?
Stefan Priebe - Profihost AG
2012-11-23 08:22:43 UTC
Permalink
Hello,

the QGA Support in QemuServer.pm was added but the guest agent client isn't.

Is there any status on this one?

Thanks!

greets,
Stefan
Post by Alexandre Derumier
This implement qemu guest agent client.
I Have take the qmp client code and try to adapt it.
We cannot pass id in the quest agent client,so I always execute
{ "execute": "guest-sync", "arguments": { "id": sequenceid } }
before each command
sending commands
---------------
{ "execute": "guest-sync", "arguments": { "id": 123456 } }
{"execute":"guest-ping"}
parse result
------------
{ "return": 123456}\n{"return": {}}
I don't know if it's the right way, so please review code.
---
PVE/Makefile | 5 +-
PVE/QGAClient.pm | 279 +++++++++++++++++++++++++++++++++++++++++++++++++++++
PVE/QemuServer.pm | 38 +++++++
3 files changed, 320 insertions(+), 2 deletions(-)
create mode 100755 PVE/QGAClient.pm
diff --git a/PVE/Makefile b/PVE/Makefile
index 232c881..8a70aeb 100644
--- a/PVE/Makefile
+++ b/PVE/Makefile
@@ -1,11 +1,12 @@
PERLSOURCE = \
QemuServer.pm \
QemuMigrate.pm \
- QMPClient.pm
+ QMPClient.pm \
+ QGAClient.pm
.PHONY: install
install -d ${DESTDIR}${PERLDIR}/PVE
install -m 0644 ${PERLSOURCE} ${DESTDIR}${PERLDIR}/PVE/
make -C VZDump install
- make -C API2 install
\ No newline at end of file
+ make -C API2 install
diff --git a/PVE/QGAClient.pm b/PVE/QGAClient.pm
new file mode 100755
index 0000000..8880b5a
--- /dev/null
+++ b/PVE/QGAClient.pm
@@ -0,0 +1,279 @@
+package PVE::QGAClient;
+
+use strict;
+use PVE::QemuServer;
+use IO::Multiplex;
+use POSIX qw(EINTR EAGAIN);
+use JSON;
+use Time::HiRes qw(usleep gettimeofday tv_interval);
+
+use Data::Dumper;
+
+# Qemu Guest Agent client.
+#
+# This implementation uses IO::Multiplex (libio-multiplex-perl) and
+# allows you to issue quest agent commands to different VMs in parallel.
+
+# Note: kvm can onyl handle 1 connection, so we close connections asap
+
+sub new {
+
+ my $mux = new IO::Multiplex;
+
+ my $self = bless {
+ mux => $mux,
+ fhs => {}, # $vmid => fh
+ fhs_lookup => {}, # $fh => $vmid
+ queue => {},
+ current => {},
+ errors => {},
+ }, $class;
+
+ $self->{eventcb} = $eventcb if $eventcb;
+
+ $mux->set_callback_object($self);
+
+ return $self;
+}
+
+# add a single command to the queue for later execution
+# with queue_execute()
+sub queue_cmd {
+
+ my $cmd = {};
+ $cmd->{execute} = $execute;
+ $cmd->{arguments} = \%params;
+ $cmd->{callback} = $callback;
+
+}
+
+# execute a single command
+sub cmd {
+
+ my $result;
+
+ my $callback = sub {
+ $result = $resp->{'return'};
+ };
+
+ die "no command specified" if !($cmd && $cmd->{execute});
+
+ $cmd->{callback} = $callback;
+ $cmd->{arguments} = {} if !defined($cmd->{arguments});
+
+ $self->{queue}->{$vmid} = [ $cmd ];
+
+ if (!$timeout) {
+ $timeout = 3; # default
+ }
+
+ $self->queue_execute($timeout);
+
+ my $cmdstr = $cmd->{execute} || '';
+ die "VM $vmid qmp command '$cmdstr' failed - $self->{errors}->{$vmid}"
+ if defined($self->{errors}->{$vmid});
+
+ return $result;
+};
+
+my $cmdid_seq = 0;
+my $next_cmdid = sub {
+ $cmdid_seq++;
+ return "$cmdid_seq";
+};
+
+my $close_connection = sub {
+
+ my $fh = $self->{fhs}->{$vmid};
+ return if !$fh;
+
+ delete $self->{fhs}->{$vmid};
+ delete $self->{fhs_lookup}->{$fh};
+
+ $self->{mux}->close($fh);
+};
+
+my $open_connection = sub {
+
+ my $sname = PVE::QemuServer::qga_socket($vmid);
+
+ my $fh;
+ my $starttime = [gettimeofday];
+ my $count = 0;
+ for (;;) {
+ $count++;
+ $fh = IO::Socket::UNIX->new(Peer => $sname, Blocking => 0, Timeout => 1);
+ last if $fh;
+ if ($! != EINTR && $! != EAGAIN) {
+ die "unable to connect to VM $vmid socket - $!\n";
+ }
+ my $elapsed = tv_interval($starttime, [gettimeofday]);
+ if ($elapsed > 1) {
+ die "unable to connect to VM $vmid socket - timeout after $count retries\n";
+ }
+ usleep(100000);
+ }
+
+ $self->{fhs}->{$vmid} = $fh;
+ $self->{fhs_lookup}->{$fh} = $vmid;
+ $self->{mux}->add($fh);
+
+ return $fh;
+};
+
+my $check_queue = sub {
+
+ my $running = 0;
+
+ foreach my $vmid (keys %{$self->{queue}}) {
+ my $fh = $self->{fhs}->{$vmid};
+ next if !$fh;
+
+ if ($self->{errors}->{$vmid}) {
+ &$close_connection($self, $vmid);
+ next;
+ }
+
+ if ($self->{current}->{$vmid}) { # command running, waiting for response
+ $running++;
+ next;
+ }
+
+ &$close_connection($self, $vmid);
+ next;
+ }
+
+ eval {
+
+ $cmd->{id} = &$next_cmdid();
+
+ my $qmpcmdid =to_json({
+ execute => 'guest-sync',
+ arguments => { id => int($cmd->{id}) } });
+
+ my $qmpcmd = to_json({
+ execute => $cmd->{execute},
+ arguments => $cmd->{arguments}});
+
+ $self->{mux}->write($fh, $qmpcmdid.$qmpcmd);
+ };
+ $self->{errors}->{$vmid} = $err;
+ } else {
+ $running++;
+ }
+ }
+
+ $self->{mux}->endloop() if !$running;
+
+ return $running;
+};
+
+# execute all queued command
+sub queue_execute {
+
+ $timeout = 3 if !$timeout;
+
+ $self->{current} = {};
+ $self->{errors} = {};
+
+ # open all necessary connections
+ foreach my $vmid (keys %{$self->{queue}}) {
+
+ eval {
+ my $fh = &$open_connection($self, $vmid);
+ $self->{mux}->set_timeout($fh, $timeout);
+ };
+ warn $err;
+ $self->{errors}->{$vmid} = $err;
+ }
+ }
+
+ my $running;
+ for (;;) {
+
+ $running = &$check_queue($self);
+
+ last if !$running;
+
+ $self->{mux}->loop;
+ }
+
+ # make sure we close everything
+ foreach my $vmid (keys %{$self->{fhs}}) {
+ &$close_connection($self, $vmid);
+ }
+
+ $self->{queue} = $self->{current} = $self->{fhs} = $self->{fhs_lookup} = {};
+}
+
+# mux_input is called when input is available on one of
+# the descriptors.
+sub mux_input {
+
+ return if $$input !~ m/}\n(.+)}\n$/;
+ my $raw = $$input;
+ # Remove the input from the input buffer.
+ $$input = '';
+ my $vmid = $self->{fhs_lookup}->{$fh};
+ if (!$vmid) {
+ warn "internal error - unable to lookup vmid";
+ return;
+ }
+ eval {
+
+ my $obj = from_json($jsons[0]);
+
+ my $curcmd = $self->{current}->{$vmid};
+ die "unable to lookup current command for VM $vmid\n" if (!$curcmd);
+
+ my $cmdid = $obj->{return};
+ die "received responsed without command id\n" if !$cmdid;
+
+ if ($curcmd->{id} ne $cmdid) {
+ die "got wrong command id '$cmdid' (expected $curcmd->{id})\n";
+ }
+
+ delete $self->{current}->{$vmid};
+
+ $obj = from_json($jsons[1]);
+
+ if (my $callback = $curcmd->{callback}) {
+ &$callback($vmid, $obj);
+ }
+
+ };
+ $self->{errors}->{$vmid} = $err;
+ }
+
+ &$check_queue($self);
+}
+
+# This gets called every second to update player info, etc...
+sub mux_timeout {
+
+ if (my $vmid = $self->{fhs_lookup}->{$fh}) {
+ $self->{errors}->{$vmid} = "got timeout\n";
+ }
+
+ &$check_queue($self);
+}
+
+1;
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index bb0be42..c412283 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -26,6 +26,7 @@ use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file
use PVE::INotify;
use PVE::ProcFSTools;
use PVE::QMPClient;
+use PVE::QGAClient;
use Time::HiRes qw(gettimeofday);
my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
@@ -2840,6 +2841,13 @@ sub vm_start {
});
}
+sub vm_qga_cmd {
+
+ my $cmd = { execute => $execute, arguments => \%params };
+ vm_qga_command($vmid, $cmd);
+}
+
sub vm_mon_cmd {
@@ -2888,6 +2896,36 @@ sub vm_qmp_command {
return $res;
}
+sub vm_qga_command {
+
+ my $res;
+
+ my $timeout;
+ if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
+ $timeout = $cmd->{arguments}->{timeout};
+ delete $cmd->{arguments}->{timeout};
+ }
+
+ eval {
+ die "VM $vmid not running\n" if !check_running($vmid);
+ my $sname = PVE::QemuServer::qga_socket($vmid);
+ if (-e $sname) {
+ my $qgaclient = PVE::QGAClient->new();
+
+ $res = $qgaclient->cmd($vmid, $cmd, $timeout);
+ } else {
+ die "unable to open qga socket\n";
+ }
+ };
+ syslog("err", "VM $vmid qga command failed - $err");
+ die $err;
+ }
+
+ return $res;
+}
+
sub vm_human_monitor_command {
Dietmar Maurer
2012-11-23 08:26:25 UTC
Permalink
Post by Stefan Priebe - Profihost AG
the QGA Support in QemuServer.pm was added
No, that code was not added.
Alexandre DERUMIER
2012-11-23 08:32:29 UTC
Permalink
Post by Stefan Priebe - Profihost AG
Post by Dietmar Maurer
No, that code was not added.
Yes indeed, it was not enough clean ;)


also, old wiki :
http://wiki.qemu.org/Features/QAPI/GuestAgent
said that some kind of qmp proxy, will be integrated in the future, to reuse qmp client

-chardev qga_proxy,id=qga0 \

But nothing has been done yet currently in qemu.git.

----- Mail original -----

De: "Dietmar Maurer" <***@proxmox.com>
À: "Stefan Priebe - Profihost AG" <***@profihost.ag>, "Alexandre Derumier" <***@odiso.com>
Cc: pve-***@pve.proxmox.com
Envoyé: Vendredi 23 Novembre 2012 09:26:25
Objet: RE: [pve-devel] [PATCH] add qemu guest agent client
Post by Stefan Priebe - Profihost AG
the QGA Support in QemuServer.pm was added
No, that code was not added.
Alexandre DERUMIER
2012-11-23 09:52:21 UTC
Permalink
I'm also not sure we need multiplexing for guest-agent qmp.


----- Mail original -----

De: "Alexandre DERUMIER" <***@odiso.com>
À: "Dietmar Maurer" <***@proxmox.com>
Cc: pve-***@pve.proxmox.com
Envoyé: Vendredi 23 Novembre 2012 09:32:29
Objet: Re: [pve-devel] [PATCH] add qemu guest agent client
Post by Stefan Priebe - Profihost AG
Post by Dietmar Maurer
No, that code was not added.
Yes indeed, it was not enough clean ;)


also, old wiki :
http://wiki.qemu.org/Features/QAPI/GuestAgent
said that some kind of qmp proxy, will be integrated in the future, to reuse qmp client

-chardev qga_proxy,id=qga0 \

But nothing has been done yet currently in qemu.git.

----- Mail original -----

De: "Dietmar Maurer" <***@proxmox.com>
À: "Stefan Priebe - Profihost AG" <***@profihost.ag>, "Alexandre Derumier" <***@odiso.com>
Cc: pve-***@pve.proxmox.com
Envoyé: Vendredi 23 Novembre 2012 09:26:25
Objet: RE: [pve-devel] [PATCH] add qemu guest agent client
Post by Stefan Priebe - Profihost AG
the QGA Support in QemuServer.pm was added
No, that code was not added.
_______________________________________________
pve-devel mailing list
pve-***@pve.proxmox.com
http://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Loading...