[libvirt] PATCH: Allow running of console after creating guest

This patch adds a new flag to the 'create' and 'start' commands in virsh, making it immeditely spawn the builtin virsh console, eg # virsh start --console demo At the same time, I also add in a check for virConnectGetHostname() against the local hostname, and refuse to launch the console if they differ. With remote hypervisors it is obviously not possible to access the /dev/pts files directly. Without this check, the console may work by pure luck if there happens to be a matching device name on the local host. Rather confusing, and even potentially dangerous. # virsh -c qemu+ssh://root@demo.example.com/system console someguest error: Cannot connect to a remote console device Finally, when starting the console print a message telling the user the hotkey to quit # virsh start --console VirtTest Domain VirtTest started Connecting to console, type Ctrl+] to quit Daniel diff -r a203154020dd src/virsh.c --- a/src/virsh.c Wed Apr 01 11:57:25 2009 +0100 +++ b/src/virsh.c Wed Apr 01 13:36:40 2009 +0100 @@ -500,20 +500,30 @@ static const vshCmdOptDef opts_console[] #ifndef __MINGW32__ static int -cmdConsole(vshControl *ctl, const vshCmd *cmd) +cmdRunConsole(vshControl *ctl, virDomainPtr dom) { 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, NULL))) - return FALSE; + char *thatHost = NULL; + char *thisHost = NULL; + + if (!(thisHost = virGetHostname())) { + vshError(ctl, FALSE, "%s", _("Failed to get local hostname")); + goto cleanup; + } + + if (!(thatHost = virConnectGetHostname(ctl->conn))) { + vshError(ctl, FALSE, "%s", _("Failed to get connection hostname")); + goto cleanup; + } + + if (STRNEQ(thisHost, thatHost)) { + vshError(ctl, FALSE, "%s", _("Cannot connect to a remote console device")); + goto cleanup; + } doc = virDomainGetXMLDesc(dom, 0); if (!doc) @@ -532,6 +542,7 @@ cmdConsole(vshControl *ctl, const vshCmd obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt); if ((obj != NULL) && ((obj->type == XPATH_STRING) && (obj->stringval != NULL) && (obj->stringval[0] != 0))) { + vshPrintExtra(ctl, "%s", _("Connecting to console, type Ctrl+] to quit\n")); if (vshRunConsole((const char *)obj->stringval) == 0) ret = TRUE; } else { @@ -543,14 +554,16 @@ cmdConsole(vshControl *ctl, const vshCmd xmlXPathFreeContext(ctxt); if (xml) xmlFreeDoc(xml); - virDomainFree(dom); + free(thisHost); + free(thatHost); + return ret; } #else /* __MINGW32__ */ static int -cmdConsole(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +cmdRunConsole(vshControl *ctl, virDomainPtr dom ATTRIBUTE_UNUSED) { vshError (ctl, FALSE, "%s", _("console not implemented on this platform")); return FALSE; @@ -558,6 +571,24 @@ cmdConsole(vshControl *ctl, const vshCmd #endif /* __MINGW32__ */ +static int +cmdConsole(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int ret; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return FALSE; + + ret = cmdRunConsole(ctl, dom); + + virDomainFree(dom); + return ret; +} + /* * "list" command */ @@ -882,6 +913,7 @@ static const vshCmdInfo info_create[] = static const vshCmdOptDef opts_create[] = { {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing an XML domain description")}, + {"console", VSH_OT_BOOL, 0, gettext_noop("attach to console after creation")}, {NULL, 0, 0, NULL} }; @@ -893,6 +925,7 @@ cmdCreate(vshControl *ctl, const vshCmd int found; int ret = TRUE; char *buffer; + int console = vshCommandOptBool(cmd, "console"); if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) return FALSE; @@ -910,6 +943,8 @@ cmdCreate(vshControl *ctl, const vshCmd if (dom != NULL) { vshPrint(ctl, _("Domain %s created from %s\n"), virDomainGetName(dom), from); + if (console) + cmdRunConsole(ctl, dom); virDomainFree(dom); } else { vshError(ctl, FALSE, _("Failed to create domain from %s"), from); @@ -1030,6 +1065,7 @@ static const vshCmdInfo info_start[] = { static const vshCmdOptDef opts_start[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the inactive domain")}, + {"console", VSH_OT_BOOL, 0, gettext_noop("attach to console after creation")}, {NULL, 0, 0, NULL} }; @@ -1038,6 +1074,7 @@ cmdStart(vshControl *ctl, const vshCmd * { virDomainPtr dom; int ret = TRUE; + int console = vshCommandOptBool(cmd, "console"); if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) return FALSE; @@ -1054,6 +1091,8 @@ cmdStart(vshControl *ctl, const vshCmd * if (virDomainCreate(dom) == 0) { vshPrint(ctl, _("Domain %s started\n"), virDomainGetName(dom)); + if (console) + cmdRunConsole(ctl, dom); } else { vshError(ctl, FALSE, _("Failed to start domain %s"), virDomainGetName(dom)); -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Wed, Apr 01, 2009 at 01:47:26PM +0100, Daniel P. Berrange wrote:
Finally, when starting the console print a message telling the user the hotkey to quit
# virsh start --console VirtTest Domain VirtTest started Connecting to console, type Ctrl+] to quit
Can we please make this the same as telnet (and virt-console): 514 if (!retrying && verbose) { 515 printf("Connected to domain %s\n", dom_name); 516 printf("Escape character is '^]'\n"); regards john

On Wed, Apr 01, 2009 at 08:51:14AM -0400, John Levon wrote:
On Wed, Apr 01, 2009 at 01:47:26PM +0100, Daniel P. Berrange wrote:
Finally, when starting the console print a message telling the user the hotkey to quit
# virsh start --console VirtTest Domain VirtTest started Connecting to console, type Ctrl+] to quit
Can we please make this the same as telnet (and virt-console):
514 if (!retrying && verbose) { 515 printf("Connected to domain %s\n", dom_name); 516 printf("Escape character is '^]'\n");
Sure, this patch makes that change... FYI, I'd like to update the virt-console patch to current CVS and get it merged after 0.6.2 release is cut. Daniel diff -r a203154020dd src/virsh.c --- a/src/virsh.c Wed Apr 01 11:57:25 2009 +0100 +++ b/src/virsh.c Wed Apr 01 14:30:29 2009 +0100 @@ -500,20 +500,30 @@ static const vshCmdOptDef opts_console[] #ifndef __MINGW32__ static int -cmdConsole(vshControl *ctl, const vshCmd *cmd) +cmdRunConsole(vshControl *ctl, virDomainPtr dom) { 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, NULL))) - return FALSE; + char *thatHost = NULL; + char *thisHost = NULL; + + if (!(thisHost = virGetHostname())) { + vshError(ctl, FALSE, "%s", _("Failed to get local hostname")); + goto cleanup; + } + + if (!(thatHost = virConnectGetHostname(ctl->conn))) { + vshError(ctl, FALSE, "%s", _("Failed to get connection hostname")); + goto cleanup; + } + + if (STRNEQ(thisHost, thatHost)) { + vshError(ctl, FALSE, "%s", _("Cannot connect to a remote console device")); + goto cleanup; + } doc = virDomainGetXMLDesc(dom, 0); if (!doc) @@ -532,6 +542,8 @@ cmdConsole(vshControl *ctl, const vshCmd obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt); if ((obj != NULL) && ((obj->type == XPATH_STRING) && (obj->stringval != NULL) && (obj->stringval[0] != 0))) { + vshPrintExtra(ctl, _("Connected to domain %s\n"), virDomainGetName(dom)); + vshPrintExtra(ctl, "%s", _("Escape caharacter is ^]\n")); if (vshRunConsole((const char *)obj->stringval) == 0) ret = TRUE; } else { @@ -543,14 +555,16 @@ cmdConsole(vshControl *ctl, const vshCmd xmlXPathFreeContext(ctxt); if (xml) xmlFreeDoc(xml); - virDomainFree(dom); + free(thisHost); + free(thatHost); + return ret; } #else /* __MINGW32__ */ static int -cmdConsole(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +cmdRunConsole(vshControl *ctl, virDomainPtr dom ATTRIBUTE_UNUSED) { vshError (ctl, FALSE, "%s", _("console not implemented on this platform")); return FALSE; @@ -558,6 +572,24 @@ cmdConsole(vshControl *ctl, const vshCmd #endif /* __MINGW32__ */ +static int +cmdConsole(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int ret; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return FALSE; + + ret = cmdRunConsole(ctl, dom); + + virDomainFree(dom); + return ret; +} + /* * "list" command */ @@ -882,6 +914,7 @@ static const vshCmdInfo info_create[] = static const vshCmdOptDef opts_create[] = { {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing an XML domain description")}, + {"console", VSH_OT_BOOL, 0, gettext_noop("attach to console after creation")}, {NULL, 0, 0, NULL} }; @@ -893,6 +926,7 @@ cmdCreate(vshControl *ctl, const vshCmd int found; int ret = TRUE; char *buffer; + int console = vshCommandOptBool(cmd, "console"); if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) return FALSE; @@ -910,6 +944,8 @@ cmdCreate(vshControl *ctl, const vshCmd if (dom != NULL) { vshPrint(ctl, _("Domain %s created from %s\n"), virDomainGetName(dom), from); + if (console) + cmdRunConsole(ctl, dom); virDomainFree(dom); } else { vshError(ctl, FALSE, _("Failed to create domain from %s"), from); @@ -1030,6 +1066,7 @@ static const vshCmdInfo info_start[] = { static const vshCmdOptDef opts_start[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the inactive domain")}, + {"console", VSH_OT_BOOL, 0, gettext_noop("attach to console after creation")}, {NULL, 0, 0, NULL} }; @@ -1038,6 +1075,7 @@ cmdStart(vshControl *ctl, const vshCmd * { virDomainPtr dom; int ret = TRUE; + int console = vshCommandOptBool(cmd, "console"); if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) return FALSE; @@ -1054,6 +1092,8 @@ cmdStart(vshControl *ctl, const vshCmd * if (virDomainCreate(dom) == 0) { vshPrint(ctl, _("Domain %s started\n"), virDomainGetName(dom)); + if (console) + cmdRunConsole(ctl, dom); } else { vshError(ctl, FALSE, _("Failed to start domain %s"), virDomainGetName(dom)); -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Wed, Apr 01, 2009 at 02:31:37PM +0100, Daniel P. Berrange wrote:
On Wed, Apr 01, 2009 at 08:51:14AM -0400, John Levon wrote:
On Wed, Apr 01, 2009 at 01:47:26PM +0100, Daniel P. Berrange wrote:
Finally, when starting the console print a message telling the user the hotkey to quit
# virsh start --console VirtTest Domain VirtTest started Connecting to console, type Ctrl+] to quit
Can we please make this the same as telnet (and virt-console):
514 if (!retrying && verbose) { 515 printf("Connected to domain %s\n", dom_name); 516 printf("Escape character is '^]'\n");
Sure, this patch makes that change...
Opps, wrong patch. Here it is again without the typo! Daniel diff -r a203154020dd src/virsh.c --- a/src/virsh.c Wed Apr 01 11:57:25 2009 +0100 +++ b/src/virsh.c Wed Apr 01 14:32:13 2009 +0100 @@ -500,20 +500,30 @@ static const vshCmdOptDef opts_console[] #ifndef __MINGW32__ static int -cmdConsole(vshControl *ctl, const vshCmd *cmd) +cmdRunConsole(vshControl *ctl, virDomainPtr dom) { 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, NULL))) - return FALSE; + char *thatHost = NULL; + char *thisHost = NULL; + + if (!(thisHost = virGetHostname())) { + vshError(ctl, FALSE, "%s", _("Failed to get local hostname")); + goto cleanup; + } + + if (!(thatHost = virConnectGetHostname(ctl->conn))) { + vshError(ctl, FALSE, "%s", _("Failed to get connection hostname")); + goto cleanup; + } + + if (STRNEQ(thisHost, thatHost)) { + vshError(ctl, FALSE, "%s", _("Cannot connect to a remote console device")); + goto cleanup; + } doc = virDomainGetXMLDesc(dom, 0); if (!doc) @@ -532,6 +542,8 @@ cmdConsole(vshControl *ctl, const vshCmd obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt); if ((obj != NULL) && ((obj->type == XPATH_STRING) && (obj->stringval != NULL) && (obj->stringval[0] != 0))) { + vshPrintExtra(ctl, _("Connected to domain %s\n"), virDomainGetName(dom)); + vshPrintExtra(ctl, "%s", _("Escape character is ^]\n")); if (vshRunConsole((const char *)obj->stringval) == 0) ret = TRUE; } else { @@ -543,14 +555,16 @@ cmdConsole(vshControl *ctl, const vshCmd xmlXPathFreeContext(ctxt); if (xml) xmlFreeDoc(xml); - virDomainFree(dom); + free(thisHost); + free(thatHost); + return ret; } #else /* __MINGW32__ */ static int -cmdConsole(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +cmdRunConsole(vshControl *ctl, virDomainPtr dom ATTRIBUTE_UNUSED) { vshError (ctl, FALSE, "%s", _("console not implemented on this platform")); return FALSE; @@ -558,6 +572,24 @@ cmdConsole(vshControl *ctl, const vshCmd #endif /* __MINGW32__ */ +static int +cmdConsole(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int ret; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return FALSE; + + ret = cmdRunConsole(ctl, dom); + + virDomainFree(dom); + return ret; +} + /* * "list" command */ @@ -882,6 +914,7 @@ static const vshCmdInfo info_create[] = static const vshCmdOptDef opts_create[] = { {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing an XML domain description")}, + {"console", VSH_OT_BOOL, 0, gettext_noop("attach to console after creation")}, {NULL, 0, 0, NULL} }; @@ -893,6 +926,7 @@ cmdCreate(vshControl *ctl, const vshCmd int found; int ret = TRUE; char *buffer; + int console = vshCommandOptBool(cmd, "console"); if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) return FALSE; @@ -910,6 +944,8 @@ cmdCreate(vshControl *ctl, const vshCmd if (dom != NULL) { vshPrint(ctl, _("Domain %s created from %s\n"), virDomainGetName(dom), from); + if (console) + cmdRunConsole(ctl, dom); virDomainFree(dom); } else { vshError(ctl, FALSE, _("Failed to create domain from %s"), from); @@ -1030,6 +1066,7 @@ static const vshCmdInfo info_start[] = { static const vshCmdOptDef opts_start[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the inactive domain")}, + {"console", VSH_OT_BOOL, 0, gettext_noop("attach to console after creation")}, {NULL, 0, 0, NULL} }; @@ -1038,6 +1075,7 @@ cmdStart(vshControl *ctl, const vshCmd * { virDomainPtr dom; int ret = TRUE; + int console = vshCommandOptBool(cmd, "console"); if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) return FALSE; @@ -1054,6 +1092,8 @@ cmdStart(vshControl *ctl, const vshCmd * if (virDomainCreate(dom) == 0) { vshPrint(ctl, _("Domain %s started\n"), virDomainGetName(dom)); + if (console) + cmdRunConsole(ctl, dom); } else { vshError(ctl, FALSE, _("Failed to start domain %s"), virDomainGetName(dom)); -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

Daniel P. Berrange wrote:
On Wed, Apr 01, 2009 at 02:31:37PM +0100, Daniel P. Berrange wrote:
On Wed, Apr 01, 2009 at 08:51:14AM -0400, John Levon wrote:
On Wed, Apr 01, 2009 at 01:47:26PM +0100, Daniel P. Berrange wrote:
Finally, when starting the console print a message telling the user the hotkey to quit
# virsh start --console VirtTest Domain VirtTest started Connecting to console, type Ctrl+] to quit Can we please make this the same as telnet (and virt-console):
514 if (!retrying && verbose) { 515 printf("Connected to domain %s\n", dom_name); 516 printf("Escape character is '^]'\n"); Sure, this patch makes that change...
Opps, wrong patch. Here it is again without the typo!
Nice, I like it. ACK -- Chris Lalancette
participants (3)
-
Chris Lalancette
-
Daniel P. Berrange
-
John Levon