[libvirt] [PATCH 0/2] Add virsh commands to modify cpu node and model node of a domain XML

From: Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com> This patchset adds two virsh commands, "confcpu" and "confcpu-model". "confcpu" allows to modify 'mode' attirbute and 'match' attribute of a cpu node of a domain XML. "confcpu-model" allows to modify cpu model, 'fallback' attribute and 'vendor_id' attribute of a model node of a domain XML. By using these commands, we can easily change cpu mode, model and etc. by hand or shellscript without editing XML. Ken ICHIKAWA (2): virsh: Add a new command "confcpu" virsh: Add a new command "confcpu-model" tools/virsh-domain.c | 411 +++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 51 +++++++ 2 files changed, 462 insertions(+) -- 1.7.11.7

From: Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com> This patch adds a new virsh command "confcpu", that allows to show and modify mode attribute and match attribute of a cpu node of a domain XML. Modification is supported for only persistent configuration. Examples of usage: change cpu mode to "host-passthrough" virsh # confcpu <domain> --mode host-passthrough change match attribute to "minimum" virsh # confcpu <domain> --match minimum reset all cpu configuration under a cpu node of a domain XML virsh # confcpu <domain> --reset show cpu node attirbutes of a running guest virsh # confcpu <domain> --live Signed-off-by: Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com> --- tools/virsh-domain.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 24 +++++++ 2 files changed, 210 insertions(+) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index f3da1d5..913a1b4 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -5526,6 +5526,191 @@ failed_stats: } /* + * "confcpu" command + */ +static const vshCmdInfo info_confcpu[] = { + {"help", N_("show or modify domain cpu node attributes")}, + {"desc", N_("Show or modify cpu node attributes of a domain XML")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_confcpu[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"mode", VSH_OT_DATA, 0, + N_("mode attribute, one of custom, host-model and host-passthrough")}, + {"match", VSH_OT_DATA, 0, + N_("match attribute, one of minimum, exact and strict")}, + {"reset", VSH_OT_BOOL, 0, + N_("remove a cpu node including child nodes 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 +cmdConfCPU(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + virDomainPtr dom_edited = NULL; + const char *newMode = NULL; + char *curMode = NULL; + const char *newMatch = NULL; + char *curMatch = 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; + + if (current + config + live > 1) { + vshError(ctl, "%s", + _("--config, --live, and --current are mutually exclusive")); + return false; + } + + if (vshCommandOptString(cmd, "mode", &newMode) < 0 || + vshCommandOptString(cmd, "match", &newMatch) < 0) { + vshError(ctl, "%s", _("missing argument")); + return false; + } + + modify = reset || newMode || newMatch; + + 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 cpu 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 cpu node attributes then exit. */ + if (!modify) { + curMode = virXPathString("string(./cpu[1]/@mode)", ctxt); + curMatch = virXPathString("string(./cpu[1]/@match)", ctxt); + vshPrint(ctl, "mode : %s\n", curMode? curMode : ""); + vshPrint(ctl, "match : %s\n", curMatch? curMatch : ""); + + ret = true; + goto cleanup; + } + + /* Modification mode: modify cpu node. */ + + if (reset) { + /* remove cpu node */ + if ((cpuNode = virXPathNode("./cpu[1]", ctxt))) { + xmlUnlinkNode(cpuNode); + xmlFreeNode(cpuNode); + cpuNode = NULL; + } + } + + if (newMode || newMatch) { + /* 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; + } + } + } + + if (newMode) { + /* modify mode attribute of the cpu node*/ + if (!xmlSetProp(cpuNode, + (const xmlChar*)"mode", + (const xmlChar*)newMode)) { + vshError(ctl, "%s", _("Could not modify mode attribute.")); + goto cleanup; + } + } + + if (newMatch) { + /* modify match attribute of the cpu node*/ + if (!xmlSetProp(cpuNode, + (const xmlChar*)"match", + (const xmlChar*)newMatch)) { + vshError(ctl, "%s", _("Could not modify match 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 cpu node.")); + goto cleanup; + } + virDomainFree(dom_edited); + + vshPrint(ctl, "%s", _("Configuration redefined successfully.\n")); + ret = true; + + cleanup: + VIR_FREE(doc_edited); + VIR_FREE(curMatch); + VIR_FREE(curMode); + xmlFreeDoc(xml); + xmlXPathFreeContext(ctxt); + VIR_FREE(doc); + virDomainFree(dom); + return ret; +} + +/* * "create" command */ static const vshCmdInfo info_create[] = { @@ -8507,6 +8692,7 @@ const vshCmdDef domManagementCmds[] = { {"blockpull", cmdBlockPull, opts_block_pull, info_block_pull, 0}, {"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}, #ifndef WIN32 {"console", cmdConsole, opts_console, info_console, 0}, #endif diff --git a/tools/virsh.pod b/tools/virsh.pod index 3687a4d..6374993 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -538,6 +538,30 @@ the server has to ensure exclusive access to console devices. Optionally the I<--force> flag may be specified, requesting to disconnect any existing sessions, such as in a case of a broken connection. +=item B<confcpu> I<domain> [I<--mode> I<mode>] [I<--match> I<match>] [I<--reset>] [[I<--current>] | [I<--live>] | [I<--config>]] + +Get or set cpu node attributes of a domain XML. +I<mode> is mode attribute of a cpu node, one of "custom", "host-model" +and "host-passthrough". If I<mode> is specified, mode attribute is modified. +I<match> is match attribute of a cpu node, one of "minimum", "exact", +and "strict". If I<match> is specified, match attribute is modified. +If I<--reset> is specified, a cpu node is removed including the child +nodes, so that the cpu configuration under the cpu node of the domain XML +will be default. +If I<mode> or I<match> is specified with I<--reset>, these attributes +are added to a new cpu 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, attributes +of a cpu node are 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

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

ping. I'd like to get any comment or advice. Thank you for considering my request. Ken Ichikawa (2012/12/25 17:40), Ken ICHIKAWA wrote:
From: Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com>
This patchset adds two virsh commands, "confcpu" and "confcpu-model".
"confcpu" allows to modify 'mode' attirbute and 'match' attribute of a cpu node of a domain XML. "confcpu-model" allows to modify cpu model, 'fallback' attribute and 'vendor_id' attribute of a model node of a domain XML.
By using these commands, we can easily change cpu mode, model and etc. by hand or shellscript without editing XML.
Ken ICHIKAWA (2): virsh: Add a new command "confcpu" virsh: Add a new command "confcpu-model"
tools/virsh-domain.c | 411 +++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 51 +++++++ 2 files changed, 462 insertions(+)
participants (1)
-
Ken ICHIKAWA