One thing which is very apparent is that sys admins using libvirt / virsh have a great deal of difficulty understanding "where the configuration files have gone" and how to edit them. This patch adds a "virsh edit <domain>" command which is basically the equivalent of: virsh dumpxml dom > /tmp/dom.xml $EDITOR /tmp/dom.xml && virsh define /tmp/dom.xml but with much more sanity checking. The editor is $EDITOR or vi, and it does the right thing if the user doesn't modify the file, or if another user edits the configuration at the same time. Rich. -- Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones virt-p2v converts physical machines to virtual machines. Boot with a live CD or over the network (PXE) and turn machines into Xen guests. http://et.redhat.com/~rjones/virt-p2v
Index: docs/virsh.pod =================================================================== RCS file: /data/cvs/libvirt/docs/virsh.pod,v retrieving revision 1.16 diff -u -r1.16 virsh.pod --- docs/virsh.pod 15 May 2008 06:12:32 -0000 1.16 +++ docs/virsh.pod 29 Jul 2008 12:21:38 -0000 @@ -277,6 +277,19 @@ Output the domain information as an XML dump to stdout, this format can be used by the B<create> command. +=item B<edit> I<domain-id> + +Edit the XML configuration file for a domain. + +This is equivalent to: + virsh dumpxml domain > domain.xml + edit domain.xml + virsh define domain.xml +except that it does some error checking. + +The editor used can be supplied by the C<$EDITOR> environment +variable, or if that is not defined defaults to C<vi>. + =item B<migrate> optional I<--live> I<domain-id> I<desturi> I<migrateuri> Migrate domain to another host. Add --live for live migration. The I<desturi> Index: src/virsh.c =================================================================== RCS file: /data/cvs/libvirt/src/virsh.c,v retrieving revision 1.157 diff -u -r1.157 virsh.c --- src/virsh.c 22 Jul 2008 16:12:01 -0000 1.157 +++ src/virsh.c 29 Jul 2008 12:21:42 -0000 @@ -5070,6 +5070,179 @@ } /* + * "edit" command + */ +static vshCmdInfo info_edit[] = { + {"syntax", "edit <domain>"}, + {"help", gettext_noop("edit XML configuration for a domain")}, + {"desc", gettext_noop("Edit the XML configuration for a domain.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_edit[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdEdit (vshControl *ctl, vshCmd *cmd) +{ + int ret = FALSE; + virDomainPtr dom = NULL; + char *doc = NULL; + char *tmp = NULL; + int fd = -1; + const char *editor; + char command[100]; + int command_ret; + char *doc_edited = NULL; + struct stat statbuf; + char *doc_reread = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + goto cleanup; + + dom = vshCommandOptDomain (ctl, cmd, "domain", NULL); + if (dom == NULL) + goto cleanup; + + /* Get the XML configuration of the domain. */ + doc = virDomainGetXMLDesc (dom, 0); + if (!doc) + goto cleanup; + + /* Create and open the temporary file. */ + tmp = tempnam (NULL, "virsh"); + if (!tmp) { + vshError(ctl, FALSE, + _("tempnam: failed to create temporary file: %s"), + strerror (errno)); + goto cleanup; + } + fd = open (tmp, O_EXCL|O_CREAT|O_WRONLY, 0600); + if (fd == -1) { + vshError(ctl, FALSE, + _("open: %s: failed to create temporary file: %s"), + tmp, strerror (errno)); + goto cleanup; + } + + if (safewrite (fd, doc, strlen (doc)) == -1) { + vshError(ctl, FALSE, + _("write: %s: failed to create temporary file: %s"), + tmp, strerror (errno)); + goto cleanup; + } + if (close (fd) == -1) { + vshError(ctl, FALSE, + _("close: %s: failed to create temporary file: %s"), + tmp, strerror (errno)); + goto cleanup; + } + fd = -1; + + /* Start the editor. */ + editor = getenv ("EDITOR"); + if (!editor) editor = "vi"; /* could be cruel & default to ed(1) here */ + + snprintf (command, sizeof command, "%s %s", editor, tmp); + command_ret = system (command); + + if (command_ret == -1) { + vshError(ctl, FALSE, + "%s: %s", + command, strerror (errno)); + goto cleanup; + } + if (command_ret != WEXITSTATUS (0)) { + vshError(ctl, FALSE, + _("%s: command exited with non-zero status"), command); + goto cleanup; + } + + /* Read back the edited XML file. */ + fd = open (tmp, O_RDONLY); + if (fd == -1) { + vshError(ctl, FALSE, + _("open: %s: failed to read temporary file: %s"), + tmp, strerror (errno)); + goto cleanup; + } + if (fstat (fd, &statbuf) == -1) { + vshError(ctl, FALSE, + _("stat: %s: failed to read temporary file: %s"), + tmp, strerror (errno)); + goto cleanup; + } + doc_edited = malloc (statbuf.st_size + 1); + if (!doc_edited) { + vshError(ctl, FALSE, + _("malloc: failed to allocate memory for file: %s"), + strerror (errno)); + goto cleanup; + } + doc_edited[statbuf.st_size+1] = '\0'; + if (saferead (fd, doc_edited, statbuf.st_size) == -1) { + vshError(ctl, FALSE, + _("read: %s: failed to read temporary file: %s"), + tmp, strerror (errno)); + goto cleanup; + } + close (fd); + fd = -1; + + unlink (tmp); + tmp = NULL; + + /* Compare original XML with edited. Has it changed at all? */ + if (STREQ (doc, doc_edited)) { + vshPrint(ctl, _("Domain %s XML configuration not changed.\n"), + virDomainGetName (dom)); + ret = TRUE; + goto cleanup; + } + + /* Now re-read the domain XML. Did someone else change it while + * it was being edited? This also catches problems such as us + * losing a connection or the domain going away. + */ + doc_reread = virDomainGetXMLDesc (dom, 0); + if (!doc_reread) + goto cleanup; + + if (STRNEQ (doc, doc_reread)) { + vshError (ctl, FALSE, + _("ERROR: the XML configuration was changed by another user")); + goto cleanup; + } + + /* Everything checks out, so redefine the domain. */ + virDomainFree (dom); + dom = virDomainDefineXML(ctl->conn, doc_edited); + if (!dom) + goto cleanup; + + vshPrint(ctl, _("Domain %s XML configuration edited.\n"), + virDomainGetName(dom)); + + ret = TRUE; + + cleanup: + if (fd >= 0) + close (fd); + if (dom) + virDomainFree(dom); + free (doc); + free (doc_edited); + if (tmp) { + unlink (tmp); + free (tmp); + } + + return ret; +} + +/* * "quit" command */ static vshCmdInfo info_quit[] = { @@ -5112,6 +5285,7 @@ {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat}, {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat}, {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml}, + {"edit", cmdEdit, opts_edit, info_edit}, {"freecell", cmdFreecell, opts_freecell, info_freecell}, {"hostname", cmdHostname, NULL, info_hostname}, {"list", cmdList, opts_list, info_list},
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list