render / rpms / libvirt

Forked from rpms/libvirt 7 months ago
Clone
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