Blob Blame History Raw
From 6360c62ec2a0ccfb66346daa3566930111685598 Mon Sep 17 00:00:00 2001
Message-Id: <6360c62ec2a0ccfb66346daa3566930111685598@dist-git>
From: Peter Krempa <pkrempa@redhat.com>
Date: Tue, 2 Aug 2016 13:41:44 +0200
Subject: [PATCH] util: qemu: Allow nested objects in JSON -> commandline
 generator

Move the iterator of objects to the recursive function so that nested
objects are supported by flattening the structure with '.' delimiters.

(cherry picked from commit cd86d6f4656d01894141840531d61595e40e4682)

https://bugzilla.redhat.com/show_bug.cgi?id=1134878 [JSON backing]
https://bugzilla.redhat.com/show_bug.cgi?id=1247521 [gluster multi-host]
---
 src/util/virqemu.c          | 70 ++++++++++++++++++++++++++++++++++-----------
 tests/qemucommandutiltest.c |  8 ++++++
 2 files changed, 61 insertions(+), 17 deletions(-)

diff --git a/src/util/virqemu.c b/src/util/virqemu.c
index 99c14c2..df665ad 100644
--- a/src/util/virqemu.c
+++ b/src/util/virqemu.c
@@ -26,11 +26,49 @@
 #include "virerror.h"
 #include "virlog.h"
 #include "virqemu.h"
+#include "virstring.h"
+#include "viralloc.h"
 
 #define VIR_FROM_THIS VIR_FROM_NONE
 
 VIR_LOG_INIT("util.qemu");
 
+struct virQEMUCommandLineJSONIteratorData {
+    const char *prefix;
+    virBufferPtr buf;
+};
+
+
+static int
+virQEMUBuildCommandLineJSONRecurse(const char *key,
+                                   const virJSONValue *value,
+                                   virBufferPtr buf,
+                                   bool nested);
+
+/* internal iterator to handle nested object formatting */
+static int
+virQEMUBuildCommandLineJSONIterate(const char *key,
+                                   const virJSONValue *value,
+                                   void *opaque)
+{
+    struct virQEMUCommandLineJSONIteratorData *data = opaque;
+    char *tmpkey = NULL;
+    int ret = -1;
+
+    if (data->prefix) {
+        if (virAsprintf(&tmpkey, "%s.%s", data->prefix, key) < 0)
+            return -1;
+
+        ret = virQEMUBuildCommandLineJSONRecurse(tmpkey, value, data->buf, false);
+
+        VIR_FREE(tmpkey);
+    } else {
+        ret = virQEMUBuildCommandLineJSONRecurse(key, value, data->buf, false);
+    }
+
+    return ret;
+}
+
 
 static int
 virQEMUBuildCommandLineJSONRecurse(const char *key,
@@ -38,12 +76,19 @@ virQEMUBuildCommandLineJSONRecurse(const char *key,
                                    virBufferPtr buf,
                                    bool nested)
 {
+    struct virQEMUCommandLineJSONIteratorData data = { key, buf };
     virJSONValuePtr elem;
     virBitmapPtr bitmap = NULL;
     ssize_t pos = -1;
     ssize_t end;
     size_t i;
 
+    if (!key && value->type != VIR_JSON_TYPE_OBJECT) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("only JSON objects can be top level"));
+        return -1;
+    }
+
     switch ((virJSONType) value->type) {
     case VIR_JSON_TYPE_STRING:
         virBufferAsprintf(buf, ",%s=", key);
@@ -96,10 +141,15 @@ virQEMUBuildCommandLineJSONRecurse(const char *key,
         break;
 
     case VIR_JSON_TYPE_OBJECT:
+        if (virJSONValueObjectForeachKeyValue(value,
+                                              virQEMUBuildCommandLineJSONIterate,
+                                              &data) < 0)
+            return -1;
+        break;
+
     case VIR_JSON_TYPE_NULL:
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("NULL and OBJECT JSON types can't be converted to "
-                         "commandline string"));
+                       _("NULL JSON type can't be converted to commandline"));
         return -1;
     }
 
@@ -108,15 +158,6 @@ virQEMUBuildCommandLineJSONRecurse(const char *key,
 }
 
 
-static int
-virQEMUBuildCommandLineJSONIterate(const char *key,
-                                   const virJSONValue *value,
-                                   void *opaque)
-{
-    return virQEMUBuildCommandLineJSONRecurse(key, value, opaque, false);
-}
-
-
 /**
  * virQEMUBuildCommandLineJSON:
  * @value: json object containing the value
@@ -131,12 +172,7 @@ int
 virQEMUBuildCommandLineJSON(const virJSONValue *value,
                             virBufferPtr buf)
 {
-    if (virJSONValueObjectForeachKeyValue(value,
-                                          virQEMUBuildCommandLineJSONIterate,
-                                          buf) < 0)
-        return -1;
-
-    return 0;
+    return virQEMUBuildCommandLineJSONRecurse(NULL, value, buf, false);
 }
 
 
diff --git a/tests/qemucommandutiltest.c b/tests/qemucommandutiltest.c
index 8299462..4872ea3 100644
--- a/tests/qemucommandutiltest.c
+++ b/tests/qemucommandutiltest.c
@@ -117,6 +117,14 @@ mymain(void)
                                      "array=bleah,array=qwerty,array=1");
     DO_TEST_COMMAND_OBJECT_FROM_JSON("{\"boolean\":true,\"hyphen-name\":1234,\"some_string\":\"bleah\"}",
                                      "boolean=yes,hyphen-name=1234,some_string=bleah");
+    DO_TEST_COMMAND_OBJECT_FROM_JSON("{\"nest\": {\"boolean\":true,"
+                                                 "\"hyphen-name\":1234,"
+                                                 "\"some_string\":\"bleah\","
+                                                 "\"bleah\":\"bl,eah\""
+                                                 "}"
+                                     "}",
+                                     "nest.boolean=yes,nest.hyphen-name=1234,"
+                                     "nest.some_string=bleah,nest.bleah=bl,,eah");
 
     return ret;
 
-- 
2.9.2