]> xenbits.xensource.com Git - libvirt.git/commitdiff
virCommand: Introduce virCommandSetDryRun
authorMichal Privoznik <mprivozn@redhat.com>
Tue, 28 Jan 2014 18:18:43 +0000 (19:18 +0100)
committerMichal Privoznik <mprivozn@redhat.com>
Wed, 29 Jan 2014 17:01:36 +0000 (18:01 +0100)
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>
src/libvirt_private.syms
src/util/vircommand.c
src/util/vircommand.h

index 0c163437de47b2d97153222b598d379468499839..76552478461c87545ee6a94f8b53ce43a01ed9ae 100644 (file)
@@ -1096,6 +1096,7 @@ virCommandRequireHandshake;
 virCommandRun;
 virCommandRunAsync;
 virCommandSetAppArmorProfile;
+virCommandSetDryRun;
 virCommandSetErrorBuffer;
 virCommandSetErrorFD;
 virCommandSetGID;
index a52a1ab96b2a147f8e1188cbc0b09011f3ee352c..b137436ea6747f3c796590a19412c34315ed4922 100644 (file)
@@ -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;
+}
index e977f93ed73b167e1eafc2315cc27a59479334ea..a7432004f1f1de5541a85b7dd8ee7f0bfb31585b 100644 (file)
@@ -184,4 +184,6 @@ void virCommandAbort(virCommandPtr cmd);
 void virCommandFree(virCommandPtr cmd);
 
 void virCommandDoAsyncIO(virCommandPtr cmd);
+
+void virCommandSetDryRun(virBufferPtr buf);
 #endif /* __VIR_COMMAND_H__ */