# # Copyright (C) 2008 Red Hat, Inc. # Copyright (C) 2008 Cole Robinson # # 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 threading import time # pylint: disable=E0611 from gi.repository import GObject from gi.repository import Gtk from gi.repository import Gdk # pylint: enable=E0611 import virtinst import virtManager.uihelpers as uihelpers from virtManager import util from virtManager.mediadev import MEDIA_CDROM from virtManager.baseclass import vmmGObjectUI from virtManager.asyncjob import vmmAsyncJob from virtManager.storagebrowse import vmmStorageBrowser from virtManager.details import vmmDetails from virtManager.domain import vmmDomainVirtinst # Number of seconds to wait for media detection DETECT_TIMEOUT = 20 DEFAULT_MEM = 1024 PAGE_NAME = 0 PAGE_INSTALL = 1 PAGE_MEM = 2 PAGE_STORAGE = 3 PAGE_FINISH = 4 INSTALL_PAGE_ISO = 0 INSTALL_PAGE_URL = 1 INSTALL_PAGE_PXE = 2 INSTALL_PAGE_IMPORT = 3 INSTALL_PAGE_CONTAINER_APP = 4 INSTALL_PAGE_CONTAINER_OS = 5 RHEL6_OS_SUPPORT = [ "rhel3", "rhel4", "rhel5.4", "rhel6", "win2k3", "winxp", "win2k8", "vista", "win7", ] class vmmCreate(vmmGObjectUI): __gsignals__ = { "action-show-vm": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), } def __init__(self, engine): vmmGObjectUI.__init__(self, "vmm-create.ui", "vmm-create") self.engine = engine self.conn = None self.caps = None self.capsguest = None self.capsdomain = None self.guest = None self.disk = None self.nic = None self.storage_browser = None self.conn_signals = [] # Distro detection state variables self.detectedDistro = None self.detecting = False self.mediaDetected = False self.show_all_os = False # 'Guest' class from the previous failed install self.failed_guest = None # Whether there was an error at dialog startup self.have_startup_error = False # Host space polling self.host_storage_timer = None # 'Configure before install' window self.config_window = None self.config_window_signals = [] self.builder.connect_signals({ "on_vmm_newcreate_delete_event" : self.close, "on_create_cancel_clicked": self.close, "on_create_back_clicked" : self.back, "on_create_forward_clicked" : self.forward, "on_create_finish_clicked" : self.finish, "on_create_pages_switch_page": self.page_changed, "on_create_vm_name_activate": self.forward, "on_create_conn_changed": self.conn_changed, "on_method_changed": self.method_changed, "on_install_url_box_changed": self.url_box_changed, "on_install_local_cdrom_toggled": self.toggle_local_cdrom, "on_install_local_cdrom_combo_changed": self.detect_media_os, "on_install_local_box_changed": self.detect_media_os, "on_install_local_browse_clicked": self.browse_iso, "on_install_import_browse_clicked": self.browse_import, "on_install_app_browse_clicked": self.browse_app, "on_install_oscontainer_browse_clicked": self.browse_oscontainer, "on_install_detect_os_toggled": self.toggle_detect_os, "on_install_os_type_changed": self.change_os_type, "on_install_os_version_changed": self.change_os_version, "on_install_local_iso_toggled": self.toggle_local_iso, "on_install_detect_os_box_show": self.detect_visibility_changed, "on_install_detect_os_box_hide": self.detect_visibility_changed, "on_enable_storage_toggled": self.toggle_enable_storage, "on_config_storage_browse_clicked": self.browse_storage, "on_config_storage_select_toggled": self.toggle_storage_select, "on_config_netdev_changed": self.netdev_changed, "on_config_set_macaddr_toggled": self.toggle_macaddr, "on_config_hv_changed": self.hv_changed, "on_config_arch_changed": self.arch_changed, }) self.bind_escape_key_close() self.set_initial_state() def is_visible(self): return self.topwin.get_visible() def show(self, parent, uri=None): logging.debug("Showing new vm wizard") if not self.is_visible(): self.reset_state(uri) self.topwin.set_transient_for(parent) self.topwin.present() def close(self, ignore1=None, ignore2=None): logging.debug("Closing new vm wizard") self.topwin.hide() self.remove_timers() if self.config_window: self.config_window.close() if self.storage_browser: self.storage_browser.close() return 1 def _cleanup(self): self.remove_conn() self.conn = None self.caps = None self.capsguest = None self.capsdomain = None self.guest = None self.disk = None self.nic = None if self.storage_browser: self.storage_browser.cleanup() self.storage_browser = None def remove_timers(self): try: if self.host_storage_timer: self.remove_gobject_timeout(self.host_storage_timer) self.host_storage_timer = None except: pass def remove_conn(self): if not self.conn: return for signal in self.conn_signals: self.conn.disconnect(signal) self.conn_signals = [] self.conn = None def set_conn(self, newconn, force_validate=False): if self.conn == newconn and not force_validate: return self.remove_conn() self.conn = newconn if self.conn: self.set_conn_state() # State init methods def startup_error(self, error, hideinstall=True): self.have_startup_error = True self.widget("startup-error-box").show() self.widget("create-forward").set_sensitive(False) if hideinstall: self.widget("install-box").hide() self.widget("startup-error").set_text("Error: %s" % error) return False def startup_warning(self, error): self.widget("startup-error-box").show() self.widget("startup-error").set_text("Warning: %s" % error) def set_initial_state(self): self.widget("create-pages").set_show_tabs(False) self.widget("install-method-pages").set_show_tabs(False) finish_img = Gtk.Image.new_from_stock(Gtk.STOCK_QUIT, Gtk.IconSize.BUTTON) self.widget("create-finish").set_image(finish_img) blue = Gdk.Color.parse("#0072A8")[1] self.widget("create-header").modify_bg(Gtk.StateType.NORMAL, blue) box = self.widget("create-vm-icon-box") image = Gtk.Image.new_from_icon_name("vm_new_wizard", Gtk.IconSize.DIALOG) image.show() box.pack_end(image, False, False, False) # Connection list self.widget("create-conn-label").set_text("") self.widget("startup-error").set_text("") conn_list = self.widget("create-conn") conn_model = Gtk.ListStore(str, str) conn_list.set_model(conn_model) text = Gtk.CellRendererText() conn_list.pack_start(text, True) conn_list.add_attribute(text, 'text', 1) # ISO media list iso_list = self.widget("install-local-box") iso_model = Gtk.ListStore(str) iso_list.set_model(iso_model) iso_list.set_entry_text_column(0) self.widget("install-local-box").get_child().connect("activate", self.detect_media_os) # Lists for the install urls media_url_list = self.widget("install-url-box") media_url_model = Gtk.ListStore(str) media_url_list.set_model(media_url_model) media_url_list.set_entry_text_column(0) self.widget("install-url-box").get_child().connect("activate", self.detect_media_os) ks_url_list = self.widget("install-ks-box") ks_url_model = Gtk.ListStore(str) ks_url_list.set_model(ks_url_model) ks_url_list.set_entry_text_column(0) def sep_func(model, it, combo): ignore = combo return model[it][2] # Lists for distro type + variant # [os value, os label, is seperator, is 'show all' os_type_list = self.widget("install-os-type") os_type_model = Gtk.ListStore(str, str, bool, bool) os_type_list.set_model(os_type_model) text = Gtk.CellRendererText() os_type_list.pack_start(text, True) os_type_list.add_attribute(text, 'text', 1) os_type_list.set_row_separator_func(sep_func, os_type_list) os_variant_list = self.widget("install-os-version") os_variant_model = Gtk.ListStore(str, str, bool, bool) os_variant_list.set_model(os_variant_model) text = Gtk.CellRendererText() os_variant_list.pack_start(text, True) os_variant_list.add_attribute(text, 'text', 1) os_variant_list.set_row_separator_func(sep_func, os_variant_list) # Physical CD-ROM model cd_list = self.widget("install-local-cdrom-combo") uihelpers.init_mediadev_combo(cd_list) # Networking # [ interface type, device name, label, sensitive ] net_list = self.widget("config-netdev") bridge_box = self.widget("config-netdev-bridge-box") uihelpers.init_network_list(net_list, bridge_box) # Archtecture archModel = Gtk.ListStore(str) archList = self.widget("config-arch") text = Gtk.CellRendererText() archList.pack_start(text, True) archList.add_attribute(text, 'text', 0) archList.set_model(archModel) hyperModel = Gtk.ListStore(str, str, str, bool) hyperList = self.widget("config-hv") text = Gtk.CellRendererText() hyperList.pack_start(text, True) hyperList.add_attribute(text, 'text', 0) hyperList.add_attribute(text, 'sensitive', 3) hyperList.set_model(hyperModel) # Sparse tooltip sparse_info = self.widget("config-storage-nosparse-info") uihelpers.set_sparse_tooltip(sparse_info) def reset_state(self, urihint=None): self.failed_guest = None self.have_startup_error = False self.guest = None self.disk = None self.nic = None self.show_all_os = False self.widget("create-pages").set_current_page(PAGE_NAME) self.page_changed(None, None, PAGE_NAME) self.widget("startup-error-box").hide() self.widget("install-box").show() # Name page state self.widget("create-vm-name").set_text("") self.widget("create-vm-name").grab_focus() self.widget("method-local").set_active(True) self.widget("create-conn").set_active(-1) activeconn = self.populate_conn_list(urihint) try: self.set_conn(activeconn, force_validate=True) except Exception, e: logging.exception("Error setting create wizard conn state.") return self.startup_error(str(e)) if not activeconn: return self.startup_error( _("No active connection to install on.")) # Everything from this point forward should be connection independent # Distro/Variant self.toggle_detect_os(self.widget("install-detect-os")) self.populate_os_type_model() self.widget("install-os-type").set_active(0) self.widget("install-local-box").get_child().set_text("") iso_model = self.widget("install-local-box").get_model() self.populate_media_model(iso_model, self.config.get_iso_paths()) # Install URL self.widget("install-urlopts-entry").set_text("") self.widget("install-ks-box").get_child().set_text("") self.widget("install-url-box").get_child().set_text("") self.widget("install-url-options").set_expanded(False) urlmodel = self.widget("install-url-box").get_model() ksmodel = self.widget("install-ks-box").get_model() self.populate_media_model(urlmodel, self.config.get_media_urls()) self.populate_media_model(ksmodel, self.config.get_kickstart_urls()) # Install import self.widget("install-import-entry").set_text("") # Install container app self.widget("install-app-entry").set_text("/bin/sh") # Install container OS self.widget("install-oscontainer-fs").set_text("") # Mem / CPUs self.widget("config-mem").set_value(DEFAULT_MEM) self.widget("config-cpus").set_value(1) # Storage label_widget = self.widget("phys-hd-label") label_widget.set_markup("") if not self.host_storage_timer: self.host_storage_timer = self.timeout_add(3 * 1000, uihelpers.host_space_tick, self.conn, label_widget) self.widget("enable-storage").set_active(True) self.widget("config-storage-create").set_active(True) self.widget("config-storage-size").set_value(8) self.widget("config-storage-entry").set_text("") self.widget("config-storage-nosparse").set_active(True) # Final page self.widget("summary-customize").set_active(False) # Make sure window is a sane size self.topwin.resize(1, 1) def set_conn_state(self): # Update all state that has some dependency on the current connection self.widget("create-forward").set_sensitive(True) if self.conn.caps.no_install_options(): error = _("No hypervisor options were found for this " "connection.") if self.conn.is_qemu(): error += "\n\n" error += _("This usually means that QEMU or KVM is not " "installed on your machine, or the KVM kernel " "modules are not loaded.") return self.startup_error(error) # A bit out of order, but populate arch + hv lists so we can # determine a default self.conn.invalidate_caps() self.caps = self.conn.caps self.change_caps() self.populate_hv() if self.conn.is_xen(): if self.conn.caps.hw_virt_supported(): if self.conn.caps.is_bios_virt_disabled(): error = _("Host supports full virtualization, but " "no related install options are available. " "This may mean support is disabled in your " "system BIOS.") self.startup_warning(error) else: error = _("Host does not appear to support hardware " "virtualization. Install options may be limited.") self.startup_warning(error) elif self.conn.is_qemu(): if not self.conn.caps.is_kvm_available(): error = _("KVM is not available. This may mean the KVM " "package is not installed, or the KVM kernel modules " "are not loaded. Your virtual machines may perform poorly.") self.startup_warning(error) # Helper state is_local = not self.conn.is_remote() is_storage_capable = self.conn.is_storage_capable() can_storage = (is_local or is_storage_capable) is_pv = (self.capsguest.os_type == "xen") is_container = self.conn.is_container() can_remote_url = self.conn.check_stream_support( self.conn.SUPPORT_STREAM_UPLOAD) # Install Options method_tree = self.widget("method-tree") method_pxe = self.widget("method-pxe") method_local = self.widget("method-local") method_import = self.widget("method-import") method_container_app = self.widget("method-container-app") method_tree.set_sensitive(is_local or can_remote_url) method_local.set_sensitive(not is_pv and can_storage) method_pxe.set_sensitive(not is_pv) method_import.set_sensitive(can_storage) virt_methods = [method_local, method_tree, method_pxe, method_import] pxe_tt = None local_tt = None tree_tt = None import_tt = None if not is_local: if not can_remote_url: tree_tt = _("Libvirt version does not " "support remote URL installs.") if not is_storage_capable: local_tt = _("Connection does not support storage management.") import_tt = local_tt if is_pv: base = _("%s installs not available for paravirt guests.") pxe_tt = base % "PXE" local_tt = base % "CDROM/ISO" for w in virt_methods: if w.get_sensitive(): w.set_active(True) break if not (is_container or [w for w in virt_methods if w.get_sensitive()]): return self.startup_error( _("No install methods available for this connection."), hideinstall=False) method_tree.set_tooltip_text(tree_tt or "") method_local.set_tooltip_text(local_tt or "") method_pxe.set_tooltip_text(pxe_tt or "") method_import.set_tooltip_text(import_tt or "") # Container install options method_container_app.set_active(True) self.widget("virt-install-box").set_property("visible", not is_container) self.widget("container-install-box").set_property("visible", is_container) # Install local iso_option = self.widget("install-local-iso") cdrom_option = self.widget("install-local-cdrom") cdrom_list = self.widget("install-local-cdrom-combo") cdrom_warn = self.widget("install-local-cdrom-warn") sigs = uihelpers.populate_mediadev_combo(self.conn, cdrom_list, MEDIA_CDROM) self.conn_signals.extend(sigs) if self.conn.mediadev_error: cdrom_warn.show() cdrom_option.set_sensitive(False) cdrom_warn.set_tooltip_text(self.conn.mediadev_error) else: cdrom_warn.hide() # Don't select physical CDROM if no valid media is present use_cd = (cdrom_list.get_active() >= 0) if use_cd: cdrom_option.set_active(True) else: iso_option.set_active(True) # Only allow ISO option for remote VM if not is_local: iso_option.set_active(True) self.toggle_local_cdrom(cdrom_option) self.toggle_local_iso(iso_option) # Memory memory = int(self.conn.host_memory_size()) mem_label = (_("Up to %(maxmem)s available on the host") % {'maxmem': self.pretty_memory(memory)}) mem_label = ("%s" % mem_label) self.widget("config-mem").set_range(50, memory / 1024) self.widget("phys-mem-label").set_markup(mem_label) # CPU phys_cpus = int(self.conn.host_active_processor_count()) cmax = phys_cpus if cmax <= 0: cmax = 1 cpu_label = (_("Up to %(numcpus)d available") % {'numcpus': int(phys_cpus)}) cpu_label = ("%s" % cpu_label) self.widget("config-cpus").set_range(1, cmax) self.widget("phys-cpu-label").set_markup(cpu_label) # Storage storage_tooltip = None use_storage = self.widget("config-storage-select") storage_area = self.widget("config-storage-area") storage_area.set_sensitive(can_storage) if not can_storage: storage_tooltip = _("Connection does not support storage" " management.") use_storage.set_sensitive(True) storage_area.set_tooltip_text(storage_tooltip or "") # Networking net_list = self.widget("config-netdev") net_expander = self.widget("config-advanced-expander") net_warn_icon = self.widget("config-netdev-warn-icon") net_warn_box = self.widget("config-netdev-warn-box") net_expander.hide() net_warn_icon.hide() net_warn_box.hide() net_expander.set_expanded(False) do_warn = uihelpers.populate_network_list(net_list, self.conn, False) self.set_net_warn(self.conn.netdev_error or do_warn, self.conn.netdev_error, True) newmac = uihelpers.generate_macaddr(self.conn) self.widget("config-set-macaddr").set_active(bool(newmac)) self.widget("config-macaddr").set_text(newmac) def set_net_warn(self, show_warn, msg, do_tooltip): net_warn_icon = self.widget("config-netdev-warn-icon") net_warn_box = self.widget("config-netdev-warn-box") net_warn_label = self.widget("config-netdev-warn-label") net_expander = self.widget("config-advanced-expander") if show_warn: net_expander.set_expanded(True) if do_tooltip: net_warn_icon.set_property("visible", show_warn) if msg: net_warn_icon.set_tooltip_text(show_warn and msg or "") else: net_warn_box.set_property("visible", show_warn) markup = show_warn and ("%s" % msg) or "" net_warn_label.set_markup(markup) def populate_hv(self): hv_list = self.widget("config-hv") model = hv_list.get_model() model.clear() default = 0 tooltip = None instmethod = self.get_config_install_page() for guest in self.caps.guests: gtype = guest.os_type for dom in guest.domains: domtype = dom.hypervisor_type label = util.pretty_hv(gtype, domtype) sensitive = True # Don't add multiple rows for each arch for m in model: if m[0] == label: label = None break if label is None: continue # Determine if this is the default given by guest_lookup if (gtype == self.capsguest.os_type and self.capsdomain.hypervisor_type == domtype): default = len(model) if gtype == "xen": if (instmethod == INSTALL_PAGE_PXE or instmethod == INSTALL_PAGE_ISO): sensitive = False tooltip = _("Only URL or import installs are supported " "for paravirt.") model.append([label, gtype, domtype, sensitive]) hv_info = self.widget("config-hv-info") if tooltip: hv_info.show() hv_info.set_tooltip_text(tooltip) else: hv_info.hide() hv_list.set_active(default) def populate_arch(self): arch_list = self.widget("config-arch") model = arch_list.get_model() model.clear() default = 0 for guest in self.caps.guests: for dom in guest.domains: if (guest.os_type == self.capsguest.os_type and dom.hypervisor_type == self.capsdomain.hypervisor_type): arch = guest.arch if arch == self.capsguest.arch: default = len(model) model.append([guest.arch]) arch_list.set_active(default) def populate_conn_list(self, urihint=None): conn_list = self.widget("create-conn") model = conn_list.get_model() model.clear() default = -1 for c in self.engine.conns.values(): connobj = c["conn"] if not connobj.is_active(): continue if connobj.get_uri() == urihint: default = len(model) elif default < 0 and not connobj.is_remote(): # Favor local connections over remote connections default = len(model) model.append([connobj.get_uri(), connobj.get_pretty_desc_active()]) no_conns = (len(model) == 0) if default < 0 and not no_conns: default = 0 activeuri = "" activedesc = "" activeconn = None if not no_conns: conn_list.set_active(default) activeuri, activedesc = model[default] activeconn = self.engine.conns[activeuri]["conn"] self.widget("create-conn-label").set_text(activedesc) if len(model) <= 1: self.widget("create-conn").hide() self.widget("create-conn-label").show() else: self.widget("create-conn").show() self.widget("create-conn-label").hide() return activeconn def _add_os_row(self, model, name="", label="", supported=False, sep=False, action=False): visible = self.show_all_os or supported if sep or action: visible = not self.show_all_os if not visible: return model.append([name, label, sep, action]) def populate_os_type_model(self): widget = self.widget("install-os-type") model = widget.get_model() model.clear() filtervars = (not self._rhel6_defaults() and RHEL6_OS_SUPPORT or None) types = virtinst.Guest.list_os_types() types.sort() supportl = virtinst.Guest.list_os_types(supported=True, filtervars=filtervars) if not filtervars: # Kind of a hack, just show linux + windows by default since # that's all 98% of people care about supportl = ["linux", "windows"] self._add_os_row(model, None, _("Generic"), True) for t in types: label = virtinst.Guest.get_os_type_label(t) supported = (t in supportl) self._add_os_row(model, t, label, supported) # Add sep self._add_os_row(model, sep=True) # Add action option self._add_os_row(model, label=_("Show all OS options"), action=True) widget.set_active(0) def populate_os_variant_model(self, _type): model = self.widget("install-os-version").get_model() model.clear() if not _type: self._add_os_row(model, None, _("Generic"), True) return filtervars = (not self._rhel6_defaults() and RHEL6_OS_SUPPORT or None) preferred = self.config.preferred_distros variants = virtinst.Guest.list_os_variants(_type, preferred) supportl = virtinst.Guest.list_os_variants( _type, preferred, supported=True, filtervars=filtervars) for v in variants: label = virtinst.Guest.get_os_variant_label(_type, v) supported = v in supportl self._add_os_row(model, v, label, supported) # Add sep self._add_os_row(model, sep=True) # Add action option self._add_os_row(model, label=_("Show all OS options"), action=True) def populate_media_model(self, model, urls): model.clear() if urls is not None: for url in urls: model.append([url]) def change_caps(self, gtype=None, dtype=None, arch=None): if gtype is None: # If none specified, prefer HVM. This way, the default install # options won't be limited because we default to PV. If hvm not # supported, differ to guest_lookup for g in self.caps.guests: if g.os_type == "hvm": gtype = "hvm" break (newg, newdom) = self.caps.guest_lookup(os_type=gtype, typ=dtype, accelerated=True, arch=arch) if (self.capsguest and self.capsdomain and (newg.arch == self.capsguest.arch and newg.os_type == self.capsguest.os_type and newdom.hypervisor_type == self.capsdomain.hypervisor_type)): # No change return self.capsguest = newg self.capsdomain = newdom logging.debug("Guest type set to os_type=%s, arch=%s, dom_type=%s", self.capsguest.os_type, self.capsguest.arch, self.capsdomain.hypervisor_type) def populate_summary(self): distro, version, dlabel, vlabel = self.get_config_os_info() mem = self.pretty_memory(int(self.guest.memory) * 1024) cpu = str(int(self.guest.vcpus)) instmethod = self.get_config_install_page() install = "" if instmethod == INSTALL_PAGE_ISO: install = _("Local CDROM/ISO") elif instmethod == INSTALL_PAGE_URL: install = _("URL Install Tree") elif instmethod == INSTALL_PAGE_PXE: install = _("PXE Install") elif instmethod == INSTALL_PAGE_IMPORT: install = _("Import existing OS image") elif instmethod == INSTALL_PAGE_CONTAINER_APP: install = _("Application container") elif instmethod == INSTALL_PAGE_CONTAINER_OS: install = _("Operating system container") storagetmpl = "%s" disks = self.guest.get_devices("disk") if disks: disk = disks[0] storage = "%s" % self.pretty_storage(disk.size) storage += " " + (storagetmpl % disk.path) elif len(self.guest.get_devices("filesystem")): fs = self.guest.get_devices("filesystem")[0] storage = storagetmpl % fs.source elif self.guest.installer.is_container(): storage = _("Host filesystem") else: storage = _("None") osstr = "" have_os = True if self.guest.installer.is_container(): osstr = _("Linux") elif not distro: osstr = _("Generic") have_os = False elif not version: osstr = _("Generic") + " " + dlabel have_os = False else: osstr = vlabel title = "Ready to begin installation of %s" % self.guest.name self.widget("finish-warn-os").set_property("visible", not have_os) self.widget("summary-title").set_markup(title) self.widget("summary-os").set_text(osstr) self.widget("summary-install").set_text(install) self.widget("summary-mem").set_text(mem) self.widget("summary-cpu").set_text(cpu) self.widget("summary-storage").set_markup(storage) # get_* methods def get_config_name(self): return self.widget("create-vm-name").get_text() def is_install_page(self): notebook = self.widget("create-pages") curpage = notebook.get_current_page() return curpage == PAGE_INSTALL def get_config_install_page(self): if self.widget("virt-install-box").get_property("visible"): if self.widget("method-local").get_active(): return INSTALL_PAGE_ISO elif self.widget("method-tree").get_active(): return INSTALL_PAGE_URL elif self.widget("method-pxe").get_active(): return INSTALL_PAGE_PXE elif self.widget("method-import").get_active(): return INSTALL_PAGE_IMPORT else: if self.widget("method-container-app").get_active(): return INSTALL_PAGE_CONTAINER_APP if self.widget("method-container-os").get_active(): return INSTALL_PAGE_CONTAINER_OS def get_config_os_info(self): d_list = self.widget("install-os-type") d_idx = d_list.get_active() v_list = self.widget("install-os-version") v_idx = v_list.get_active() distro = None dlabel = None variant = None vlabel = None if d_idx >= 0: row = d_list.get_model()[d_idx] distro = row[0] dlabel = row[1] if v_idx >= 0: row = v_list.get_model()[v_idx] variant = row[0] vlabel = row[1] return (distro and str(distro), variant and str(variant), str(dlabel), str(vlabel)) def get_config_local_media(self, store_media=False): if self.widget("install-local-cdrom").get_active(): cd = self.widget("install-local-cdrom-combo") idx = cd.get_active() model = cd.get_model() if idx != -1: return model[idx][uihelpers.OPTICAL_DEV_PATH] return None else: ret = self.widget("install-local-box").get_child().get_text() if ret and store_media: self.config.add_iso_path(ret) return ret def get_config_detectable_media(self): instpage = self.get_config_install_page() media = "" if instpage == INSTALL_PAGE_ISO: media = self.get_config_local_media() elif instpage == INSTALL_PAGE_URL: media = self.widget("install-url-box").get_child().get_text() elif instpage == INSTALL_PAGE_IMPORT: media = self.widget("install-import-entry").get_text() return media def get_config_url_info(self, store_media=False): media = self.widget("install-url-box").get_child().get_text().strip() extra = self.widget("install-urlopts-entry").get_text().strip() ks = self.widget("install-ks-box").get_child().get_text().strip() if media and store_media: self.config.add_media_url(media) if ks and store_media: self.config.add_kickstart_url(ks) return (media.strip(), extra.strip(), ks.strip()) def get_config_import_path(self): return self.widget("install-import-entry").get_text() def get_config_container_app_path(self): return self.widget("install-app-entry").get_text() def get_config_container_fs_path(self): return self.widget("install-oscontainer-fs").get_text() def get_default_path(self, name): # Don't generate a new path if the install failed if self.failed_guest: disks = self.failed_guest.get_devices("disk") if disks: return disks[0].path return util.get_default_path(self.conn, name) def is_default_storage(self): usedef = self.widget("config-storage-create").get_active() isimport = (self.get_config_install_page() == INSTALL_PAGE_IMPORT) return usedef and not isimport def get_storage_info(self): path = None size = uihelpers.spin_get_helper(self.widget("config-storage-size")) sparse = not self.widget("config-storage-nosparse").get_active() if self.get_config_install_page() == INSTALL_PAGE_IMPORT: path = self.get_config_import_path() size = None sparse = False elif self.is_default_storage(): path = self.get_default_path(self.guest.name) logging.debug("Default storage path is: %s", path) else: path = self.widget("config-storage-entry").get_text() return (path, size, sparse) def get_config_network_info(self): net_list = self.widget("config-netdev") bridge_ent = self.widget("config-netdev-bridge") macaddr = self.widget("config-macaddr").get_text() net_type, net_src = uihelpers.get_network_selection(net_list, bridge_ent) return net_type, net_src, macaddr.strip() def get_config_graphics_type(self): return self.config.get_graphics_type() def get_config_customize(self): return self.widget("summary-customize").get_active() def is_detect_active(self): return self.widget("install-detect-os").get_active() # Listeners def conn_changed(self, src): idx = src.get_active() model = src.get_model() if idx < 0: conn = None else: uri = model[idx][0] conn = self.engine.conns[uri]["conn"] # If we aren't visible, let reset_state handle this for us, which # has a better chance of reporting error if not self.is_visible(): return self.set_conn(conn) def method_changed(self, src): ignore = src self.set_page_num_text(0) def netdev_changed(self, ignore): self.check_network_selection() def check_network_selection(self): src = self.widget("config-netdev") idx = src.get_active() show_pxe_warn = True pxe_install = (self.get_config_install_page() == INSTALL_PAGE_PXE) if not idx < 0: row = src.get_model()[idx] ntype = row[0] key = row[6] if (ntype is None or ntype == virtinst.VirtualNetworkInterface.TYPE_USER): show_pxe_warn = True elif ntype != virtinst.VirtualNetworkInterface.TYPE_VIRTUAL: show_pxe_warn = False else: obj = self.conn.get_net(key) show_pxe_warn = not obj.can_pxe() if not (show_pxe_warn and pxe_install): return self.set_net_warn(True, _("Network selection does not support PXE"), False) def hv_changed(self, src): idx = src.get_active() if idx < 0: return row = src.get_model()[idx] self.change_caps(row[1], row[2]) self.populate_arch() def arch_changed(self, src): idx = src.get_active() if idx < 0: return arch = src.get_model()[idx][0] self.change_caps(self.capsguest.os_type, self.capsdomain.hypervisor_type, arch) def url_box_changed(self, ignore): # If the url_entry has focus, don't fire detect_media_os, it means # the user is probably typing self.mediaDetected = False if self.widget("install-url-box").get_child().has_focus(): return self.detect_media_os() def should_detect_media(self): return (self.is_detect_active() and not self.mediaDetected) def detect_media_os(self, ignore1=None, forward=False): if not self.should_detect_media(): return if not self.is_install_page(): return self.start_detection(forward=forward) def toggle_detect_os(self, src): dodetect = src.get_active() if dodetect: self.widget("install-os-type-label").show() self.widget("install-os-version-label").show() self.widget("install-os-type").hide() self.widget("install-os-version").hide() self.mediaDetected = False self.detect_media_os() # Run detection else: self.widget("install-os-type-label").hide() self.widget("install-os-version-label").hide() self.widget("install-os-type").show() self.widget("install-os-version").show() def _selected_os_row(self): box = self.widget("install-os-type") model = box.get_model() idx = box.get_active() if idx == -1: return None return model[idx] def change_os_type(self, box): ignore = box row = self._selected_os_row() if row: _type = row[0] self.populate_os_variant_model(_type) if row[3]: self.show_all_os = True self.populate_os_type_model() return variant = self.widget("install-os-version") variant.set_active(0) def change_os_version(self, box): model = box.get_model() idx = box.get_active() if idx == -1: return # Get previous os_type_list = self.widget("install-os-type") os_type_model = os_type_list.get_model() type_row = self._selected_os_row() if not type_row: return os_type = type_row[0] show_all = model[idx][3] if not show_all: return self.show_all_os = True self.populate_os_type_model() for idx in range(len(os_type_model)): if os_type_model[idx][0] == os_type: os_type_list.set_active(idx) break def toggle_local_cdrom(self, src): combo = self.widget("install-local-cdrom-combo") is_active = src.get_active() if is_active: if combo.get_active() != -1: # Local CDROM was selected with media preset, detect distro self.detect_media_os() self.widget("install-local-cdrom-combo").set_sensitive(is_active) def toggle_local_iso(self, src): uselocal = src.get_active() self.widget("install-local-box").set_sensitive(uselocal) self.widget("install-local-browse").set_sensitive(uselocal) def detect_visibility_changed(self, src, ignore=None): is_visible = src.get_property("visible") detect_chkbox = self.widget("install-detect-os") nodetect_label = self.widget("install-nodetect-label") detect_chkbox.set_active(is_visible) detect_chkbox.toggled() if is_visible: nodetect_label.hide() else: nodetect_label.show() def browse_oscontainer(self, ignore1=None, ignore2=None): def set_path(ignore, path): self.widget("install-oscontainer-fs").set_text(path) self._browse_file(set_path, is_media=False, is_dir=True) def browse_app(self, ignore1=None, ignore2=None): def set_path(ignore, path): self.widget("install-app-entry").set_text(path) self._browse_file(set_path, is_media=False) def browse_import(self, ignore1=None, ignore2=None): def set_path(ignore, path): self.widget("install-import-entry").set_text(path) self._browse_file(set_path, is_media=False) def browse_iso(self, ignore1=None, ignore2=None): def set_path(ignore, path): self.widget("install-local-box").get_child().set_text(path) self._browse_file(set_path, is_media=True) self.widget("install-local-box").activate() def browse_storage(self, ignore1): def set_path(ignore, path): self.widget("config-storage-entry").set_text(path) self._browse_file(set_path, is_media=False) def toggle_enable_storage(self, src): self.widget("config-storage-box").set_sensitive(src.get_active()) def toggle_storage_select(self, src): act = src.get_active() self.widget("config-storage-browse-box").set_sensitive(act) def toggle_macaddr(self, src): self.widget("config-macaddr").set_sensitive(src.get_active()) # Navigation methods def set_install_page(self): instnotebook = self.widget("install-method-pages") detectbox = self.widget("install-detect-os-box") osbox = self.widget("install-os-distro-box") instpage = self.get_config_install_page() # Setting OS value for a container guest doesn't really matter # at the moment iscontainer = instpage in [INSTALL_PAGE_CONTAINER_APP, INSTALL_PAGE_CONTAINER_OS] osbox.set_property("visible", iscontainer) # Detection only works/ is valid for URL, # FIXME: Also works for CDROM if running as root (since we need to # mount the iso/cdrom), but we should probably make this work for # more distros (like windows) before we enable it if (instpage == INSTALL_PAGE_URL): detectbox.show() else: detectbox.hide() if instpage == INSTALL_PAGE_PXE: # Hide the install notebook for pxe, since there isn't anything # to ask for instnotebook.hide() else: instnotebook.show() instnotebook.set_current_page(instpage) def container_install(self): return self.get_config_install_page() in [INSTALL_PAGE_CONTAINER_APP, INSTALL_PAGE_CONTAINER_OS] def skip_disk_page(self): return self.get_config_install_page() in [INSTALL_PAGE_IMPORT, INSTALL_PAGE_CONTAINER_APP, INSTALL_PAGE_CONTAINER_OS] def back(self, src_ignore): notebook = self.widget("create-pages") curpage = notebook.get_current_page() next_page = curpage - 1 if curpage == PAGE_INSTALL: self.reset_guest_type() elif curpage == PAGE_FINISH and self.skip_disk_page(): # Skip over storage page next_page -= 1 notebook.set_current_page(next_page) def _get_next_pagenum(self, curpage): next_page = curpage + 1 if next_page == PAGE_STORAGE and self.skip_disk_page(): # Skip storage page for import installs next_page += 1 return next_page def forward(self, src_ignore=None): notebook = self.widget("create-pages") curpage = notebook.get_current_page() if self.have_startup_error: return if curpage == PAGE_INSTALL and self.should_detect_media(): # Make sure we have detected the OS before validating the page self.detect_media_os(forward=True) return if self.validate(notebook.get_current_page()) is not True: return if curpage == PAGE_NAME: self.set_install_page() # See if we need to alter our default HV based on install method self.guest_from_install_type() next_page = self._get_next_pagenum(curpage) self.widget("create-forward").grab_focus() notebook.set_current_page(next_page) def set_page_num_text(self, cur): cur += 1 final = PAGE_FINISH + 1 if self.skip_disk_page(): final -= 1 cur = min(cur, final) page_lbl = ("%s" % _("Step %(current_page)d of %(max_page)d") % {'current_page': cur, 'max_page': final}) self.widget("config-pagenum").set_markup(page_lbl) def page_changed(self, ignore1, ignore2, pagenum): # Update page number self.set_page_num_text(pagenum) if pagenum == PAGE_NAME: self.widget("create-back").set_sensitive(False) else: self.widget("create-back").set_sensitive(True) if pagenum == PAGE_INSTALL: self.detect_media_os() self.widget("install-os-distro-box").set_property( "visible", not self.container_install()) if pagenum != PAGE_FINISH: self.widget("create-forward").show() self.widget("create-finish").hide() return # PAGE_FINISH # This is hidden in reset_state, so that it doesn't distort # the size of the wizard if it is expanded by default due to # error self.widget("config-advanced-expander").show() self.widget("create-forward").hide() self.widget("create-finish").show() self.widget("create-finish").grab_focus() self.populate_summary() # Repopulate the HV list, so we can make install method relevant # changes self.populate_hv() # Make sure the networking selection takes into account # the install method, so we can warn if trying to PXE boot with # insufficient network option self.check_network_selection() def get_graphics_device(self, guest): if guest.installer.is_container(): return support_spice = guest.conn.check_conn_support( guest.conn.SUPPORT_CONN_HV_GRAPHICS_SPICE) if not self._rhel6_defaults(): support_spice = True gtype = self.get_config_graphics_type() if (gtype == virtinst.VirtualGraphics.TYPE_SPICE and not support_spice): logging.debug("Spice requested but HV doesn't support it. " "Using VNC graphics.") gtype = virtinst.VirtualGraphics.TYPE_VNC return virtinst.VirtualGraphics(guest.conn, type=gtype) def get_video_device(self, guest): if guest.installer.is_container(): return return virtinst.VirtualVideoDevice(guest.conn) def get_sound_device(self, guest): if (not self.config.get_new_vm_sound() or guest.installer.is_container()): return return virtinst.VirtualAudio(guest.conn) def build_guest(self, installer, name): guest = installer.guest_from_installer() guest.name = name # Generate UUID (makes customize dialog happy) try: guest.uuid = virtinst.util.randomUUID(guest.conn) except Exception, e: self.err.show_err(_("Error setting UUID: %s") % str(e)) return None # Set up default devices try: devs = [] devs.append(self.get_graphics_device(guest)) devs.append(self.get_video_device(guest)) devs.append(self.get_sound_device(guest)) for dev in devs: if dev: guest.add_device(dev) except Exception, e: self.err.show_err(_("Error setting up default devices:") + str(e)) return None return guest def validate(self, pagenum, oldguest=None): try: if pagenum == PAGE_NAME: return self.validate_name_page() elif pagenum == PAGE_INSTALL: return self.validate_install_page(oldguest=oldguest) elif pagenum == PAGE_MEM: return self.validate_mem_page() elif pagenum == PAGE_STORAGE: return self.validate_storage_page(oldguest=oldguest) elif pagenum == PAGE_FINISH: return self.validate_final_page() except Exception, e: self.err.show_err(_("Uncaught error validating install " "parameters: %s") % str(e)) return def validate_name_page(self): name = self.get_config_name() try: g = virtinst.Guest(self.conn.get_backend()) g.name = name except Exception, e: return self.err.val_err(_("Invalid System Name"), e) return True def validate_install_page(self, oldguest=None): instmethod = self.get_config_install_page() installer = None location = None extra = None ks = None cdrom = False is_import = False init = None fs = None distro, variant, ignore1, ignore2 = self.get_config_os_info() if instmethod == INSTALL_PAGE_ISO: instclass = virtinst.DistroInstaller media = self.get_config_local_media() if not media: return self.err.val_err( _("An install media selection is required.")) location = media cdrom = True elif instmethod == INSTALL_PAGE_URL: instclass = virtinst.DistroInstaller media, extra, ks = self.get_config_url_info() if not media: return self.err.val_err(_("An install tree is required.")) location = media elif instmethod == INSTALL_PAGE_PXE: instclass = virtinst.PXEInstaller elif instmethod == INSTALL_PAGE_IMPORT: instclass = virtinst.ImportInstaller is_import = True import_path = self.get_config_import_path() if not import_path: return self.err.val_err( _("A storage path to import is required.")) elif instmethod == INSTALL_PAGE_CONTAINER_APP: instclass = virtinst.ContainerInstaller init = self.get_config_container_app_path() if not init: return self.err.val_err(_("An application path is required.")) elif instmethod == INSTALL_PAGE_CONTAINER_OS: instclass = virtinst.ContainerInstaller fs = self.get_config_container_fs_path() if not fs: return self.err.val_err(_("An OS directory path is required.")) # Build the installer and Guest instance try: installer = self.build_installer(instclass) name = self.get_config_name() self.guest = self.build_guest(installer, name) if not self.guest: return False except Exception, e: return self.err.val_err( _("Error setting installer parameters."), e) # Validate media location try: if location is not None: self.guest.installer.location = location if cdrom: self.guest.installer.cdrom = True extraargs = "" if extra: extraargs += extra if ks: extraargs += " ks=%s" % ks if extraargs: self.guest.installer.extraargs = extraargs if init: self.guest.installer.init = init if fs: fsdev = virtinst.VirtualFilesystem(self.guest.conn) fsdev.target = "/" fsdev.source = fs self.guest.add_device(fsdev) except Exception, e: return self.err.val_err( _("Error setting install media location."), e) # OS distro/variant validation try: if distro: self.guest.os_type = distro if variant: self.guest.os_variant = variant except ValueError, e: return self.err.val_err(_("Error setting OS information."), e) # Kind of wonky, run storage validation now, which will assign # the import path. Import installer skips the storage page. if is_import: if not self.validate_storage_page(oldguest=oldguest): return False if not oldguest: if self.guest.installer.scratchdir_required(): path = self.guest.installer.scratchdir elif instmethod == INSTALL_PAGE_ISO: path = self.guest.installer.location else: path = None if path: uihelpers.check_path_search_for_qemu(self.topwin, self.conn, path) # Validation passed, store the install path (if there is one) in # gconf self.get_config_local_media(store_media=True) self.get_config_url_info(store_media=True) return True def validate_mem_page(self): cpus = self.widget("config-cpus").get_value() mem = self.widget("config-mem").get_value() # VCPUS try: self.guest.vcpus = int(cpus) except Exception, e: return self.err.val_err(_("Error setting CPUs."), e) # Memory try: self.guest.memory = int(mem) self.guest.maxmemory = int(mem) except Exception, e: return self.err.val_err(_("Error setting guest memory."), e) return True def validate_storage_page(self, oldguest=None): use_storage = self.widget("enable-storage").get_active() instcd = self.get_config_install_page() == INSTALL_PAGE_ISO conn = self.conn.get_backend() # CD/ISO install and no disks implies LiveCD if instcd: self.guest.installer.livecd = not use_storage usepath = None if oldguest and self.disk: usepath = self.disk.path if self.disk and self.disk in self.guest.get_devices("disk"): self.guest.remove_device(self.disk) self.disk = None # Validate storage if not use_storage: return True # Make sure default pool is running if self.is_default_storage(): ret = uihelpers.check_default_pool_active(self.topwin, self.conn) if not ret: return False try: # This can error out diskpath, disksize, sparse = self.get_storage_info() if usepath: diskpath = usepath elif self.is_default_storage() and not oldguest: # See if the ideal disk path (/default/pool/vmname.img) # exists, and if unused, prompt the use for using it ideal = util.get_ideal_path(self.conn, self.guest.name) do_exist = False ret = True try: do_exist = virtinst.VirtualDisk.path_exists(conn, ideal) ret = virtinst.VirtualDisk.path_in_use_by(conn, ideal) except: logging.exception("Error checking default path usage") if do_exist and not ret: do_use = self.err.yes_no( _("The following storage already exists, but is not\n" "in use by any virtual machine:\n\n%s\n\n" "Would you like to reuse this storage?") % ideal) if do_use: diskpath = ideal if not diskpath: return self.err.val_err(_("A storage path must be specified.")) disk = virtinst.VirtualDisk(conn, path=diskpath, size=disksize, sparse=sparse) fmt = self.config.get_storage_format() if (self.is_default_storage() and disk.vol_install and fmt in disk.vol_install.formats): logging.debug("Setting disk format from prefs: %s", fmt) disk.vol_install.format = fmt except Exception, e: return self.err.val_err(_("Storage parameter error."), e) isfatal, errmsg = disk.is_size_conflict() if not oldguest and not isfatal and errmsg: # Fatal errors are reported when setting 'size' res = self.err.ok_cancel(_("Not Enough Free Space"), errmsg) if not res: return False # Disk collision if not oldguest and disk.is_conflict_disk(self.guest.conn): res = self.err.yes_no(_('Disk "%s" is already in use by another ' 'guest!' % disk.path), _("Do you really want to use the disk?")) if not res: return False if not oldguest: uihelpers.check_path_search_for_qemu(self.topwin, self.conn, disk.path) self.disk = disk self.guest.add_device(self.disk) return True def validate_final_page(self): # HV + Arch selection self.guest.installer.type = self.capsdomain.hypervisor_type self.guest.installer.os_type = self.capsguest.os_type self.guest.installer.arch = self.capsguest.arch nettype, devname, macaddr = self.get_config_network_info() if nettype is None: # No network device available instmethod = self.get_config_install_page() methname = None if instmethod == INSTALL_PAGE_PXE: methname = "PXE" elif instmethod == INSTALL_PAGE_URL: methname = "URL" if methname: return self.err.val_err( _("Network device required for %s install.") % methname) nic = uihelpers.validate_network(self.topwin, self.conn, nettype, devname, macaddr) if nic is False: return False if self.nic and self.nic in self.guest.get_devices("interface"): self.guest.remove_device(self.nic) if nic: self.nic = nic self.guest.add_device(self.nic) return True # Interesting methods def build_installer(self, instclass): installer = instclass(self.conn.get_backend(), type=self.capsdomain.hypervisor_type, os_type=self.capsguest.os_type) installer.arch = self.capsguest.arch return installer def guest_from_install_type(self): instmeth = self.get_config_install_page() if not self.conn.is_xen() and not self.conn.is_test_conn(): return # FIXME: some things are dependent on domain type (vcpu max) if instmeth in [INSTALL_PAGE_URL, INSTALL_PAGE_IMPORT]: self.change_caps(gtype="xen") def reset_guest_type(self): self.change_caps() def rebuild_guest(self): pagenum = 0 guest = self.guest while True: self.validate(pagenum, oldguest=guest) if pagenum >= PAGE_FINISH: break pagenum = self._get_next_pagenum(pagenum) def finish(self, src_ignore): # Validate the final page page = self.widget("create-pages").get_current_page() if self.validate(page) is not True: return False self.rebuild_guest() guest = self.guest # Start the install self.failed_guest = None self.topwin.set_sensitive(False) self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) def start_install(): if not self.get_config_customize(): self.start_install(guest) return self.customize(guest) self._check_start_error(start_install) def _undo_finish(self, ignore=None): self.topwin.set_sensitive(True) self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) def _check_start_error(self, cb, *args, **kwargs): try: cb(*args, **kwargs) except Exception, e: self._undo_finish() self.err.show_err(_("Error starting installation: ") + str(e)) def customize(self, guest): virtinst_guest = vmmDomainVirtinst(self.conn, guest, self.guest.uuid) def cleanup_config_window(): if self.config_window: for s in self.config_window_signals: self.config_window.disconnect(s) self.config_window.cleanup() self.config_window = None def start_install_wrapper(ignore, guest): cleanup_config_window() if not self.is_visible(): return self._check_start_error(self.start_install, guest) def details_closed(ignore): cleanup_config_window() self._undo_finish() self.widget("summary-customize").set_active(False) cleanup_config_window() self.config_window = vmmDetails(virtinst_guest, self.topwin) self.config_window_signals = [] self.config_window_signals.append(self.config_window.connect( "customize-finished", start_install_wrapper, guest)) self.config_window_signals.append(self.config_window.connect( "details-closed", details_closed)) self.config_window.show() def start_install(self, guest): progWin = vmmAsyncJob(self.do_install, [guest], _("Creating Virtual Machine"), _("The virtual machine is now being " "created. Allocation of disk storage " "and retrieval of the installation " "images may take a few minutes to " "complete."), self.topwin) error, details = progWin.run() self.topwin.set_sensitive(True) self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) if error: error = (_("Unable to complete install: '%s'") % error) self.err.show_err(error, details=details) self.failed_guest = self.guest return self.close() # Launch details dialog for new VM self.emit("action-show-vm", self.conn.get_uri(), guest.uuid) def do_install(self, asyncjob, guest): meter = asyncjob.get_meter() logging.debug("Starting background install process") guest.start_install(False, meter=meter) logging.debug("Install completed") # Make sure we pick up the domain object # Wait for VM to show up self.conn.schedule_priority_tick() count = 0 while (guest.uuid not in self.conn.vms) and (count < 100): count += 1 time.sleep(.1) vm = self.conn.get_vm(guest.uuid) vm.tick() if vm.is_shutoff(): # Domain is already shutdown, but no error was raised. # Probably means guest had no 'install' phase, as in # for live cds. Try to restart the domain. vm.startup() elif guest.installer.has_install_phase(): # Register a status listener, which will restart the # guest after the install has finished def cb(): vm.connect_opt_out("status-changed", self.check_install_status, guest) return False self.idle_add(cb) def check_install_status(self, vm, ignore1, ignore2, virtinst_guest=None): if vm.is_crashed(): logging.debug("VM crashed, cancelling install plans.") return True if not vm.is_shutoff(): return try: if virtinst_guest: continue_inst = virtinst_guest.get_continue_inst() if continue_inst: logging.debug("VM needs a 2 stage install, continuing.") # Continue the install, then reconnect this opt # out handler, removing the virtinst_guest which # will force one final restart. virtinst_guest.continue_install() vm.connect_opt_out("status-changed", self.check_install_status, None) return True if vm.get_install_abort(): logging.debug("User manually shutdown VM, not restarting " "guest after install.") return True logging.debug("Install should be completed, starting VM.") vm.startup() except Exception, e: self.err.show_err(_("Error continue install: %s") % str(e)) return True def pretty_storage(self, size): return "%.1f GB" % float(size) def pretty_memory(self, mem): return "%d MB" % (mem / 1024.0) # Distro detection methods def set_distro_labels(self, distro, ver): # Helper to set auto detect result labels if not self.is_detect_active(): return self.widget("install-os-type-label").set_text(distro) self.widget("install-os-version-label").set_text(ver) def set_os_val(self, os_widget, value): # Helper method to set the OS Type/Variant selections to the passed # values, or -1 if not present. model = os_widget.get_model() def set_val(): idx = 0 for idx in range(0, len(model)): row = model[idx] if value and row[0] == value: break if idx == len(os_widget.get_model()) - 1: idx = -1 os_widget.set_active(idx) if idx == -1: os_widget.set_active(0) if idx >= 0: return row[1] if self.show_all_os: return None ret = set_val() if ret: return ret # Trigger the last element in the list, which turns on show_all_os os_widget.set_active(len(model) - 1) ret = set_val() if ret: return ret return _("Unknown") def set_distro_selection(self, distro, ver): # Wrapper to change OS Type/Variant values, and update the distro # detection labels if not self.is_detect_active(): return dl = self.set_os_val(self.widget("install-os-type"), distro) vl = self.set_os_val(self.widget("install-os-version"), ver) self.set_distro_labels(dl, vl) def check_detection(self, idx, forward): results = None try: base = _("Detecting") if not self.detectedDistro or (idx >= (DETECT_TIMEOUT * 2)): detect_str = base + ("." * ((idx % 3) + 1)) self.set_distro_labels(detect_str, detect_str) self.timeout_add(500, self.check_detection, idx + 1, forward) return results = self.detectedDistro except: logging.exception("Error in distro detect timeout") results = results or (None, None) self.widget("create-forward").set_sensitive(True) self.mediaDetected = True self.detecting = False logging.debug("Finished OS detection.") self.set_distro_selection(*results) if forward: self.idle_add(self.forward, ()) def start_detection(self, forward): if self.detecting: return media = self.get_config_detectable_media() if not media: return self.detectedDistro = None logging.debug("Starting OS detection thread for media=%s", media) self.widget("create-forward").set_sensitive(False) detectThread = threading.Thread(target=self.actually_detect, name="Actual media detection", args=(media,)) detectThread.setDaemon(True) detectThread.start() self.check_detection(0, forward) def actually_detect(self, media): try: installer = self.build_installer(virtinst.DistroInstaller) installer.location = media self.detectedDistro = installer.detect_distro() except: logging.exception("Error detecting distro.") self.detectedDistro = (None, None) def _rhel6_defaults(self): emu = None if self.guest: emu = self.guest.emulator elif self.capsdomain: emu = self.capsdomain.emulator ret = self.conn.rhel6_defaults(emu) return ret def _browse_file(self, callback, is_media=False, is_dir=False): if is_media: reason = self.config.CONFIG_DIR_ISO_MEDIA elif is_dir: reason = self.config.CONFIG_DIR_FS else: reason = self.config.CONFIG_DIR_IMAGE if self.storage_browser is None: self.storage_browser = vmmStorageBrowser(self.conn) self.storage_browser.rhel6_defaults = self._rhel6_defaults() self.storage_browser.set_vm_name(self.get_config_name()) self.storage_browser.set_finish_cb(callback) self.storage_browser.set_browse_reason(reason) self.storage_browser.show(self.topwin, self.conn)