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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list