From 74df83a9eba87f81d4190dad0db7e30b9d89c7ea Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Jul 27 2016 11:33:10 +0000 Subject: util: qemu: Add support for numbered array members Add support for converting objects nested in arrays with a numbering discriminator on the command line. This syntax is used for the object-based specification of disk source properties. --- diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 73904a6..f49a3b2 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2206,6 +2206,7 @@ virProcessWait; virQEMUBuildBufferEscapeComma; virQEMUBuildCommandLineJSON; virQEMUBuildCommandLineJSONArrayBitmap; +virQEMUBuildCommandLineJSONArrayNumbered; virQEMUBuildLuksOpts; virQEMUBuildObjectCommandlineFromJSON; diff --git a/src/util/virqemu.c b/src/util/virqemu.c index 8babe36..20410f7 100644 --- a/src/util/virqemu.c +++ b/src/util/virqemu.c @@ -79,6 +79,39 @@ virQEMUBuildCommandLineJSONArrayBitmap(const char *key, } +int +virQEMUBuildCommandLineJSONArrayNumbered(const char *key, + const virJSONValue *array, + virBufferPtr buf) +{ + const virJSONValue *member; + size_t nelems = virJSONValueArraySize(array); + char *prefix = NULL; + size_t i; + int ret = 0; + + for (i = 0; i < nelems; i++) { + member = virJSONValueArrayGet((virJSONValuePtr) array, i); + + if (virAsprintf(&prefix, "%s.%zu", key, i) < 0) + goto cleanup; + + if (virQEMUBuildCommandLineJSONRecurse(prefix, member, buf, + virQEMUBuildCommandLineJSONArrayNumbered, + true) < 0) + goto cleanup; + + VIR_FREE(prefix); + } + + ret = 0; + + cleanup: + VIR_FREE(prefix); + return ret; +} + + /* internal iterator to handle nested object formatting */ static int virQEMUBuildCommandLineJSONIterate(const char *key, diff --git a/src/util/virqemu.h b/src/util/virqemu.h index 801c35b..40cd9b8 100644 --- a/src/util/virqemu.h +++ b/src/util/virqemu.h @@ -35,6 +35,9 @@ typedef int (*virQEMUBuildCommandLineJSONArrayFormatFunc)(const char *key, int virQEMUBuildCommandLineJSONArrayBitmap(const char *key, const virJSONValue *array, virBufferPtr buf); +int virQEMUBuildCommandLineJSONArrayNumbered(const char *key, + const virJSONValue *array, + virBufferPtr buf); int virQEMUBuildCommandLineJSON(const virJSONValue *value, virBufferPtr buf, diff --git a/tests/qemucommandutiltest.c b/tests/qemucommandutiltest.c index 0bf0351..1985983 100644 --- a/tests/qemucommandutiltest.c +++ b/tests/qemucommandutiltest.c @@ -30,6 +30,7 @@ typedef struct { const char *props; const char *expectprops; + virQEMUBuildCommandLineJSONArrayFormatFunc arrayfunc; } testQemuCommandBuildObjectFromJSONData; static int @@ -46,8 +47,7 @@ testQemuCommandBuildFromJSON(const void *opaque) return -1; } - if (virQEMUBuildCommandLineJSON(val, &buf, - virQEMUBuildCommandLineJSONArrayBitmap) < 0) { + if (virQEMUBuildCommandLineJSON(val, &buf, data->arrayfunc) < 0) { fprintf(stderr, "\nvirQEMUBuildCommandlineJSON failed process JSON:\n%s\n", data->props); @@ -83,16 +83,23 @@ mymain(void) virTestCounterReset("testQemuCommandBuildFromJSON"); -#define DO_TEST_COMMAND_OBJECT_FROM_JSON(PROPS, EXPECT) \ +#define DO_TEST_COMMAND_FROM_JSON(PROPS, ARRAYFUNC, EXPECT) \ do { \ data1.props = PROPS; \ data1.expectprops = EXPECT; \ + data1.arrayfunc = ARRAYFUNC; \ if (virTestRun(virTestCounterNext(), \ testQemuCommandBuildFromJSON, \ &data1) < 0) \ ret = -1; \ } while (0) +#define DO_TEST_COMMAND_OBJECT_FROM_JSON(PROPS, EXPECT) \ + DO_TEST_COMMAND_FROM_JSON(PROPS, virQEMUBuildCommandLineJSONArrayBitmap, EXPECT) + +#define DO_TEST_COMMAND_DRIVE_FROM_JSON(PROPS, EXPECT) \ + DO_TEST_COMMAND_FROM_JSON(PROPS, virQEMUBuildCommandLineJSONArrayNumbered, EXPECT) + DO_TEST_COMMAND_OBJECT_FROM_JSON("{}", NULL); DO_TEST_COMMAND_OBJECT_FROM_JSON("{\"string\":\"qwer\"}", "string=qwer"); DO_TEST_COMMAND_OBJECT_FROM_JSON("{\"string\":\"qw,e,r\"}", "string=qw,,e,,r"); @@ -120,6 +127,29 @@ mymain(void) "}", "nest.boolean=yes,nest.hyphen-name=1234," "nest.some_string=bleah,nest.bleah=bl,,eah"); + DO_TEST_COMMAND_DRIVE_FROM_JSON("{\"driver\":\"gluster\"," + "\"volume\":\"test\"," + "\"path\":\"img\"," + "\"server\":[ { \"type\":\"tcp\"," + "\"host\":\"example.com\"," + "\"port\":\"1234\"" + "}," + "{ \"type\":\"unix\"," + "\"socket\":\"/path/socket\"" + "}," + "{ \"type\":\"tcp\"," + "\"host\":\"example.com\"" + "}" + "]" + "}", + "driver=gluster,volume=test,path=img," + "server.0.type=tcp," + "server.0.host=example.com," + "server.0.port=1234," + "server.1.type=unix," + "server.1.socket=/path/socket," + "server.2.type=tcp," + "server.2.host=example.com"); return ret;