[libvirt] [RFC PATCH 1/8] conf: Introduce virDomainDefParseJSONString()

Andrea Bolognani abologna at redhat.com
Mon Apr 1 12:39:23 UTC 2019


We parse just enough JSON to be able to define a domain using
the new API at the moment: clearly more work is needed before
it can be considered a replacement for the existing XML-based
APIs, but you gotta start somewhere :)

Signed-off-by: Andrea Bolognani <abologna at redhat.com>
---
 include/libvirt/virterror.h |   1 +
 src/conf/domain_conf.c      | 241 ++++++++++++++++++++++++++++++++++++
 src/conf/domain_conf.h      |   5 +
 src/libvirt_private.syms    |   1 +
 src/util/virerror.c         |   3 +
 5 files changed, 251 insertions(+)

diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 6dc83a17cc..90406d595a 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -326,6 +326,7 @@ typedef enum {
     VIR_ERR_INVALID_DOMAIN_CHECKPOINT = 102, /* invalid domain checkpoint */
     VIR_ERR_NO_DOMAIN_CHECKPOINT = 103, /* domain checkpoint not found */
     VIR_ERR_NO_DOMAIN_BACKUP = 104,     /* domain backup job id not found */
+    VIR_ERR_JSON_ERROR = 105,           /* JSON format error */
 
 # ifdef VIR_ENUM_SENTINELS
     VIR_ERR_NUMBER_LAST
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 5f2b1f68b5..896dd75082 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -58,6 +58,7 @@
 #include "virhostdev.h"
 #include "virmdev.h"
 #include "virdomainsnapshotobjlist.h"
+#include "virjson.h"
 
 #define VIR_FROM_THIS VIR_FROM_DOMAIN
 
@@ -21206,6 +21207,246 @@ virDomainDefParseFile(const char *filename,
 }
 
 
+static int
+virDomainDefParseJSONDomainOSType(virDomainDefPtr def,
+                                  virJSONValuePtr osType)
+{
+    virJSONValuePtr attributes = virJSONValueObjectGetObject(osType, "attributes");
+    const char *type = NULL;
+    const char *arch = NULL;
+    const char *machine = NULL;
+    int ret = -1;
+
+    if (!attributes) {
+        virReportError(VIR_ERR_JSON_ERROR, "%s",
+                       _("No attributes for 'type' object"));
+        goto cleanup;
+    }
+
+    if (!(type = virJSONValueObjectGetString(osType, "value"))) {
+        virReportError(VIR_ERR_JSON_ERROR, "%s",
+                       _("Missing OS type"));
+        goto cleanup;
+    }
+
+    if ((def->os.type = virDomainOSTypeFromString(type)) < 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Invalid OS type '%s'"),
+                       type);
+        return -1;
+    }
+
+    if ((machine = virJSONValueObjectGetString(attributes, "machine")) &&
+        VIR_STRDUP(def->os.machine, machine) < 0) {
+        goto cleanup;
+    }
+
+    if ((arch = virJSONValueObjectGetString(attributes, "arch")) &&
+        !(def->os.arch = virArchFromString(arch))) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Invalid architecture '%s'"),
+                       arch);
+    }
+
+    ret = 0;
+
+ cleanup:
+    return ret;
+}
+
+
+static int
+virDomainDefParseJSONDomainOS(virDomainDefPtr def,
+                              virJSONValuePtr os)
+{
+    virJSONValuePtr children = virJSONValueObjectGetObject(os, "children");
+    virJSONValuePtr osType = NULL;
+    int ret = -1;
+
+    if (!children) {
+        virReportError(VIR_ERR_JSON_ERROR, "%s",
+                       _("No children for 'os' object"));
+        goto cleanup;
+    }
+
+    if (!(osType = virJSONValueObjectGetObject(children, "type"))) {
+        virReportError(VIR_ERR_JSON_ERROR, "%s",
+                       _("Missing 'type' children for 'os' object"));
+        goto cleanup;
+    }
+
+    if (virDomainDefParseJSONDomainOSType(def, osType) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    return ret;
+}
+
+
+static int
+virDomainDefParseJSONDomain(virDomainDefPtr def,
+                            virJSONValuePtr domain)
+{
+    virJSONValuePtr attributes = virJSONValueObjectGetObject(domain, "attributes");
+    virJSONValuePtr children = virJSONValueObjectGetObject(domain, "children");
+    virJSONValuePtr tmp = NULL;
+    const char *virtType = NULL;
+    const char *name = NULL;
+    int ret = -1;
+
+    if (!attributes) {
+        virReportError(VIR_ERR_JSON_ERROR, "%s",
+                       _("No attributes for 'domain' object"));
+        goto cleanup;
+    }
+
+    if (!(virtType = virJSONValueObjectGetString(attributes, "type"))) {
+        virReportError(VIR_ERR_JSON_ERROR, "%s",
+                       _("Missing 'type' attribute for 'domain' object"));
+        goto cleanup;
+    }
+
+    if ((def->virtType = virDomainVirtTypeFromString(virtType)) < 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Invalid virtualization type '%s'"),
+                       virtType);
+        goto cleanup;
+    }
+
+    if (!children) {
+        virReportError(VIR_ERR_JSON_ERROR, "%s",
+                       _("No children for 'domain' object"));
+        goto cleanup;
+    }
+
+    if (!(tmp = virJSONValueObjectGetObject(children, "name")) ||
+        !(name = virJSONValueObjectGetString(tmp, "value"))) {
+        virReportError(VIR_ERR_NO_NAME, NULL);
+        goto cleanup;
+    }
+
+    if (!VIR_STRDUP(def->name, name))
+        goto cleanup;
+
+    if ((tmp = virJSONValueObjectGetObject(children, "uuid"))) {
+
+        const char *uuid;
+
+        if (!(uuid = virJSONValueObjectGetString(tmp, "value")) ||
+            virUUIDParse(uuid, def->uuid) < 0) {
+            virReportError(VIR_ERR_JSON_ERROR,
+                           _("Invalid UUID '%s'"),
+                           uuid);
+            goto cleanup;
+        }
+    } else {
+        if (virUUIDGenerate(def->uuid) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Failed to generate UUID"));
+            goto cleanup;
+        }
+    }
+
+    if ((tmp = virJSONValueObjectGetObject(children, "memory"))) {
+
+        unsigned long long max = virMemoryMaxValue(true);
+        unsigned long long memory;
+
+        if (!virJSONValueObjectHasKey(tmp, "value")) {
+            virReportError(VIR_ERR_JSON_ERROR, "%s",
+                           _("Missing 'value' attribute for 'memory' object"));
+            goto cleanup;
+        }
+
+        if (virJSONValueObjectGetNumberUlong(tmp, "value", &memory) < 0 ||
+            virScaleInteger(&memory, NULL, 1024, max) < 0) {
+            virReportError(VIR_ERR_JSON_ERROR, "%s",
+                           _("Invalid memory size"));
+            goto cleanup;
+        }
+
+        /* Yes, we really do use kibibytes for our internal sizing.  */
+        def->mem.total_memory = VIR_DIV_UP(memory, 1024);
+
+        if (def->mem.total_memory >= VIR_DIV_UP(max, 1024)) {
+            virReportError(VIR_ERR_OVERFLOW, "%s",
+                           _("Memory size is too large"));
+            goto cleanup;
+        }
+    }
+
+    if (virDomainDefSetVcpusMax(def, 1, NULL) < 0 ||
+        virDomainDefSetVcpus(def, 1) < 0) {
+        goto cleanup;
+    }
+
+    if (!(tmp = virJSONValueObjectGetObject(children, "os"))) {
+        virReportError(VIR_ERR_JSON_ERROR, "%s",
+                       _("No 'os' object"));
+        goto cleanup;
+    }
+
+    if (virDomainDefParseJSONDomainOS(def, tmp) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    return ret;
+}
+
+
+static virDomainDefPtr
+virDomainDefParseJSON(virJSONValuePtr json,
+                      virCapsPtr caps,
+                      virDomainXMLOptionPtr xmlopt,
+                      void *parseOpaque,
+                      unsigned int flags)
+{
+    virDomainDefPtr def = NULL;
+    virJSONValuePtr domain = NULL;
+
+    if (!(def = virDomainDefNew()))
+        goto error;
+
+    if (!(domain = virJSONValueObjectGetObject(json, "domain"))) {
+        virReportError(VIR_ERR_JSON_ERROR, "%s",
+                       _("No 'domain' object"));
+        goto error;
+    }
+
+    if (virDomainDefParseJSONDomain(def, domain) < 0 ||
+        virDomainDefPostParse(def, caps, flags, xmlopt, parseOpaque) < 0 ||
+        virDomainDefValidate(def, caps, flags, xmlopt) < 0) {
+        goto error;
+    }
+
+    return def;
+
+ error:
+    virDomainDefFree(def);
+    return NULL;
+}
+
+
+virDomainDefPtr
+virDomainDefParseJSONString(const char *buf,
+                            virCapsPtr caps,
+                            virDomainXMLOptionPtr xmlopt,
+                            void *parseOpaque,
+                            unsigned int flags)
+{
+    VIR_AUTOPTR(virJSONValue) json = NULL;
+
+    if (!(json = virJSONValueFromString(buf)))
+        return NULL;
+
+    return virDomainDefParseJSON(json, caps, xmlopt, parseOpaque, flags);
+}
+
+
 virDomainDefPtr
 virDomainDefParseNode(xmlDocPtr xml,
                       xmlNodePtr root,
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 4a25480662..ebeabd8dbe 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2954,6 +2954,11 @@ virDomainDefPtr virDomainDefParseFile(const char *filename,
                                       virDomainXMLOptionPtr xmlopt,
                                       void *parseOpaque,
                                       unsigned int flags);
+virDomainDefPtr virDomainDefParseJSONString(const char *buf,
+                                            virCapsPtr caps,
+                                            virDomainXMLOptionPtr xmlopt,
+                                            void *parseOpaque,
+                                            unsigned int flags);
 virDomainDefPtr virDomainDefParseNode(xmlDocPtr doc,
                                       xmlNodePtr root,
                                       virCapsPtr caps,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 73ef24d66f..8c60a01d8c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -291,6 +291,7 @@ virDomainDefMaybeAddInput;
 virDomainDefNeedsPlacementAdvice;
 virDomainDefNew;
 virDomainDefParseFile;
+virDomainDefParseJSONString;
 virDomainDefParseNode;
 virDomainDefParseString;
 virDomainDefPostParse;
diff --git a/src/util/virerror.c b/src/util/virerror.c
index 05e535d859..4e843efe99 100644
--- a/src/util/virerror.c
+++ b/src/util/virerror.c
@@ -1224,6 +1224,9 @@ const virErrorMsgTuple virErrorMsgStrings[VIR_ERR_NUMBER_LAST] = {
     [VIR_ERR_NO_DOMAIN_BACKUP] = {
         N_("Domain backup job id not found"),
         N_("Domain backup job id not found: %s") },
+    [VIR_ERR_JSON_ERROR] = {
+        N_("JSON description is invalid or not well formed"),
+        N_("JSON error: %s") },
 };
 
 
-- 
2.20.1




More information about the libvir-list mailing list