Signed-off-by: MATSUDA Daiki <matsudadik(a)intellilink.co.jp>
---
tools/virsh-host.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/virsh.pod | 13 +++++++
2 files changed, 102 insertions(+), 0 deletions(-)
diff --git a/tools/virsh-host.c b/tools/virsh-host.c
index b09d9f9..682d374 100644
--- a/tools/virsh-host.c
+++ b/tools/virsh-host.c
@@ -633,6 +633,93 @@ cleanup:
}
/*
+ * "qemu-agent-command" command
+ */
+static const vshCmdInfo info_qemu_agent_command[] = {
+ {"help", N_("QEMU Guest Agent Command")},
+ {"desc", N_("Run an arbitrary qemu guest agent command; use at your
own risk")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_qemu_agent_command[] = {
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or
uuid")},
+ {"timeout", VSH_OT_INT, VSH_OFLAG_REQ_OPT, N_("timeout seconds. must
be positive.")},
+ {"async", VSH_OT_BOOL, 0, N_("execute command without waiting for
timeout")},
+ {"block", VSH_OT_BOOL, 0, N_("execute command without
timeout")},
+ {"cmd", VSH_OT_ARGV, VSH_OFLAG_REQ, N_("command")},
+ {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdQemuAgentCommand(vshControl *ctl, const vshCmd *cmd)
+{
+ virDomainPtr dom = NULL;
+ bool ret = false;
+ char *guest_agent_cmd = NULL;
+ char *result = NULL;
+ int timeout = VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT;
+ int judge = 0;
+ unsigned int flags = 0;
+ const vshCmdOpt *opt = NULL;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ bool pad = false;
+
+ if (!vshConnectionUsability(ctl, ctl->conn))
+ goto cleanup;
+
+ dom = vshCommandOptDomain(ctl, cmd, NULL);
+ if (dom == NULL)
+ goto cleanup;
+
+ while ((opt = vshCommandOptArgv(cmd, opt))) {
+ if (pad)
+ virBufferAddChar(&buf, ' ');
+ pad = true;
+ virBufferAdd(&buf, opt->data, -1);
+ }
+ if (virBufferError(&buf)) {
+ vshPrint(ctl, "%s", _("Failed to collect command"));
+ goto cleanup;
+ }
+ guest_agent_cmd = virBufferContentAndReset(&buf);
+
+ judge = vshCommandOptInt(cmd, "timeout", &timeout);
+ if (judge < 0) {
+ vshError(ctl, "%s", _("timeout number has to be a number"));
+ } else if (judge > 0) {
+ judge = 1;
+ }
+ if (judge && timeout < 1) {
+ vshError(ctl, "%s", _("timeout must be positive"));
+ }
+
+ if (vshCommandOptBool(cmd, "async")) {
+ timeout = VIR_DOMAIN_QEMU_AGENT_COMMAND_NOWAIT;
+ judge++;
+ }
+ if (vshCommandOptBool(cmd, "block")) {
+ timeout = VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK;
+ judge++;
+ }
+
+ if (judge > 1) {
+ vshError(ctl, "%s", _("timeout, async and block options are
exclusive"));
+ }
+ result = virDomainQemuAgentCommand(dom, guest_agent_cmd, timeout, flags);
+
+ if (result) printf("%s\n", result);
+
+ ret = true;
+
+cleanup:
+ VIR_FREE(result);
+ VIR_FREE(guest_agent_cmd);
+ if (dom)
+ virDomainFree(dom);
+
+ return ret;
+}
+/*
* "sysinfo" command
*/
static const vshCmdInfo info_sysinfo[] = {
@@ -832,6 +919,8 @@ static const vshCmdDef hostAndHypervisorCmds[] = {
{"qemu-attach", cmdQemuAttach, opts_qemu_attach, info_qemu_attach, 0},
{"qemu-monitor-command", cmdQemuMonitorCommand, opts_qemu_monitor_command,
info_qemu_monitor_command, 0},
+ {"qemu-agent-command", cmdQemuAgentCommand, opts_qemu_agent_command,
+ info_qemu_agent_command, 0},
{"sysinfo", cmdSysinfo, NULL, info_sysinfo, 0},
{"uri", cmdURI, NULL, info_uri, 0},
{"version", cmdVersion, opts_version, info_version, 0},
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 35613c4..f997cb4 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -164,6 +164,7 @@ group as an option. For example:
hostname print the hypervisor hostname
qemu-attach Attach to existing QEMU process
qemu-monitor-command QEMU Monitor Command
+ qemu-agent-command QEMU Guest Agent Command
sysinfo print the hypervisor sysinfo
uri print the hypervisor canonical URI
@@ -2780,6 +2781,18 @@ before passing the single command to the monitor.
=back
+=item B<qemu-agent-command> I<domain> [I<--timeout> I<seconds> |
I<--async> | I<--block>] I<command>...
+
+Send an arbitrary guest agent command I<command> to domain I<domain> through
+qemu agent.
+I<--timeout>, I<--async> and I<--block> options are exclusive.
+I<--timeout> requires timeout seconds I<seconds> and it must be positive.
+When I<--aysnc> is given, the command waits for timeout whether success or
+failed. And when I<--block> is given, the command waits forever with blocking
+timeout.
+
+=back
+
=head1 ENVIRONMENT
The following environment variables can be set to alter the behaviour
--
1.7.1