[libvirt] [PATCH 4/7] Add ability to register callback for virCommand dry run

Daniel P. Berrange berrange at redhat.com
Wed Mar 12 13:21:18 UTC 2014


To allow for fault injection of the virCommand dry run,
add the ability to register a callback. The callback will
be passed the argv, env and stdin buffer and is expected
to return the exit status and optionally fill stdout and
stderr buffers.

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 src/util/vircommand.c          | 47 +++++++++++++++++++++++++++++++-----------
 src/util/vircommand.h          | 12 ++++++++++-
 tests/virkmodtest.c            |  8 +++----
 tests/virnetdevbandwidthtest.c |  3 ++-
 4 files changed, 52 insertions(+), 18 deletions(-)

diff --git a/src/util/vircommand.c b/src/util/vircommand.c
index db4166f..42d0182 100644
--- a/src/util/vircommand.c
+++ b/src/util/vircommand.c
@@ -132,6 +132,9 @@ struct _virCommand {
 
 /* See virCommandSetDryRun for description for this variable */
 static virBufferPtr dryRunBuffer;
+static virCommandDryRunCallback dryRunCallback;
+static void *dryRunOpaque;
+static int dryRunStatus;
 
 /*
  * virCommandFDIsSet:
@@ -2264,16 +2267,25 @@ virCommandRunAsync(virCommandPtr cmd, pid_t *pid)
     }
 
     str = virCommandToString(cmd);
-    if (dryRunBuffer) {
+    if (dryRunBuffer || dryRunCallback) {
+        dryRunStatus = 0;
         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');
+        if (dryRunBuffer) {
+            VIR_DEBUG("Dry run requested, appending stringified "
+                      "command to dryRunBuffer=%p", dryRunBuffer);
+            virBufferAdd(dryRunBuffer, str, -1);
+            virBufferAddChar(dryRunBuffer, '\n');
+        }
+        if (dryRunCallback) {
+            dryRunCallback((const char *const*)cmd->args,
+                           (const char *const*)cmd->env,
+                           cmd->inbuf, cmd->outbuf, cmd->errbuf,
+                           &dryRunStatus, dryRunOpaque);
+        }
         ret = 0;
         goto cleanup;
     }
@@ -2353,10 +2365,11 @@ virCommandWait(virCommandPtr cmd, int *exitstatus)
         return -1;
     }
 
-    if (dryRunBuffer) {
-        VIR_DEBUG("Dry run requested, claiming success");
+    if (dryRunBuffer || dryRunCallback) {
+        VIR_DEBUG("Dry run requested, returning status %d",
+                  dryRunStatus);
         if (exitstatus)
-            *exitstatus = 0;
+            *exitstatus = dryRunStatus;
         return 0;
     }
 
@@ -2701,6 +2714,7 @@ virCommandDoAsyncIO(virCommandPtr cmd)
 /**
  * virCommandSetDryRun:
  * @buf: buffer to store stringified commands
+ * @callback: callback to process input/output/args
  *
  * Sometimes it's desired to not actually run given command, but
  * see its string representation without having to change the
@@ -2709,8 +2723,13 @@ virCommandDoAsyncIO(virCommandPtr cmd)
  * 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:
+ * appended to @buf instead of being executed. If @callback is
+ * provided, then it is invoked with the argv, env and stdin
+ * data string for the command. It is expected to fill the stdout
+ * and stderr data strings and exit status variables.
+ *
+ * The strings stored in @buf are escaped for a shell and
+ * separated by a newline. For example:
  *
  * virBuffer buffer = VIR_BUFFER_INITIALIZER;
  * virCommandSetDryRun(&buffer);
@@ -2722,10 +2741,14 @@ virCommandDoAsyncIO(virCommandPtr cmd)
  *
  * /bin/echo 'Hello world'\n
  *
- * To cancel this effect pass NULL.
+ * To cancel this effect pass NULL for @buf and @callback.
  */
 void
-virCommandSetDryRun(virBufferPtr buf)
+virCommandSetDryRun(virBufferPtr buf,
+                    virCommandDryRunCallback cb,
+                    void *opaque)
 {
     dryRunBuffer = buf;
+    dryRunCallback = cb;
+    dryRunOpaque = opaque;
 }
diff --git a/src/util/vircommand.h b/src/util/vircommand.h
index 7485edc..9405f5f 100644
--- a/src/util/vircommand.h
+++ b/src/util/vircommand.h
@@ -187,5 +187,15 @@ void virCommandFree(virCommandPtr cmd);
 
 void virCommandDoAsyncIO(virCommandPtr cmd);
 
-void virCommandSetDryRun(virBufferPtr buf);
+typedef void (*virCommandDryRunCallback)(const char *const*args,
+                                         const char *const*env,
+                                         const char *input,
+                                         char **output,
+                                         char **error,
+                                         int *status,
+                                         void *opaque);
+
+void virCommandSetDryRun(virBufferPtr buf,
+                         virCommandDryRunCallback cb,
+                         void *opaque);
 #endif /* __VIR_COMMAND_H__ */
diff --git a/tests/virkmodtest.c b/tests/virkmodtest.c
index c6f5a72..f362d03 100644
--- a/tests/virkmodtest.c
+++ b/tests/virkmodtest.c
@@ -95,7 +95,7 @@ testKModLoad(const void *args)
     bool useBlacklist = info->useBlacklist;
     virBuffer buf = VIR_BUFFER_INITIALIZER;
 
-    virCommandSetDryRun(&buf);
+    virCommandSetDryRun(&buf, NULL, NULL);
 
     errbuf = virKModLoad(module, useBlacklist);
     if (errbuf) {
@@ -109,7 +109,7 @@ testKModLoad(const void *args)
     ret = 0;
 
 cleanup:
-    virCommandSetDryRun(NULL);
+    virCommandSetDryRun(NULL, NULL, NULL);
     VIR_FREE(errbuf);
     return ret;
 }
@@ -124,7 +124,7 @@ testKModUnload(const void *args)
     const char *module = info->module;
     virBuffer buf = VIR_BUFFER_INITIALIZER;
 
-    virCommandSetDryRun(&buf);
+    virCommandSetDryRun(&buf, NULL, NULL);
 
     errbuf = virKModUnload(module);
     if (errbuf) {
@@ -138,7 +138,7 @@ testKModUnload(const void *args)
     ret = 0;
 
 cleanup:
-    virCommandSetDryRun(NULL);
+    virCommandSetDryRun(NULL, NULL, NULL);
     VIR_FREE(errbuf);
     return ret;
 }
diff --git a/tests/virnetdevbandwidthtest.c b/tests/virnetdevbandwidthtest.c
index 073fdf8..3aebd49 100644
--- a/tests/virnetdevbandwidthtest.c
+++ b/tests/virnetdevbandwidthtest.c
@@ -76,7 +76,7 @@ testVirNetDevBandwidthSet(const void *data)
     if (!iface)
         iface = "eth0";
 
-    virCommandSetDryRun(&buf);
+    virCommandSetDryRun(&buf, NULL, NULL);
 
     if (virNetDevBandwidthSet(iface, band, info->hierarchical_class) < 0)
         goto cleanup;
@@ -100,6 +100,7 @@ testVirNetDevBandwidthSet(const void *data)
 
     ret = 0;
 cleanup:
+    virCommandSetDryRun(NULL, NULL, NULL);
     virNetDevBandwidthFree(band);
     virBufferFreeAndReset(&buf);
     VIR_FREE(actual_cmd);
-- 
1.8.5.3




More information about the libvir-list mailing list