|
|
c401cc |
From 5174fe3a8c3ebee598ec2b5b2426d70d4aaf5bb3 Mon Sep 17 00:00:00 2001
|
|
|
c401cc |
Message-Id: <5174fe3a8c3ebee598ec2b5b2426d70d4aaf5bb3.1391615407.git.jdenemar@redhat.com>
|
|
|
c401cc |
From: Michal Privoznik <mprivozn@redhat.com>
|
|
|
c401cc |
Date: Tue, 4 Feb 2014 13:34:53 -0500
|
|
|
c401cc |
Subject: [PATCH] virCommand: Introduce virCommandSetDryRun
|
|
|
c401cc |
|
|
|
c401cc |
https://bugzilla.redhat.com/show_bug.cgi?id=1045124
|
|
|
c401cc |
|
|
|
c401cc |
There are some units within libvirt that utilize virCommand API to run
|
|
|
c401cc |
some commands and deserve own unit testing. These units are, however,
|
|
|
c401cc |
not desired to be rewritten to dig virCommand API usage out. As a great
|
|
|
c401cc |
example virNetDevBandwidth could be used. The problem with the bandwidth
|
|
|
c401cc |
unit is: it uses virCommand API heavily. Therefore we need a mechanism
|
|
|
c401cc |
to not really run a command, but rather see its string representation
|
|
|
c401cc |
after which we can decide if the unit construct the correct sequence of
|
|
|
c401cc |
commands or not.
|
|
|
c401cc |
|
|
|
c401cc |
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
|
c401cc |
(cherry picked from commit 550a2ceffb46f2a7dbc6ce0197da8b1b6e8c5abd)
|
|
|
c401cc |
Signed-off-by: John Ferlan <jferlan@redhat.com>
|
|
|
c401cc |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
c401cc |
---
|
|
|
c401cc |
src/libvirt_private.syms | 1 +
|
|
|
c401cc |
src/util/vircommand.c | 61 +++++++++++++++++++++++++++++++++++++++++++++---
|
|
|
c401cc |
src/util/vircommand.h | 2 ++
|
|
|
c401cc |
3 files changed, 61 insertions(+), 3 deletions(-)
|
|
|
c401cc |
|
|
|
c401cc |
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
|
|
|
c401cc |
index a1b3e4a..5e65c35 100644
|
|
|
c401cc |
--- a/src/libvirt_private.syms
|
|
|
c401cc |
+++ b/src/libvirt_private.syms
|
|
|
c401cc |
@@ -1267,6 +1267,7 @@ virCommandRequireHandshake;
|
|
|
c401cc |
virCommandRun;
|
|
|
c401cc |
virCommandRunAsync;
|
|
|
c401cc |
virCommandSetAppArmorProfile;
|
|
|
c401cc |
+virCommandSetDryRun;
|
|
|
c401cc |
virCommandSetErrorBuffer;
|
|
|
c401cc |
virCommandSetErrorFD;
|
|
|
c401cc |
virCommandSetGID;
|
|
|
c401cc |
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
|
|
|
c401cc |
index fca0e09..3302ce6 100644
|
|
|
c401cc |
--- a/src/util/vircommand.c
|
|
|
c401cc |
+++ b/src/util/vircommand.c
|
|
|
c401cc |
@@ -129,6 +129,9 @@ struct _virCommand {
|
|
|
c401cc |
#endif
|
|
|
c401cc |
};
|
|
|
c401cc |
|
|
|
c401cc |
+/* See virCommandSetDryRun for description for this variable */
|
|
|
c401cc |
+static virBufferPtr dryRunBuffer;
|
|
|
c401cc |
+
|
|
|
c401cc |
/*
|
|
|
c401cc |
* virCommandFDIsSet:
|
|
|
c401cc |
* @fd: FD to test
|
|
|
c401cc |
@@ -2199,7 +2202,7 @@ int
|
|
|
c401cc |
virCommandRunAsync(virCommandPtr cmd, pid_t *pid)
|
|
|
c401cc |
{
|
|
|
c401cc |
int ret = -1;
|
|
|
c401cc |
- char *str;
|
|
|
c401cc |
+ char *str = NULL;
|
|
|
c401cc |
size_t i;
|
|
|
c401cc |
bool synchronous = false;
|
|
|
c401cc |
int infd[2] = {-1, -1};
|
|
|
c401cc |
@@ -2262,9 +2265,21 @@ virCommandRunAsync(virCommandPtr cmd, pid_t *pid)
|
|
|
c401cc |
}
|
|
|
c401cc |
|
|
|
c401cc |
str = virCommandToString(cmd);
|
|
|
c401cc |
- VIR_DEBUG("About to run %s", str ? str : cmd->args[0]);
|
|
|
c401cc |
- VIR_FREE(str);
|
|
|
c401cc |
+ if (dryRunBuffer) {
|
|
|
c401cc |
+ if (!str) {
|
|
|
c401cc |
+ /* error already reported by virCommandToString */
|
|
|
c401cc |
+ goto cleanup;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+
|
|
|
c401cc |
+ VIR_DEBUG("Dry run requested, appending stringified "
|
|
|
c401cc |
+ "command to dryRunBuffer=%p", dryRunBuffer);
|
|
|
c401cc |
+ virBufferAdd(dryRunBuffer, str, -1);
|
|
|
c401cc |
+ virBufferAddChar(dryRunBuffer, '\n');
|
|
|
c401cc |
+ ret = 0;
|
|
|
c401cc |
+ goto cleanup;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
|
|
|
c401cc |
+ VIR_DEBUG("About to run %s", str ? str : cmd->args[0]);
|
|
|
c401cc |
ret = virExec(cmd);
|
|
|
c401cc |
VIR_DEBUG("Command result %d, with PID %d",
|
|
|
c401cc |
ret, (int)cmd->pid);
|
|
|
c401cc |
@@ -2303,6 +2318,7 @@ cleanup:
|
|
|
c401cc |
VIR_FORCE_CLOSE(cmd->infd);
|
|
|
c401cc |
VIR_FORCE_CLOSE(cmd->inpipe);
|
|
|
c401cc |
}
|
|
|
c401cc |
+ VIR_FREE(str);
|
|
|
c401cc |
return ret;
|
|
|
c401cc |
}
|
|
|
c401cc |
|
|
|
c401cc |
@@ -2334,6 +2350,13 @@ virCommandWait(virCommandPtr cmd, int *exitstatus)
|
|
|
c401cc |
return -1;
|
|
|
c401cc |
}
|
|
|
c401cc |
|
|
|
c401cc |
+ if (dryRunBuffer) {
|
|
|
c401cc |
+ VIR_DEBUG("Dry run requested, claiming success");
|
|
|
c401cc |
+ if (exitstatus)
|
|
|
c401cc |
+ *exitstatus = 0;
|
|
|
c401cc |
+ return 0;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+
|
|
|
c401cc |
if (cmd->pid == -1) {
|
|
|
c401cc |
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
c401cc |
_("command is not yet running"));
|
|
|
c401cc |
@@ -2669,3 +2692,35 @@ virCommandDoAsyncIO(virCommandPtr cmd)
|
|
|
c401cc |
|
|
|
c401cc |
cmd->flags |= VIR_EXEC_ASYNC_IO | VIR_EXEC_NONBLOCK;
|
|
|
c401cc |
}
|
|
|
c401cc |
+
|
|
|
c401cc |
+/**
|
|
|
c401cc |
+ * virCommandSetDryRun:
|
|
|
c401cc |
+ * @buf: buffer to store stringified commands
|
|
|
c401cc |
+ *
|
|
|
c401cc |
+ * Sometimes it's desired to not actually run given command, but
|
|
|
c401cc |
+ * see its string representation without having to change the
|
|
|
c401cc |
+ * callee. Unit testing serves as a great example. In such cases,
|
|
|
c401cc |
+ * the callee constructs the command and calls it via
|
|
|
c401cc |
+ * virCommandRun* API. The virCommandSetDryRun allows you to
|
|
|
c401cc |
+ * modify this behavior: once called, every call to
|
|
|
c401cc |
+ * virCommandRun* results in command string representation being
|
|
|
c401cc |
+ * appended to @buf instead of being executed. the strings are
|
|
|
c401cc |
+ * escaped for a shell and separated by a newline. For example:
|
|
|
c401cc |
+ *
|
|
|
c401cc |
+ * virBuffer buffer = VIR_BUFFER_INITIALIZER;
|
|
|
c401cc |
+ * virCommandSetDryRun(&buffer);
|
|
|
c401cc |
+ *
|
|
|
c401cc |
+ * virCommandPtr echocmd = virCommandNewArgList("/bin/echo", "Hello world", NULL);
|
|
|
c401cc |
+ * virCommandRun(echocmd, NULL);
|
|
|
c401cc |
+ *
|
|
|
c401cc |
+ * After this, the @buffer should contain:
|
|
|
c401cc |
+ *
|
|
|
c401cc |
+ * /bin/echo 'Hello world'\n
|
|
|
c401cc |
+ *
|
|
|
c401cc |
+ * To cancel this effect pass NULL.
|
|
|
c401cc |
+ */
|
|
|
c401cc |
+void
|
|
|
c401cc |
+virCommandSetDryRun(virBufferPtr buf)
|
|
|
c401cc |
+{
|
|
|
c401cc |
+ dryRunBuffer = buf;
|
|
|
c401cc |
+}
|
|
|
c401cc |
diff --git a/src/util/vircommand.h b/src/util/vircommand.h
|
|
|
c401cc |
index e977f93..a743200 100644
|
|
|
c401cc |
--- a/src/util/vircommand.h
|
|
|
c401cc |
+++ b/src/util/vircommand.h
|
|
|
c401cc |
@@ -184,4 +184,6 @@ void virCommandAbort(virCommandPtr cmd);
|
|
|
c401cc |
void virCommandFree(virCommandPtr cmd);
|
|
|
c401cc |
|
|
|
c401cc |
void virCommandDoAsyncIO(virCommandPtr cmd);
|
|
|
c401cc |
+
|
|
|
c401cc |
+void virCommandSetDryRun(virBufferPtr buf);
|
|
|
c401cc |
#endif /* __VIR_COMMAND_H__ */
|
|
|
c401cc |
--
|
|
|
c401cc |
1.8.5.3
|
|
|
c401cc |
|