Now you can edit a saved state file even if you forgot to grab a dumpxml file prior to saving a domain. Plus, in-place editing feels so much nicer. * tools/virsh.c (cmdSaveImageDumpxml, cmdSaveImageDefine) (cmdSaveImageEdit): New commands. * tools/virsh.pod (save-image-dumpxml, save-image-define) (save-image-edit): Document them. --- Needs the next patch to be testable. 'save-image-edit' feels a bit long, but I couldn't think of something shorter. Should I keep the new save-image-* commands in the main domain group, or should I create a new save-image group, in case we add more later? tools/virsh.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 31 ++++++++++ 2 files changed, 209 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index dece917..1701f09 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -1659,6 +1659,178 @@ cleanup: } /* + * "save-image-dumpxml" command + */ +static const vshCmdInfo info_save_image_dumpxml[] = { + {"help", N_("saved state domain information in XML")}, + {"desc", N_("Output the domain information for a saved state file,\n" + "as an XML dump to stdout.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_save_image_dumpxml[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("saved state file to read")}, + {"security-info", VSH_OT_BOOL, 0, N_("include security sensitive information in XML dump")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSaveImageDumpxml(vshControl *ctl, const vshCmd *cmd) +{ + const char *file = NULL; + bool ret = false; + int flags = 0; + char *xml = NULL; + + if (vshCommandOptBool(cmd, "security-info")) + flags |= VIR_DOMAIN_XML_SECURE; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "file", &file) <= 0) + return false; + + xml = virDomainSaveImageGetXMLDesc(ctl->conn, file, flags); + if (!xml) + goto cleanup; + + vshPrint(ctl, "%s", xml); + ret = true; + +cleanup: + VIR_FREE(xml); + return ret; +} + +/* + * "save-image-define" command + */ +static const vshCmdInfo info_save_image_define[] = { + {"help", N_("redefine the XML for a domain's saved state file")}, + {"desc", N_("Replace the domain XML associated with a saved state file")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_save_image_define[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("saved state file to modify")}, + {"xml", VSH_OT_STRING, VSH_OFLAG_REQ, + N_("filename containing updated XML for the target")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSaveImageDefine(vshControl *ctl, const vshCmd *cmd) +{ + const char *file = NULL; + bool ret = false; + const char *xmlfile = NULL; + char *xml = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "file", &file) <= 0) + return false; + + if (vshCommandOptString(cmd, "xml", &xmlfile) <= 0) { + vshError(ctl, "%s", _("malformed or missing xml argument")); + return false; + } + + if (virFileReadAll(xmlfile, 8192, &xml) < 0) + goto cleanup; + + if (virDomainSaveImageDefineXML(ctl->conn, file, xml, 0) < 0) { + vshError(ctl, _("Failed to update %s"), file); + goto cleanup; + } + + vshPrint(ctl, _("State file %s updated.\n"), file); + ret = true; + +cleanup: + VIR_FREE(xml); + return ret; +} + +/* + * "save-image-edit" command + */ +static const vshCmdInfo info_save_image_edit[] = { + {"help", N_("edit XML for a domain's saved state file")}, + {"desc", N_("Edit the domain XML associated with a saved state file")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_save_image_edit[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("saved state file to edit")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSaveImageEdit(vshControl *ctl, const vshCmd *cmd) +{ + const char *file = NULL; + bool ret = false; + char *tmp = NULL; + char *doc = NULL; + char *doc_edited = NULL; + int flags = VIR_DOMAIN_XML_SECURE; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "file", &file) <= 0) + return false; + + /* Get the XML configuration of the saved image. */ + doc = virDomainSaveImageGetXMLDesc(ctl->conn, file, flags); + if (!doc) + goto cleanup; + + /* Create and open the temporary file. */ + tmp = editWriteToTempFile(ctl, doc); + if (!tmp) + goto cleanup; + + /* Start the editor. */ + if (editFile(ctl, tmp) == -1) + goto cleanup; + + /* Read back the edited file. */ + doc_edited = editReadBackFile(ctl, tmp); + if (!doc_edited) + goto cleanup; + + /* Compare original XML with edited. Has it changed at all? */ + if (STREQ(doc, doc_edited)) { + vshPrint(ctl, _("Saved image %s XML configuration not changed.\n"), + file); + ret = true; + goto cleanup; + } + + /* Everything checks out, so redefine the xml. */ + if (virDomainSaveImageDefineXML(ctl->conn, file, doc_edited, 0) < 0) { + vshError(ctl, _("Failed to update %s"), file); + goto cleanup; + } + + vshPrint(ctl, _("State file %s edited.\n"), file); + ret = true; + +cleanup: + VIR_FREE(doc); + VIR_FREE(doc_edited); + if (tmp) { + unlink(tmp); + VIR_FREE(tmp); + } + return ret; +} + +/* * "managedsave" command */ static const vshCmdInfo info_managedsave[] = { @@ -12084,6 +12256,12 @@ static const vshCmdDef domManagementCmds[] = { {"restore", cmdRestore, opts_restore, info_restore, 0}, {"resume", cmdResume, opts_resume, info_resume, 0}, {"save", cmdSave, opts_save, info_save, 0}, + {"save-image-define", cmdSaveImageDefine, opts_save_image_define, + info_save_image_define, 0}, + {"save-image-dumpxml", cmdSaveImageDumpxml, opts_save_image_dumpxml, + info_save_image_dumpxml, 0}, + {"save-image-edit", cmdSaveImageEdit, opts_save_image_edit, + info_save_image_edit, 0}, {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo, 0}, {"screenshot", cmdScreenshot, opts_screenshot, info_screenshot, 0}, {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem, 0}, diff --git a/tools/virsh.pod b/tools/virsh.pod index f2fd9ed..b31d374 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -642,6 +642,37 @@ between the creation and restore point. For a more complete system restore point, where the disk state is saved alongside the memory state, see the B<snapshot> family of commands. +=item B<save-image-define> I<file> I<xml> + +Update the domain XML that will be used when I<file> is later +used in the B<restore> command. The I<xml> argument must be a file +name containing the alternative XML, with changes only in the +host-specific portions of the domain XML. For example, it can +be used to account for file naming differences resulting from creating +disk snapshots of underlying storage after the guest was saved. + +=item B<save-image-dumpxml> I<file> [I<--security-info>] + +Extract the domain XML that was in effect at the time the saved state +file I<file> was created with the B<save> command. Using +I<--security-info> will also include security sensitive information. + +=item B<save-image-edit> I<file> + +Edit the XML configuration associated with a saved state file I<file> +created by the B<save> command. + +This is equivalent to: + + virsh save-image-dumpxml state-file > state-file.xml + vi state-file.xml (or make changes with your other text editor) + virsh save-image-define state-file state-file-xml + +except that it does some error checking. + +The editor used can be supplied by the C<$VISUAL> or C<$EDITOR> environment +variables, and defaults to C<vi>. + =item B<schedinfo> [I<--set> B<parameter=value>] I<domain-id> [[I<--config>] [I<--live>] | [I<--current>]] -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list