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(a)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