@@ -408,6 +408,11 @@ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
$(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \
"GEN","$@")
+qga/qapi-generated/qga-qapi-event.c qga/qapi-generated/qga-qapi-event.h :\
+$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-event.py $(qapi-py)
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
+ $(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \
+ "GEN","$@")
qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \
$(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \
@@ -441,7 +446,7 @@ $(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
$(gen-out-type) -o "." $<, \
"GEN","$@")
-QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
+QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h qga-qapi-event.h)
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
qemu-ga$(EXESUF): $(qga-obj-y) $(COMMON_LDADDS)
@@ -3,6 +3,6 @@ qga-obj-$(CONFIG_POSIX) += commands-posix.o channel-posix.o
qga-obj-$(CONFIG_WIN32) += commands-win32.o channel-win32.o service-win32.o
qga-obj-$(CONFIG_WIN32) += vss-win32.o
qga-obj-y += qapi-generated/qga-qapi-types.o qapi-generated/qga-qapi-visit.o
-qga-obj-y += qapi-generated/qga-qmp-marshal.o
+qga-obj-y += qapi-generated/qga-qmp-marshal.o qapi-generated/qga-qapi-event.o
qga-vss-dll-obj-$(CONFIG_QGA_VSS) += vss-win32/
@@ -118,6 +118,14 @@ static int ga_channel_client_add(GAChannel *c, int fd)
return 0;
}
+gboolean ga_channel_client_attached(GAChannel *c)
+{
+ g_assert(c);
+ /* TODO: make this work with all methods. following works only with
+ * unix-listen */
+ return c->client_channel != NULL;
+}
+
static gboolean ga_channel_open(GAChannel *c, const gchar *path,
GAChannelMethod method, int fd)
{
@@ -315,6 +315,12 @@ static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method,
return true;
}
+gboolean ga_channel_client_attached(GAChannel *c)
+{
+ /* TODO: make this work with all methods */
+ return true;
+}
+
GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
int listen_fd, GAChannelCallback cb, gpointer opaque)
{
@@ -30,5 +30,6 @@ GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
void ga_channel_free(GAChannel *c);
GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count);
GIOStatus ga_channel_write_all(GAChannel *c, const gchar *buf, gsize size);
+gboolean ga_channel_client_attached(GAChannel *c);
#endif
@@ -13,6 +13,7 @@
#include "qapi/qmp/dispatch.h"
#include "qemu-common.h"
#include "qga-qmp-commands.h"
+#include "qga-qapi-event.h"
#define QGA_READ_COUNT_DEFAULT 4096
@@ -23,6 +23,8 @@
#include "qapi/qmp/qjson.h"
#include "qga/guest-agent-core.h"
#include "qemu/module.h"
+#include "qapi/qmp-event.h"
+#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
#include "qapi/qmp/dispatch.h"
#include "qga/channel.h"
@@ -674,6 +676,59 @@ static gboolean channel_event_cb(GIOCondition condition, gpointer data)
return true;
}
+/* TODO: HACK HACK HACK... can't we get a GAstate somehow? */
+QDict *queued_event;
+static void ga_event_emit(qga_QAPIEvent event, QDict *qdict, Error **errp)
+{
+ if (queued_event) {
+ error_setg(errp, "unsent event already waiting");
+ } else {
+ QINCREF(qdict);
+ queued_event = qdict;
+ }
+}
+/* HACK HACK HACK!!! */
+
+static gboolean monitoring_cb(gpointer data)
+{
+ Error *err = NULL;
+ GAState *s = (GAState *)data;
+
+ g_assert(s->channel);
+ g_warning("monitoring!");
+
+ if (!ga_channel_client_attached(s->channel)) {
+ goto ok;
+ }
+
+ /* TODO: call something */
+ goto ok;
+
+/*fail:*/
+ g_assert(err);
+ g_warning("%s", error_get_pretty(err));
+ error_free(err);
+
+ok:
+ /* Always return true. False would remove this callback. */
+ return true;
+}
+
+static gboolean monitoring_init(GAState *s)
+{
+ if (g_timeout_add_seconds(5, monitoring_cb, (gpointer)s) <= 0) {
+ g_error("failed to create monitoring timer");
+ goto fail;
+ }
+ g_debug("monitoring timer created");
+
+ qmp_event_set_func_emit(ga_event_emit);
+ return true;
+
+fail:
+ return false;
+}
+
static gboolean channel_init(GAState *s, const gchar *method, const gchar *path,
int listen_fd)
{
@@ -1330,6 +1385,10 @@ static int run_agent(GAState *s, GAConfig *config, int socket_activation)
g_critical("failed to initialize guest agent channel");
return EXIT_FAILURE;
}
+
+ /* TODO: error handling? */
+ monitoring_init(ga_state);
+
#ifndef _WIN32
g_main_loop_run(ga_state->main_loop);
#else
new file mode 100644
@@ -0,0 +1,2 @@
+# *-*- Mode: Python -*-*
+
@@ -1,5 +1,7 @@
# *-*- Mode: Python -*-*
+{ 'include': 'qapi-event.json' }
+
##
#
# General note concerning the use of guest agent interfaces:
Events can play an integral role when monitoring internal state of the guest OS. This patch adds the core functionality for adding events to QEMU Guest Agent. Signed-off-by: Tomáš Golembiovský <tgolembi@redhat.com> --- Makefile | 7 +++++- qga/Makefile.objs | 2 +- qga/channel-posix.c | 8 +++++++ qga/channel-win32.c | 6 +++++ qga/channel.h | 1 + qga/guest-agent-core.h | 1 + qga/main.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ qga/qapi-event.json | 2 ++ qga/qapi-schema.json | 2 ++ 9 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 qga/qapi-event.json