[Libvir] Add 'console' and 'vncdisplay' commands to virsh

Daniel P. Berrange berrange at redhat.com
Fri Jan 26 02:58:27 UTC 2007


The attached patch adds two new commands to virsh:

 - console  - connects to the guest's serial console
 - vncdisplay - outputs the ip address & port number of a guest vnc display

The former is another stage in eliminating the need to run 'xm' - replacing
the Xen specific 'xm console' code, with the added advantage of working
with any libvirt backend driver.

The vncdisplay is intended to make it easier for people to launch a
VNC viewer process. It prints out a IP address & port number in a format
suitable for passing to vncviewer on the command line, eg

   vncviewer `virsh vncdisplay myguest`

Regards,
Dan.
-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 
-------------- next part --------------
? src/vs.log
? src/xm.log
Index: src/Makefile.am
===================================================================
RCS file: /data/cvs/libvirt/src/Makefile.am,v
retrieving revision 1.30
diff -u -p -r1.30 Makefile.am
--- src/Makefile.am	16 Nov 2006 19:06:13 -0000	1.30
+++ src/Makefile.am	26 Jan 2007 02:53:36 -0000
@@ -32,7 +32,7 @@ libvirt_la_SOURCES =						\
 
 bin_PROGRAMS = virsh
 
-virsh_SOURCES = virsh.c
+virsh_SOURCES = virsh.c console.c console.h
 virsh_LDFLAGS =
 virsh_DEPENDENCIES = $(DEPS)
 virsh_LDADD = $(LDADDS) $(VIRSH_LIBS)
Index: src/console.c
===================================================================
RCS file: src/console.c
diff -N src/console.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/console.c	26 Jan 2007 02:53:36 -0000
@@ -0,0 +1,188 @@
+/*
+ * console.c: A dumb serial console client
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Daniel Berrange <berrange at redhat.com>
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <poll.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "console.h"
+#include "internal.h"
+
+/* ie  Ctrl-]  as per telnet */
+#define CTRL_CLOSE_BRACKET '\35'
+
+static int got_signal = 0;
+static void do_signal(int sig ATTRIBUTE_UNUSED) {
+    got_signal = 1;
+}
+
+int virRunConsole(const char *tty) {
+    int ttyfd, ret = -1;
+    struct termios ttyattr, rawattr;
+    void (*old_sigquit)(int);
+    void (*old_sigterm)(int);
+    void (*old_sigint)(int);
+    void (*old_sighup)(int);
+    void (*old_sigpipe)(int);
+
+
+    /* We do not want this to become the controlling TTY */
+    if ((ttyfd = open(tty, O_NOCTTY | O_RDWR)) < 0) {
+        fprintf(stderr, _("unable to open tty %s: %s\n"),
+                tty, strerror(errno));
+        return -1;
+    }
+
+    /* Put  STDIN into raw mode so that stuff typed
+       does not echo to the screen (the TTY reads will
+       result in it being echoed back already), and
+       also ensure Ctrl-C, etc is blocked, and misc
+       other bits */
+    if (tcgetattr(STDIN_FILENO, &ttyattr) < 0) {
+        fprintf(stderr, _("unable to get tty attributes: %s\n"),
+                strerror(errno));
+        goto closetty;
+    }
+
+    rawattr = ttyattr;
+    cfmakeraw(&rawattr);
+
+    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &rawattr) < 0) {
+        fprintf(stderr, _("unable to set tty attributes: %s\n"),
+                strerror(errno));
+        goto closetty;
+    }
+
+
+    /* Trap all common signals so that we can safely restore
+       the original terminal settings on STDIN before the
+       process exits - people don't like being left with a
+       messed up terminal ! */
+    old_sigquit = signal(SIGQUIT, do_signal);
+    old_sigterm = signal(SIGTERM, do_signal);
+    old_sigint = signal(SIGINT, do_signal);
+    old_sighup = signal(SIGHUP, do_signal);
+    old_sigpipe = signal(SIGPIPE, do_signal);
+    got_signal = 0;
+
+
+    /* Now lets process STDIN & tty forever.... */
+    for (; !got_signal ;) {
+        unsigned int i;
+        struct pollfd fds[] = {
+            { STDIN_FILENO, POLLIN, 0 },
+            { ttyfd, POLLIN, 0 },
+        };
+
+        /* Wait for data to be available for reading on
+           STDIN or the tty */
+        if (poll(fds, (sizeof(fds)/sizeof(struct pollfd)), -1) < 0) {
+            if (got_signal)
+                goto cleanup;
+
+            if (errno == EINTR || errno == EAGAIN)
+                continue;
+
+            fprintf(stderr, _("failure waiting for I/O: %s\n"),
+                    strerror(errno));
+            goto cleanup;
+        }
+
+        for (i = 0 ; i < (sizeof(fds)/sizeof(struct pollfd)) ; i++) {
+            if (!fds[i].revents)
+                continue;
+
+            /* Process incoming data available for read */
+            if (fds[i].revents & POLLIN) {
+                char buf[4096];
+                int got, sent = 0, destfd;
+
+                if ((got = read(fds[i].fd, buf, sizeof(buf))) < 0) {
+                    fprintf(stderr, _("failure reading input: %s\n"),
+                            strerror(errno));
+                    goto cleanup;
+                }
+
+                /* Quit if end of file, or we got the Ctrl-] key */
+                if (!got ||
+                    (got == 1 &&
+                     buf[0] == CTRL_CLOSE_BRACKET))
+                    goto done;
+
+                /* Data from stdin goes to the TTY,
+                   data from the TTY goes to STDOUT */
+                if (fds[i].fd == STDIN_FILENO)
+                    destfd = ttyfd;
+                else
+                    destfd = STDOUT_FILENO;
+
+                while (sent < got) {
+                    int done;
+                    if ((done = write(destfd, buf + sent, got - sent)) <= 0) {
+                        fprintf(stderr, _("failure writing output: %s\n"),
+                                strerror(errno));
+                        goto cleanup;
+                    }
+                    sent += done;
+                }
+            } else { /* Any other flag from poll is an error condition */
+                goto cleanup;
+            }
+        }
+    }
+ done:
+    ret = 0;
+
+ cleanup:
+
+    /* Restore original signal handlers */
+    signal(SIGQUIT, old_sigpipe);
+    signal(SIGQUIT, old_sighup);
+    signal(SIGQUIT, old_sigint);
+    signal(SIGQUIT, old_sigterm);
+    signal(SIGQUIT, old_sigquit);
+
+    /* Put STDIN back into the (sane?) state we found
+       it in before starting */
+    tcsetattr(STDIN_FILENO, TCSAFLUSH, &ttyattr);
+
+ closetty:
+    close(ttyfd);
+
+    return ret;
+}
+
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
Index: src/console.h
===================================================================
RCS file: src/console.h
diff -N src/console.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/console.h	26 Jan 2007 02:53:36 -0000
@@ -0,0 +1,45 @@
+/*
+ * console.c: A dumb serial console client
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Daniel Berrange <berrange at redhat.com>
+ */
+
+#ifndef __VIR_CONSOLE_H__
+#define __VIR_CONSOLE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    int virRunConsole(const char *tty);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __VIR_CONSOLE_H__ */
+
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
Index: src/virsh.c
===================================================================
RCS file: /data/cvs/libvirt/src/virsh.c,v
retrieving revision 1.44
diff -u -p -r1.44 virsh.c
--- src/virsh.c	23 Jan 2007 14:39:45 -0000	1.44
+++ src/virsh.c	26 Jan 2007 02:53:38 -0000
@@ -1,5 +1,5 @@
 /*
- * virsh.c: a Xen shell used to exercise the libvir API
+ * virsh.c: a Xen shell used to exercise the libvirt API
  *
  * Copyright (C) 2005 Red Hat, Inc.
  *
@@ -29,11 +29,16 @@
 #include <fcntl.h>
 #include <locale.h>
 
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+
 #include <readline/readline.h>
 #include <readline/history.h>
 
 #include "config.h"
 #include "internal.h"
+#include "console.h"
 
 static char *progname;
 
@@ -306,6 +311,71 @@ cmdConnect(vshControl * ctl, vshCmd * cm
 }
 
 /*
+ * "console" command 
+ */
+static vshCmdInfo info_console[] = {
+    {"syntax", "console <domain>"},
+    {"help", gettext_noop("connect to the guest console")},
+    {"desc",
+     gettext_noop("Connect the virtual serial console for the guest")},
+    {NULL, NULL}
+};
+
+static vshCmdOptDef opts_console[] = {
+    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")},
+    {NULL, 0, 0, NULL}
+};
+
+static int
+cmdConsole(vshControl * ctl, vshCmd * cmd)
+{
+    xmlDocPtr xml = NULL;
+    xmlXPathObjectPtr obj = NULL;
+    xmlXPathContextPtr ctxt = NULL;
+    virDomainPtr dom;
+    int ret = FALSE;
+    char *doc;
+
+    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+        return FALSE;
+
+    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
+        return FALSE;
+
+    doc = virDomainGetXMLDesc(dom, 0);
+    if (!doc)
+	goto cleanup;
+
+    xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
+		     XML_PARSE_NOENT | XML_PARSE_NONET |
+		     XML_PARSE_NOWARNING);
+    free(doc);
+    if (!xml)
+        goto cleanup;
+    ctxt = xmlXPathNewContext(xml);
+    if (!ctxt)
+        goto cleanup;
+
+    obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt);
+    if ((obj != NULL) && ((obj->type == XPATH_STRING) &&
+        (obj->stringval != NULL) && (obj->stringval[0] != 0))) {
+        if (virRunConsole((const char *)obj->stringval) == 0)
+            ret = TRUE;
+    } else {
+        vshPrintExtra(ctl, _("No console available for domain\n"));
+    }
+    xmlXPathFreeObject(obj);
+
+ cleanup:
+    if (ctxt)
+        xmlXPathFreeContext(ctxt);
+    if (xml)
+        xmlFreeDoc(xml);
+    virDomainFree(dom);
+    return ret;
+}
+
+/*
  * "list" command
  */
 static vshCmdInfo info_list[] = {
@@ -1633,6 +1703,88 @@ cmdVersion(vshControl * ctl, vshCmd * cm
 }
 
 /*
+ * "dumpxml" command
+ */
+static vshCmdInfo info_vncdisplay[] = {
+    {"syntax", "vncdisplay <domain>"},
+    {"help", gettext_noop("vnc display")},
+    {"desc", gettext_noop("Ouput the IP address and port number for the VNC display.")},
+    {NULL, NULL}
+};
+
+static vshCmdOptDef opts_vncdisplay[] = {
+    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")},
+    {NULL, 0, 0, NULL}
+};
+
+static int
+cmdVNCDisplay(vshControl * ctl, vshCmd * cmd)
+{
+    xmlDocPtr xml = NULL;
+    xmlXPathObjectPtr obj = NULL;
+    xmlXPathContextPtr ctxt = NULL;
+    virDomainPtr dom;
+    int ret = FALSE;
+    int port = 0;
+    char *doc;
+
+    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+        return FALSE;
+
+    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
+        return FALSE;
+
+    doc = virDomainGetXMLDesc(dom, 0);
+    if (!doc)
+	goto cleanup;
+
+    xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
+		     XML_PARSE_NOENT | XML_PARSE_NONET |
+		     XML_PARSE_NOWARNING);
+    free(doc);
+    if (!xml)
+        goto cleanup;
+    ctxt = xmlXPathNewContext(xml);
+    if (!ctxt)
+        goto cleanup;
+
+    obj = xmlXPathEval(BAD_CAST "string(/domain/devices/graphics[@type='vnc']/@port)", ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+	(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+        goto cleanup;
+    }
+    port = strtol((const char *)obj->stringval, NULL, 10);
+    if (port == -1) {
+      goto cleanup;
+    }
+    xmlXPathFreeObject(obj);
+
+    obj = xmlXPathEval(BAD_CAST "string(/domain/devices/graphics[@type='vnc']/@listen)", ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+	(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+        goto cleanup;
+    }
+    if (!strcmp((const char*)obj->stringval, "0.0.0.0")) {
+        vshPrint(ctl, ":%d\n", port-5900);
+    } else {
+        vshPrint(ctl, "%s:%d\n", (const char *)obj->stringval, port-5900);
+    }
+    xmlXPathFreeObject(obj);
+    obj = NULL;
+
+ cleanup:
+    if (obj)
+      xmlXPathFreeObject(obj);
+    if (ctxt)
+        xmlXPathFreeContext(ctxt);
+    if (xml)
+        xmlFreeDoc(xml);
+    virDomainFree(dom);
+    return ret;
+}
+
+
+/*
  * "quit" command
  */
 static vshCmdInfo info_quit[] = {
@@ -1653,6 +1805,7 @@ cmdQuit(vshControl * ctl, vshCmd * cmd A
  */
 static vshCmdDef commands[] = {
     {"connect", cmdConnect, opts_connect, info_connect},
+    {"console", cmdConsole, opts_console, info_console},
     {"create", cmdCreate, opts_create, info_create},
     {"start", cmdStart, opts_start, info_start},
     {"destroy", cmdDestroy, opts_destroy, info_destroy},
@@ -1681,6 +1834,7 @@ static vshCmdDef commands[] = {
     {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo},
     {"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin},
     {"version", cmdVersion, NULL, info_version},
+    {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay},
     {NULL, NULL, NULL, NULL}
 };
 


More information about the libvir-list mailing list