
From: Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com> This patch adds a new virsh command "confcpu-model", that allows to show and modify cpu model, fallback attribute and vendor_id attribute of a model node of a domain XML. If cpu model is specified, mode attribute of the cpu node will be "custom" automatically. Modification is supported for only persistent configuration. Examples of usage: change cpu model to "core2duo" and fallback attribute to "forbid" virsh # confcpu-model <domain> --model core2duo --fallback forbid reset all cpu model configuration under a model node of a domain XML virsh # confcpu-model <domain> --reset show model node information of a running guest virsh # confcpu-model <domain> --live Signed-off-by: Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com> --- tools/virsh-domain.c | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 27 +++++++ 2 files changed, 252 insertions(+) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 913a1b4..762d50b 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -5711,6 +5711,230 @@ cmdConfCPU(vshControl *ctl, const vshCmd *cmd) } /* + * "confcpu-model" command + */ +static const vshCmdInfo info_confcpu_model[] = { + {"help", N_("show or modify domain cpu model")}, + {"desc", N_("Show or modify model node information of a domain XML")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_confcpu_model[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"model", VSH_OT_DATA, 0, N_("cpu model")}, + {"fallback", VSH_OT_DATA, 0, + N_("fallback attribute, one of allow or forbid")}, + {"vendor_id", VSH_OT_DATA, 0, + N_("vendor_id attribute, must be exactly 12 characters long")}, + {"reset", VSH_OT_BOOL, 0, + N_("remove a model node and redefine the domain XML")}, + {"live", VSH_OT_BOOL, 0, N_("affect running state")}, + {"config", VSH_OT_BOOL, 0, N_("affect persistent configuration")}, + {"current", VSH_OT_BOOL, 0, N_("affect current state configuration")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdConfCPUModel(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + virDomainPtr dom_edited = NULL; + const char *newModel = NULL; + char *curModel = NULL; + char *escedModel = NULL; + const char *newFallback = NULL; + char *curFallback = NULL; + const char *newVendorID = NULL; + char *curVendorID =NULL; + bool reset = vshCommandOptBool(cmd, "reset"); + bool config = vshCommandOptBool(cmd, "config"); + bool live = vshCommandOptBool(cmd, "live"); + bool current = vshCommandOptBool(cmd, "current"); + int running = -1; + bool modify = false; /* Modification mode */ + unsigned int flags = 0; + bool ret = false; + char *doc = NULL; + char *doc_edited = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlDocPtr xml = NULL; + xmlNodePtr domNode = NULL; + xmlNodePtr cpuNode = NULL; + xmlNodePtr modelNode = NULL; + + if (current + config + live > 1) { + vshError(ctl, "%s", + _("--config, --live, and --current are mutually exclusive")); + return false; + } + + if (vshCommandOptString(cmd, "model", &newModel) < 0 || + vshCommandOptString(cmd, "fallback", &newFallback) < 0 || + vshCommandOptString(cmd, "vendor_id", &newVendorID) < 0) { + vshError(ctl, "%s", _("missing argument")); + return false; + } + + modify = reset || newModel || newFallback || newVendorID; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if ((running = virDomainIsActive(dom)) < 0) { + vshError(ctl, "%s", _("Coud not check domain state.")); + goto cleanup; + } + + if (live && !running) { + vshError(ctl, "%s", _("--live affects only a running domain")); + goto cleanup; + } + if (modify) { + if (live || (current && running)) { + vshError(ctl, "%s", _("Cannot modify a running guest.")); + goto cleanup; + } + } + /* If modification is needed, get persistent conf regardless of + other flags because modification of model node is supported + for only persistent config. */ + if (config || (current && !running) || modify) + flags = VIR_DOMAIN_XML_INACTIVE; + + /* get domain XML */ + if (!(doc = virDomainGetXMLDesc(dom, flags))) { + vshError(ctl, "%s", _("Could not get domain XML.")); + goto cleanup; + } + + if (!(xml = virXMLParseStringCtxt(doc, _("(domain_definition)"), &ctxt))) { + vshError(ctl, "%s", _("Could not parse domain XML.")); + goto cleanup; + } + + /* Query mode: show model node info then exit. */ + if (!modify) { + curModel = virXPathString("string(./cpu[1]/model[1])", ctxt); + curFallback = virXPathString("string(./cpu[1]/model[1]/@fallback)", + ctxt); + curVendorID = virXPathString("string(./cpu[1]/model[1]/@vendor_id)", + ctxt); + + vshPrint(ctl, "model : %s\n", curModel? curModel : ""); + vshPrint(ctl, "fallback : %s\n", curFallback? curFallback : ""); + vshPrint(ctl, "vendor_id : %s\n", curVendorID? curVendorID : ""); + + ret = true; + goto cleanup; + } + + /* Modification mode: modify model node. */ + + if (reset) { + /* remove model node */ + if ((modelNode = virXPathNode("./cpu[1]/model[1]", ctxt))) { + xmlUnlinkNode(modelNode); + xmlFreeNode(modelNode); + modelNode = NULL; + } + } + + if (newModel || newFallback || newVendorID) { + /* get cpu node */ + if (!(cpuNode = virXPathNode("./cpu[1]", ctxt))) { + /* get domain node to create a new cpu node */ + if (!(domNode = virXPathNode("/domain[1]", ctxt))) { + vshError(ctl, "%s", _("Could not find domain node.")); + goto cleanup; + } + /* create a new cpu node */ + if (!(cpuNode = xmlNewChild(domNode, + NULL, + (const xmlChar*)"cpu", + NULL))) { + vshError(ctl, "%s", _("Could not create new cpu node.")); + goto cleanup; + } + } + /* get model node */ + if (!(modelNode = virXPathNode("./cpu[1]/model[1]", ctxt))) { + /* create a new model node */ + if (!(modelNode = xmlNewChild(cpuNode, + NULL, + (const xmlChar*)"model", + NULL))) { + vshError(ctl, "%s", _("Could not create new model node.")); + goto cleanup; + } + } + } + + if (newModel) { + /* modify mode attribute of the cpu node*/ + if (!xmlSetProp(cpuNode, + (const xmlChar*)"mode", + (const xmlChar*)"custom")) { + vshError(ctl, "%s", _("Could not modify mode attribute.")); + goto cleanup; + } + + escedModel = (char*)xmlEncodeEntitiesReentrant(NULL, + (const xmlChar*)newModel); + /* modify model node content */ + xmlNodeSetContent(modelNode, (const xmlChar*)escedModel); + } + + if (newFallback) { + /* modify fallback attribute of the model node */ + if (!xmlSetProp(modelNode, + (const xmlChar*)"fallback", + (const xmlChar*)newFallback)) { + vshError(ctl, "%s", _("Could not modify fallback attribute.")); + goto cleanup; + } + } + + if (newVendorID) { + /* modify vendor_id attribute of the model node */ + if (!xmlSetProp(modelNode, + (const xmlChar*)"vendor_id", + (const xmlChar*)newVendorID)) { + vshError(ctl, "%s", _("Could not modify vendor_id attribute.")); + goto cleanup; + } + } + + /* get modified domain XML */ + xmlDocDumpMemory(xml, (xmlChar**)&doc_edited, NULL); + if (!doc_edited) { + vshError(ctl, "%s", _("Could not dump edited XML doc.")); + goto cleanup; + } + + /* update domain XML */ + if (!(dom_edited = virDomainDefineXML(ctl->conn, doc_edited))) { + vshError(ctl, "%s", _("Failed to update model node.")); + goto cleanup; + } + virDomainFree(dom_edited); + + vshPrint(ctl, "%s", _("Configuration redefined successfully.\n")); + ret = true; + + cleanup: + VIR_FREE(doc_edited); + VIR_FREE(escedModel); + VIR_FREE(curVendorID); + VIR_FREE(curFallback); + VIR_FREE(curModel); + xmlFreeDoc(xml); + xmlXPathFreeContext(ctxt); + VIR_FREE(doc); + virDomainFree(dom); + return ret; +} + +/* * "create" command */ static const vshCmdInfo info_create[] = { @@ -8693,6 +8917,7 @@ const vshCmdDef domManagementCmds[] = { {"blockresize", cmdBlockResize, opts_block_resize, info_block_resize, 0}, {"change-media", cmdChangeMedia, opts_change_media, info_change_media, 0}, {"confcpu", cmdConfCPU, opts_confcpu, info_confcpu, 0}, + {"confcpu-model", cmdConfCPUModel, opts_confcpu_model, info_confcpu_model, 0}, #ifndef WIN32 {"console", cmdConsole, opts_console, info_console, 0}, #endif diff --git a/tools/virsh.pod b/tools/virsh.pod index 6374993..accf975 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -562,6 +562,33 @@ If I<--config> is specified, affect the next boot of a persistent guest. If I<--current> is specified, affect the current guest state. These three flags are mutually exclusive. +=item B<confcpu-mode> I<domain> [I<--model> I<model>] [I<--fallback> I<fallback>] [I<--vendor_id> I<vendor_id>] [I<--reset>] [[I<--current>] | [I<--live>] | [I<--config>]] + +Get or set a model node of a domain XML. +I<model> is cpu model name. If I<model> is specified, content of a model +node is modified and mode attribute of the cpu node is specified as +"custom" automatically. +I<fallback> is fallback attribute of a model node, one of "allow" and +"forbid". If I<fallback> is specified, fallback attribute is modified. +I<vendor_id> is vendor_id attribute of a model node, must be exactly +12 characters long. If I<vendor_id> is specified, vendor_id attribute +is modified. +If I<--reset> is specified, a model node is removed so that the cpu model +configuration under the model node of the domain XML will be default. +If I<model>, I<fallback> or I<vendor_id> is specified with I<--reset>, +these are added to a new model node after I<--reset> behavior. + +These modifications don't affect a running guest state but affects a +persistent configuration. + +If neither of I<mode>, I<match> and I<--reset> are specified, information +about a model node is displayed instead of being modified. + +If I<--live> is specified, affect a running guest. +If I<--config> is specified, affect the next boot of a persistent guest. +If I<--current> is specified, affect the current guest state. +These three flags are mutually exclusive. + =item B<create> I<FILE> [I<--console>] [I<--paused>] [I<--autodestroy>] Create a domain from an XML <file>. An easy way to create the XML -- 1.7.11.7