From: Ken ICHIKAWA <ichikawa.ken(a)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(a)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