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