virt-manager/virt-manager
Cole Robinson 395a20edd8 virt-manager: Yet more fixes for DISPLAY unset error
Since these days we have to import Gtk _after_ forking, _and_ Gtk
doesn't raise a nice error for us, we need to postpone dropping stdio
so the user has any chance of seeing the error. Also try to add an
explicit error about DISPLAY again, since we don't get it from Gtk
these days.
2013-11-01 09:48:08 -04:00

299 lines
10 KiB
Python
Executable File

#!/usr/bin/python
#
# Copyright (C) 2006 Red Hat, Inc.
# Copyright (C) 2006 Daniel P. Berrange <berrange@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
#
import logging
import optparse
import os
import signal
import sys
import traceback
# pylint: disable=E0611
from gi.repository import GObject
from gi.repository import LibvirtGLib
# pylint: enable=E0611
from virtinst import util as util
from virtinst import cli as virtinstcli
from virtcli import cliutils, cliconfig
try:
# Avoid a deprecation warning about threads_init
import gi
gi.check_version("3.9.1")
except (ValueError, AttributeError):
GObject.threads_init()
def _show_startup_error(msg, details):
logging.debug("Error starting virt-manager: %s\n%s", msg, details,
exc_info=True)
from virtManager.error import vmmErrorDialog
err = vmmErrorDialog()
title = _("Error starting Virtual Machine Manager")
err.show_err(title + ": " + msg,
details=details,
title=title,
modal=True,
debug=False)
def drop_tty():
# We fork and setsid so that we drop the controlling
# tty. This prevents libvirt's SSH tunnels from prompting
# for user input if SSH keys/agent aren't configured.
if os.fork() != 0:
os._exit(0) # pylint: disable=W0212
os.setsid()
def drop_stdio():
# We close STDIN/OUT/ERR since they're generally spewing
# junk to console when domains are in process of shutting
# down. Real errors will (hopefully) all be logged to the
# main log file. This is also again to stop SSH prompting
# for input
for fd in range(0, 2):
try:
os.close(fd)
except OSError:
pass
os.open(os.devnull, os.O_RDWR)
os.dup2(0, 1)
os.dup2(0, 2)
class PassThroughOptionParser(optparse.OptionParser):
# From http://stackoverflow.com/questions/1885161/how-can-i-get-optparses-optionparser-to-ignore-invalid-options
def _process_args(self, largs, rargs, values):
while rargs:
try:
optparse.OptionParser._process_args(self, largs, rargs, values)
except (optparse.BadOptionError, optparse.AmbiguousOptionError), e:
largs.append(e.opt_str)
def parse_commandline():
optParser = PassThroughOptionParser(version=cliconfig.__version__,
usage="virt-manager [options]")
optParser.set_defaults(uuid=None)
optParser.epilog = ("Also accepts standard GTK arguments like "
"--g-fatal-warnings")
# Trace every libvirt API call to debug output
optParser.add_option("--trace-libvirt", dest="tracelibvirt",
help=optparse.SUPPRESS_HELP, action="store_true")
# Don't load any connections on startup to test first run
# PackageKit integration
optParser.add_option("--test-first-run", dest="testfirstrun",
help=optparse.SUPPRESS_HELP, action="store_true")
optParser.add_option("-c", "--connect", dest="uri",
help="Connect to hypervisor at URI", metavar="URI")
optParser.add_option("--debug", action="store_true", dest="debug",
help="Print debug output to stdout (implies --no-fork)",
default=False)
optParser.add_option("--no-fork", action="store_true", dest="nofork",
help="Don't fork into background on startup")
optParser.add_option("--no-conn-autostart", action="store_true",
dest="no_conn_auto",
help="Do not autostart connections")
optParser.add_option("--show-domain-creator", action="callback",
callback=opt_show_cb, dest="show",
help="Show 'New VM' wizard")
optParser.add_option("--show-domain-editor", type="string",
metavar="UUID", action="callback", callback=opt_show_cb,
help="Show domain details window")
optParser.add_option("--show-domain-performance", type="string",
metavar="UUID", action="callback", callback=opt_show_cb,
help="Show domain performance window")
optParser.add_option("--show-domain-console", type="string",
metavar="UUID", action="callback", callback=opt_show_cb,
help="Show domain graphical console window")
optParser.add_option("--show-host-summary", action="callback",
callback=opt_show_cb, help="Show connection details window")
optParser.add_option("--spice-disable-auto-usbredir", action="store_true",
dest="usbredir", help="Disable Auto USB redirection support")
return optParser.parse_args()
def launch_specific_window(engine, show, uri, uuid):
if not show:
return
logging.debug("Launching requested window '%s'", show)
if show == 'creator':
engine.show_domain_creator(uri)
elif show == 'editor':
engine.show_domain_editor(uri, uuid)
elif show == 'performance':
engine.show_domain_performance(uri, uuid)
elif show == 'console':
engine.show_domain_console(uri, uuid)
elif show == 'summary':
engine.show_host_summary(uri)
def opt_show_cb(option, opt_str, value, parser):
# Generic OptionParser callback for all --show-* options
# This routine stores UUID to options.uuid for all --show-* options
# where is metavar="UUID" and also sets options.show
if option.metavar == "UUID":
setattr(parser.values, "uuid", value)
s = str(option)
show = s[s.rindex('-') + 1:]
setattr(parser.values, "show", show)
def main():
cliutils.setup_i18n()
(options, leftovers) = parse_commandline()
virtinstcli.setupLogging("virt-manager", options.debug, False, False)
import virtManager
logging.debug("virt-manager version: %s", cliconfig.__version__)
logging.debug("virtManager import: %s", str(virtManager))
if options.tracelibvirt:
logging.debug("Libvirt tracing requested")
import virtManager.module_trace
import libvirt
virtManager.module_trace.wrap_module(libvirt)
# Now we've got basic environment up & running we can fork
do_drop_stdio = False
if not options.nofork and not options.debug:
drop_tty()
do_drop_stdio = True
# Ignore SIGHUP, otherwise a serial console closing drops the whole app
signal.signal(signal.SIGHUP, signal.SIG_IGN)
# The never ending fork+gconf/gsettings problems now require
# us to import Gtk _after_ the fork. This creates a funny race,
# since we need to parse the command line arguments to know if
# we need to fork, but need to import Gtk before cli processing
# so it can handle --g-fatal-args. We strip out our flags first
# and pass the left overs to gtk
origargv = sys.argv
try:
sys.argv = origargv[:1] + leftovers[:]
from gi.repository import Gtk # pylint: disable=E0611
leftovers = sys.argv[1:]
# This will error if Gtk wasn't correctly initialized
Gtk.Window()
globals()["Gtk"] = Gtk
import virtManager.config
except Exception, e:
# Don't just let the exception raise here. abrt reports bugs
# when users mess up su/sudo and DISPLAY isn't set. Printing
# it avoids the issue
display = os.environ.get("DISPLAY", "")
msg = str(e)
if not display:
msg += ": Could not open display: %s" % display
logging.debug("".join(traceback.format_exc()))
print msg
return 1
finally:
sys.argv = origargv
# Do this after the Gtk import so the user has a chance of seeing any error
if do_drop_stdio:
drop_stdio()
if leftovers:
raise RuntimeError("Unhandled command line options '%s'" % leftovers)
logging.debug("GTK version: %d.%d.%d",
Gtk.get_major_version(),
Gtk.get_minor_version(),
Gtk.get_micro_version())
config = virtManager.config.vmmConfig(
"virt-manager", cliconfig, options.testfirstrun)
if not util.local_libvirt_version() >= 6000:
# We need this version for threaded virConnect access
_show_startup_error(
_("virt-manager requires libvirt 0.6.0 or later."), "")
return
if options.usbredir and config.get_auto_redirection():
config.set_auto_redirection(False)
# Add our icon dir to icon theme
icon_theme = Gtk.IconTheme.get_default()
icon_theme.prepend_search_path(cliconfig.icon_dir)
from virtManager.engine import vmmEngine
Gtk.Window.set_default_icon_name("virt-manager")
if options.show and options.uri is None:
raise optparse.OptionValueError("can't use --show-* options "
"without --connect")
# Hook libvirt events into glib main loop
LibvirtGLib.init(None)
LibvirtGLib.event_register()
engine = vmmEngine()
engine.skip_autostart = options.no_conn_auto
engine.uri_at_startup = options.uri
if options.show:
def cb(conn):
ignore = conn
launch_specific_window(engine,
options.show, options.uri, options.uuid)
return True
engine.uri_cb = cb
engine.show_manager_window = False
engine.skip_autostart = True
# Finally start the app for real
engine.application.run(None)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
logging.debug("Received KeyboardInterrupt. Exiting application.")
except SystemExit:
raise
except Exception, run_e:
if "Gtk" not in globals():
raise
_show_startup_error(str(run_e), "".join(traceback.format_exc()))