#!/usr/bin/python # # Copyright (C) 2006 Red Hat, Inc. # Copyright (C) 2006 Daniel P. Berrange # # 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 virtinstutil from virtinst import cli as virtinstcli from virtcli import cliutils, cliconfig logging_setup = False GObject.threads_init() def _show_startup_error(msg, details): if logging_setup: 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, async=False, 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") # Generate runtime performance profile stats with hotshot optParser.add_option("--profile", dest="profile", help=optparse.SUPPRESS_HELP, metavar="FILE") # 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-usbredir", action="store_true", dest="usbredir", help="Disable 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) global logging_setup logging_setup = True 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 if not options.nofork and not options.debug: drop_tty() drop_stdio() # 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 before 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 globals()["Gtk"] = Gtk leftovers = sys.argv[1:] import virtManager.config import virtManager.util except: # 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 print "".join(traceback.format_exc()) return 1 finally: sys.argv = origargv 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.__version__, os.path.join(cliconfig.asset_dir, "ui"), options.testfirstrun) if not virtinstutil.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 virtManager.util.running_config = config config.default_qemu_user = cliconfig.default_qemu_user config.rhel6_defaults = not cliconfig.rhel_enable_unsupported_opts config.preferred_distros = cliconfig.preferred_distros config.hv_packages = cliconfig.hv_packages config.libvirt_packages = cliconfig.libvirt_packages config.askpass_package = cliconfig.askpass_package config.default_graphics_from_config = cliconfig.default_graphics 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 if options.profile is not None: import hotshot prof = hotshot.Profile(options.profile) prof.runcall(engine.application.run) prof.close() else: 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()))