virt-manager/src/virtManager/create.py

1851 lines
67 KiB
Python
Raw Normal View History

2006-08-09 19:40:34 +04:00
#
2009-03-09 23:16:45 +03:00
# Copyright (C) 2008 Red Hat, Inc.
# Copyright (C) 2008 Cole Robinson <crobinso@redhat.com>
2006-08-09 19:40:34 +04:00
#
# 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.
2006-08-09 19:40:34 +04:00
#
import gobject
import gtk
2009-03-09 23:16:45 +03:00
import sys
2009-03-09 23:16:45 +03:00
import time
import traceback
2009-03-09 23:16:45 +03:00
import threading
import logging
2006-08-09 19:40:34 +04:00
2009-03-09 23:16:45 +03:00
import virtinst
import virtManager.uihelpers as uihelpers
2009-03-09 23:16:45 +03:00
from virtManager import util
from virtManager.mediadev import MEDIA_CDROM
from virtManager.error import vmmErrorDialog
2009-03-09 23:16:45 +03:00
from virtManager.asyncjob import vmmAsyncJob
from virtManager.createmeter import vmmCreateMeter
from virtManager.storagebrowse import vmmStorageBrowser
from virtManager.details import vmmDetails
from virtManager.domain import vmmDomainVirtinst
2009-03-09 23:16:45 +03:00
OS_GENERIC = "generic"
2009-03-09 23:16:45 +03:00
# Number of seconds to wait for media detection
DETECT_TIMEOUT = 20
2009-03-09 23:16:45 +03:00
PAGE_NAME = 0
PAGE_INSTALL = 1
PAGE_MEM = 2
PAGE_STORAGE = 3
PAGE_FINISH = 4
2009-03-09 23:16:45 +03:00
INSTALL_PAGE_ISO = 0
INSTALL_PAGE_URL = 1
INSTALL_PAGE_PXE = 2
INSTALL_PAGE_IMPORT = 3
2006-08-09 19:40:34 +04:00
class vmmCreate(gobject.GObject):
__gsignals__ = {
"action-show-console": (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, (str,str)),
"action-show-terminal": (gobject.SIGNAL_RUN_FIRST,
2009-03-09 23:16:45 +03:00
gobject.TYPE_NONE, (str,str)),
"action-show-help": (gobject.SIGNAL_RUN_FIRST,
2009-03-09 23:16:45 +03:00
gobject.TYPE_NONE, [str]),
}
def __init__(self, config, engine):
2010-11-30 22:40:49 +03:00
gobject.GObject.__init__(self)
self.config = config
self.engine = engine
2009-03-09 23:16:45 +03:00
self.window = gtk.glade.XML(config.get_glade_dir() + \
"/vmm-create.glade",
"vmm-create", domain="virt-manager")
self.topwin = self.window.get_widget("vmm-create")
self.err = vmmErrorDialog(self.topwin)
2009-03-09 23:16:45 +03:00
self.conn = None
self.caps = None
self.capsguest = None
self.capsdomain = None
2009-03-09 23:16:45 +03:00
self.guest = None
self.disk = None
self.nic = None
2009-03-09 23:16:45 +03:00
self.storage_browser = None
self.conn_signals = []
2009-03-09 23:16:45 +03:00
# Distro detection state variables
self.detectedDistro = None
self.detectThreadEvent = threading.Event()
self.detectThreadEvent.set()
self.mediaDetected = False
2009-03-09 23:16:45 +03:00
# 'Guest' class from the previous failed install
self.failed_guest = None
2009-03-09 23:16:45 +03:00
# Host space polling
self.host_storage_timer = None
# 'Configure before install' window
self.config_window = None
self.config_window_signal = None
self.window.signal_autoconnect({
2009-03-09 23:16:45 +03:00
"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_help_clicked": self.show_help,
2009-03-09 23:16:45 +03:00
"on_create_pages_switch_page": self.page_changed,
"on_create_vm_name_activate": self.forward,
2009-03-09 23:16:45 +03:00
"on_create_conn_changed": self.conn_changed,
"on_install_url_box_changed": self.url_box_changed,
2009-11-16 00:36:37 +03:00
"on_install_local_cdrom_toggled": self.toggle_local_cdrom,
2009-03-09 23:16:45 +03:00
"on_install_local_cdrom_combo_changed": self.detect_media_os,
"on_install_local_box_changed": self.detect_media_os,
2009-03-09 23:16:45 +03:00
"on_install_local_browse_clicked": self.browse_iso,
"on_install_import_browse_clicked": self.browse_import,
2009-03-09 23:16:45 +03:00
"on_install_detect_os_toggled": self.toggle_detect_os,
"on_install_os_type_changed": self.change_os_type,
"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,
2009-03-09 23:16:45 +03:00
"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,
2009-03-09 23:16:45 +03:00
"on_config_set_macaddr_toggled": self.toggle_macaddr,
"on_config_hv_changed": self.hv_changed,
"on_config_arch_changed": self.arch_changed,
})
util.bind_escape_key_close(self)
2009-03-09 23:16:45 +03:00
self.set_initial_state()
def is_visible(self):
if self.topwin.flags() & gtk.VISIBLE:
return True
return False
2009-03-09 23:16:45 +03:00
def show(self, uri=None):
self.reset_state(uri)
self.topwin.show()
self.topwin.present()
2006-08-09 19:40:34 +04:00
2009-03-09 23:16:45 +03:00
def close(self, ignore1=None, ignore2=None):
self.topwin.hide()
self.remove_timers()
if self.config_window:
self.config_window.close()
2009-03-09 23:16:45 +03:00
return 1
def remove_timers(self):
try:
if self.host_storage_timer:
gobject.source_remove(self.host_storage_timer)
self.host_storage_timer = None
except:
pass
def set_conn(self, newconn, force_validate=False):
if self.conn == newconn and not force_validate:
2009-03-09 23:16:45 +03:00
return
if self.conn:
for signal in self.conn_signals:
self.conn.disconnect(signal)
self.conn_signals = []
2009-03-09 23:16:45 +03:00
self.conn = newconn
if self.conn:
self.set_conn_state()
# State init methods
def startup_error(self, error):
self.window.get_widget("startup-error-box").show()
self.window.get_widget("install-box").hide()
2009-03-09 23:16:45 +03:00
self.window.get_widget("create-forward").set_sensitive(False)
self.window.get_widget("startup-error").set_text("Error: %s" % error)
2009-03-09 23:16:45 +03:00
return False
def startup_warning(self, error):
self.window.get_widget("startup-error-box").show()
self.window.get_widget("startup-error").set_text("Warning: %s" %
error)
2006-08-09 19:40:34 +04:00
def set_initial_state(self):
2009-03-09 23:16:45 +03:00
self.window.get_widget("create-pages").set_show_tabs(False)
self.window.get_widget("install-method-pages").set_show_tabs(False)
2006-08-09 19:40:34 +04:00
2009-03-09 23:16:45 +03:00
# FIXME: Unhide this when we make some documentation
self.window.get_widget("create-help").hide()
finish_img = gtk.image_new_from_stock(gtk.STOCK_QUIT,
gtk.ICON_SIZE_BUTTON)
self.window.get_widget("create-finish").set_image(finish_img)
2009-03-09 23:16:45 +03:00
blue = gtk.gdk.color_parse("#0072A8")
self.window.get_widget("create-header").modify_bg(gtk.STATE_NORMAL,
blue)
box = self.window.get_widget("create-vm-icon-box")
image = gtk.image_new_from_icon_name("vm_new_wizard",
gtk.ICON_SIZE_DIALOG)
image.show()
box.pack_end(image, False)
2009-03-09 23:16:45 +03:00
# Connection list
self.window.get_widget("create-conn-label").set_text("")
self.window.get_widget("startup-error").set_text("")
2009-03-09 23:16:45 +03:00
conn_list = self.window.get_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.window.get_widget("install-local-box")
iso_model = gtk.ListStore(str)
iso_list.set_model(iso_model)
iso_list.set_text_column(0)
self.window.get_widget("install-local-box").child.connect("activate",
self.detect_media_os)
2009-03-09 23:16:45 +03:00
# Lists for the install urls
media_url_list = self.window.get_widget("install-url-box")
media_url_model = gtk.ListStore(str)
media_url_list.set_model(media_url_model)
media_url_list.set_text_column(0)
self.window.get_widget("install-url-box").child.connect("activate",
self.detect_media_os)
2009-03-09 23:16:45 +03:00
ks_url_list = self.window.get_widget("install-ks-box")
ks_url_model = gtk.ListStore(str)
ks_url_list.set_model(ks_url_model)
ks_url_list.set_text_column(0)
2009-03-09 23:16:45 +03:00
# Lists for distro type + variant
os_type_list = self.window.get_widget("install-os-type")
os_type_model = gtk.ListStore(str, str)
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)
2009-03-09 23:16:45 +03:00
os_variant_list = self.window.get_widget("install-os-version")
os_variant_model = gtk.ListStore(str, str)
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)
2009-03-09 23:16:45 +03:00
# Physical CD-ROM model
cd_list = self.window.get_widget("install-local-cdrom-combo")
uihelpers.init_mediadev_combo(cd_list)
2009-03-09 23:16:45 +03:00
# Networking
# [ interface type, device name, label, sensitive ]
net_list = self.window.get_widget("config-netdev")
bridge_box = self.window.get_widget("config-netdev-bridge-box")
uihelpers.init_network_list(net_list, bridge_box)
2006-08-09 19:40:34 +04:00
2009-03-09 23:16:45 +03:00
# Archtecture
archModel = gtk.ListStore(str)
2009-03-09 23:16:45 +03:00
archList = self.window.get_widget("config-arch")
text = gtk.CellRendererText()
archList.pack_start(text, True)
archList.add_attribute(text, 'text', 0)
archList.set_model(archModel)
2009-03-09 23:16:45 +03:00
hyperModel = gtk.ListStore(str, str, str, bool)
hyperList = self.window.get_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
2009-03-09 23:16:45 +03:00
sparse_info = self.window.get_widget("config-storage-nosparse-info")
uihelpers.set_sparse_tooltip(sparse_info)
2009-03-09 23:16:45 +03:00
def reset_state(self, urihint=None):
self.failed_guest = None
self.guest = None
self.disk = None
self.nic = None
2009-03-09 23:16:45 +03:00
self.window.get_widget("create-pages").set_current_page(PAGE_NAME)
self.page_changed(None, None, PAGE_NAME)
self.window.get_widget("startup-error-box").hide()
self.window.get_widget("install-box").show()
2009-03-09 23:16:45 +03:00
# Name page state
self.window.get_widget("create-vm-name").set_text("")
2009-12-15 00:48:35 +03:00
self.window.get_widget("create-vm-name").grab_focus()
2009-03-09 23:16:45 +03:00
self.window.get_widget("method-local").set_active(True)
self.window.get_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))
2009-03-09 23:16:45 +03:00
if not activeconn:
return self.startup_error(
_("No active connection to install on."))
2009-03-09 23:16:45 +03:00
# Everything from this point forward should be connection independent
# Distro/Variant
self.toggle_detect_os(self.window.get_widget("install-detect-os"))
self.populate_os_type_model()
2009-03-09 23:16:45 +03:00
self.window.get_widget("install-os-type").set_active(0)
self.window.get_widget("install-local-box").child.set_text("")
iso_model = self.window.get_widget("install-local-box").get_model()
self.populate_media_model(iso_model, self.conn.config_get_iso_paths())
2009-03-09 23:16:45 +03:00
# Install URL
self.window.get_widget("install-urlopts-entry").set_text("")
self.window.get_widget("install-ks-box").child.set_text("")
self.window.get_widget("install-url-box").child.set_text("")
self.window.get_widget("install-url-options").set_expanded(False)
2009-03-09 23:16:45 +03:00
urlmodel = self.window.get_widget("install-url-box").get_model()
ksmodel = self.window.get_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())
2007-07-14 22:43:52 +04:00
# Install import
self.window.get_widget("install-import-entry").set_text("")
2009-03-09 23:16:45 +03:00
# Mem / CPUs
self.window.get_widget("config-mem").set_value(512)
self.window.get_widget("config-cpus").set_value(1)
2009-03-09 23:16:45 +03:00
# Storage
label_widget = self.window.get_widget("phys-hd-label")
if not self.host_storage_timer:
self.host_storage_timer = util.safe_timeout_add(3 * 1000,
uihelpers.host_space_tick,
self.conn, self.config,
label_widget)
2009-03-09 23:16:45 +03:00
self.window.get_widget("enable-storage").set_active(True)
self.window.get_widget("config-storage-create").set_active(True)
self.window.get_widget("config-storage-size").set_value(8)
self.window.get_widget("config-storage-entry").set_text("")
self.window.get_widget("config-storage-nosparse").set_active(True)
2009-03-09 23:16:45 +03:00
# Final page
self.window.get_widget("summary-customize").set_active(False)
net_expander = self.window.get_widget("config-advanced-expander")
net_warn_icon = self.window.get_widget("config-netdev-warn-icon")
net_warn_box = self.window.get_widget("config-netdev-warn-box")
net_expander.hide()
net_warn_icon.hide()
net_warn_box.hide()
net_expander.set_expanded(False)
2009-03-09 23:16:45 +03:00
2009-03-09 23:16:45 +03:00
def set_conn_state(self):
# Update all state that has some dependency on the current connection
self.window.get_widget("create-forward").set_sensitive(True)
if self.conn.is_read_only():
return self.startup_error(_("Connection is read only."))
if self.conn.no_install_options():
error = _("No hypervisor options were found for this\n"
"connection.")
if self.conn.is_qemu():
error += "\n\n"
error += _("This usually means that qemu or kvm is not\n"
"installed on your machine. Please ensure they\n"
"are installed as intended.")
return self.startup_error(error)
2009-03-09 23:16:45 +03:00
# A bit out of order, but populate arch + hv lists so we can
# determine a default
self.conn.invalidate_caps()
2009-03-09 23:16:45 +03:00
self.caps = self.conn.get_capabilities()
self.change_caps()
2009-03-09 23:16:45 +03:00
self.populate_hv()
if self.conn.is_xen():
if self.conn.hw_virt_supported():
if self.conn.is_bios_virt_disabled():
error = _("Host supports full virtualization, but\n"
"no related install options are available.\n"
"This may mean support is disabled in your\n"
"system BIOS.")
self.startup_warning(error)
else:
error = _("Host does not appear to support hardware\n"
"virtualization. Install options may be limited.")
self.startup_warning(error)
elif self.conn.is_qemu():
if not self.conn.is_kvm_supported():
error = _("KVM is not available. This may mean the KVM\n"
"package is not installed, or the KVM kernel modules \n"
"are not loaded. Your virtual machines may perform poorly.")
self.startup_warning(error)
2009-03-09 23:16:45 +03:00
is_local = not self.conn.is_remote()
is_storage_capable = self.conn.is_storage_capable()
is_pv = (self.capsguest.os_type == "xen")
# Install Options
method_tree = self.window.get_widget("method-tree")
method_pxe = self.window.get_widget("method-pxe")
method_local = self.window.get_widget("method-local")
method_tree.set_sensitive(is_local)
method_local.set_sensitive(not is_pv)
method_pxe.set_sensitive(not is_pv)
pxe_tt = None
local_tt = None
tree_tt = None
if is_pv:
base = _("%s installs not available for paravirt guests.")
pxe_tt = base % "PXE"
local_tt = base % "CDROM/ISO"
if not is_local:
tree_tt = _("URL installs not available for remote connections.")
if not is_storage_capable and not local_tt:
local_tt = _("Connection does not support storage management.")
if not is_local and not is_storage_capable:
method_local.set_sensitive(False)
if method_tree.get_active() and not is_local:
method_local.set_active(True)
elif is_pv:
method_tree.set_active(True)
if not (method_tree.get_property("sensitive") or
method_local.get_property("sensitive") or
method_pxe.get_property("sensitive")):
self.startup_error(_("No install options available for this "
"connection."))
util.tooltip_wrapper(method_tree, tree_tt)
util.tooltip_wrapper(method_local, local_tt)
util.tooltip_wrapper(method_pxe, pxe_tt)
# Install local
2009-11-16 00:36:37 +03:00
iso_option = self.window.get_widget("install-local-iso")
cdrom_option = self.window.get_widget("install-local-cdrom")
cdrom_list = self.window.get_widget("install-local-cdrom-combo")
cdrom_warn = self.window.get_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)
util.tooltip_wrapper(cdrom_warn, self.conn.mediadev_error)
else:
cdrom_warn.hide()
2009-03-09 23:16:45 +03:00
# Don't select physical CDROM if no valid media is present
use_cd = (cdrom_list.get_active() >= 0)
2009-03-09 23:16:45 +03:00
if use_cd:
2009-11-16 00:36:37 +03:00
cdrom_option.set_active(True)
else:
2009-11-16 00:36:37 +03:00
iso_option.set_active(True)
# Only allow ISO option for remote VM
if not is_local:
iso_option.set_active(True)
2009-03-09 23:16:45 +03:00
2009-11-16 00:36:37 +03:00
self.toggle_local_cdrom(cdrom_option)
self.toggle_local_iso(iso_option)
2009-03-09 23:16:45 +03:00
# 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 = ("<span size='small' color='#484848'>%s</span>" %
mem_label)
self.window.get_widget("config-mem").set_range(50, memory/1024)
self.window.get_widget("phys-mem-label").set_markup(mem_label)
# CPU
phys_cpus = self.conn.host_active_processor_count()
max_v = self.conn.get_max_vcpus(_type=self.capsdomain.hypervisor_type)
cmax = phys_cpus
if int(max_v) < int(phys_cpus):
cmax = max_v
cpu_tooltip = (_("Hypervisor only supports %d virtual CPUs.") %
max_v)
else:
cpu_tooltip = None
util.tooltip_wrapper(self.window.get_widget("config-cpus"),
cpu_tooltip)
2009-03-10 05:42:17 +03:00
cmax = int(cmax)
if cmax <= 0:
cmax = 1
2009-03-09 23:16:45 +03:00
cpu_label = _("Up to %(numcpus)d available") % { 'numcpus': \
int(phys_cpus)}
cpu_label = ("<span size='small' color='#484848'>%s</span>" %
cpu_label)
2009-03-10 05:42:17 +03:00
self.window.get_widget("config-cpus").set_range(1, cmax)
2009-03-09 23:16:45 +03:00
self.window.get_widget("phys-cpu-label").set_markup(cpu_label)
# Storage
have_storage = (is_local or is_storage_capable)
storage_tooltip = None
use_storage = self.window.get_widget("config-storage-select")
storage_area = self.window.get_widget("config-storage-area")
storage_area.set_sensitive(have_storage)
if not have_storage:
storage_tooltip = _("Connection does not support storage"
" management.")
use_storage.set_sensitive(True)
util.tooltip_wrapper(storage_area, storage_tooltip)
# Networking
net_list = self.window.get_widget("config-netdev")
do_warn = uihelpers.populate_network_list(net_list, self.conn)
self.set_net_warn(self.conn.netdev_error or do_warn,
self.conn.netdev_error, True)
newmac = uihelpers.generate_macaddr(self.conn)
self.window.get_widget("config-set-macaddr").set_active(bool(newmac))
2009-03-09 23:16:45 +03:00
self.window.get_widget("config-macaddr").set_text(newmac)
def set_net_warn(self, show_warn, msg, do_tooltip):
net_warn_icon = self.window.get_widget("config-netdev-warn-icon")
net_warn_box = self.window.get_widget("config-netdev-warn-box")
net_warn_label = self.window.get_widget("config-netdev-warn-label")
net_expander = self.window.get_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:
util.tooltip_wrapper(net_warn_icon, show_warn and msg or "")
else:
net_warn_box.set_property("visible", show_warn)
markup = show_warn and ("<small>%s</small>" % msg) or ""
net_warn_label.set_markup(markup)
2009-03-09 23:16:45 +03:00
def populate_hv(self):
hv_list = self.window.get_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
2009-03-09 23:16:45 +03:00
# Don't add multiple rows for each arch
for m in model:
if m[0] == label:
label = None
break
if label == 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.")
2009-03-09 23:16:45 +03:00
model.append([label, gtype, domtype, sensitive])
2009-03-09 23:16:45 +03:00
hv_info = self.window.get_widget("config-hv-info")
if tooltip:
hv_info.show()
util.tooltip_wrapper(hv_info, tooltip)
else:
2009-03-09 23:16:45 +03:00
hv_info.hide()
2006-08-09 19:40:34 +04:00
2009-03-09 23:16:45 +03:00
hv_list.set_active(default)
2009-03-09 23:16:45 +03:00
def populate_arch(self):
arch_list = self.window.get_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.window.get_widget("create-conn")
model = conn_list.get_model()
model.clear()
default = -1
for c in self.engine.connections.values():
connobj = c["connection"]
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()])
2009-03-09 23:16:45 +03:00
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.connections[activeuri]["connection"]
self.window.get_widget("create-conn-label").set_text(activedesc)
if len(model) <= 1:
self.window.get_widget("create-conn").hide()
self.window.get_widget("create-conn-label").show()
else:
2009-03-09 23:16:45 +03:00
self.window.get_widget("create-conn").show()
self.window.get_widget("create-conn-label").hide()
return activeconn
def populate_os_type_model(self):
model = self.window.get_widget("install-os-type").get_model()
model.clear()
model.append([OS_GENERIC, _("Generic")])
types = virtinst.FullVirtGuest.list_os_types()
for t in types:
model.append([t, virtinst.FullVirtGuest.get_os_type_label(t)])
def populate_os_variant_model(self, _type):
model = self.window.get_widget("install-os-version").get_model()
model.clear()
if _type == OS_GENERIC:
model.append([OS_GENERIC, _("Generic")])
return
variants = virtinst.FullVirtGuest.list_os_variants(_type)
for variant in variants:
model.append([variant,
virtinst.FullVirtGuest.get_os_variant_label(_type,
variant)])
def populate_media_model(self, model, urls):
2009-03-09 23:16:45 +03:00
model.clear()
for url in urls:
model.append([url])
def change_caps(self, gtype=None, dtype=None, arch=None):
if gtype == 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
2009-03-09 23:16:45 +03:00
(newg,
newdom) = virtinst.CapabilitiesParser.guest_lookup(
conn=self.conn.vmm,
caps=self.caps,
os_type = gtype,
type = dtype,
accelerated=True,
arch=arch)
2009-03-09 23:16:45 +03:00
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
2009-03-09 23:16:45 +03:00
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):
ignore, ignore, 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")
2009-03-09 23:16:45 +03:00
if len(self.guest.disks) == 0:
storage = _("None")
else:
2009-03-09 23:16:45 +03:00
disk = self.guest.disks[0]
storage = "%s" % self.pretty_storage(disk.size)
storage += (" <span size='small' color='#484848'>%s</span>" %
disk.path)
osstr = ""
if not dlabel:
osstr = _("Generic")
elif not vlabel:
osstr = _("Generic") + " " + dlabel
2007-03-21 19:28:36 +03:00
else:
2009-03-09 23:16:45 +03:00
osstr = vlabel
2007-03-21 19:28:36 +03:00
2009-03-09 23:16:45 +03:00
title = "Ready to begin installation of <b>%s</b>" % self.guest.name
2009-03-09 23:16:45 +03:00
self.window.get_widget("summary-title").set_markup(title)
self.window.get_widget("summary-os").set_text(osstr)
self.window.get_widget("summary-install").set_text(install)
self.window.get_widget("summary-mem").set_text(mem)
self.window.get_widget("summary-cpu").set_text(cpu)
self.window.get_widget("summary-storage").set_markup(storage)
2009-03-09 23:16:45 +03:00
# get_* methods
def get_config_name(self):
return self.window.get_widget("create-vm-name").get_text()
def is_install_page(self):
notebook = self.window.get_widget("create-pages")
curpage = notebook.get_current_page()
return curpage == PAGE_INSTALL
2009-03-09 23:16:45 +03:00
def get_config_install_page(self):
if self.window.get_widget("method-local").get_active():
2009-03-09 23:16:45 +03:00
return INSTALL_PAGE_ISO
elif self.window.get_widget("method-tree").get_active():
2009-03-09 23:16:45 +03:00
return INSTALL_PAGE_URL
elif self.window.get_widget("method-pxe").get_active():
return INSTALL_PAGE_PXE
elif self.window.get_widget("method-import").get_active():
return INSTALL_PAGE_IMPORT
2009-03-09 23:16:45 +03:00
def get_config_os_info(self):
d_list = self.window.get_widget("install-os-type")
d_idx = d_list.get_active()
v_list = self.window.get_widget("install-os-version")
v_idx = v_list.get_active()
distro = None
dlabel = None
variant = None
vlabel = None
if d_idx >= 0:
distro, dlabel = d_list.get_model()[d_idx]
if v_idx >= 0:
variant, vlabel = v_list.get_model()[v_idx]
return (distro, variant, dlabel, vlabel)
def get_config_local_media(self, store_media=False):
2009-03-09 23:16:45 +03:00
if self.window.get_widget("install-local-cdrom").get_active():
return self.window.get_widget("install-local-cdrom-combo").get_active_text()
else:
ret = self.window.get_widget("install-local-box").child.get_text()
if ret and store_media:
self.conn.config_add_iso_path(ret)
return ret
2009-03-09 23:16:45 +03:00
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.window.get_widget("install-url-box").get_active_text()
elif instpage == INSTALL_PAGE_IMPORT:
media = self.window.get_widget("install-import-entry").get_text()
2009-03-09 23:16:45 +03:00
return media
def get_config_url_info(self, store_media=False):
media = self.window.get_widget("install-url-box").get_active_text().strip()
2009-03-09 23:16:45 +03:00
extra = self.window.get_widget("install-urlopts-entry").get_text().strip()
ks = self.window.get_widget("install-ks-box").get_active_text().strip()
2009-03-09 23:16:45 +03:00
if media and store_media:
2009-03-09 23:16:45 +03:00
self.config.add_media_url(media)
if ks and store_media:
2009-03-09 23:16:45 +03:00
self.config.add_kickstart_url(ks)
return (media.strip(), extra.strip(), ks.strip())
def get_config_import_path(self):
return self.window.get_widget("install-import-entry").get_text()
def get_default_path(self, name):
# Don't generate a new path if the install failed
if self.failed_guest:
if len(self.failed_guest.disks) > 0:
return self.failed_guest.disks[0].path
return util.get_default_path(self.conn, self.config, name)
def is_default_storage(self):
usedef = self.window.get_widget("config-storage-create").get_active()
isimport = (self.get_config_install_page() == INSTALL_PAGE_IMPORT)
return usedef and not isimport
2009-03-09 23:16:45 +03:00
def get_storage_info(self):
path = None
size = self.window.get_widget("config-storage-size").get_value()
sparse = not self.window.get_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():
2009-03-09 23:16:45 +03:00
path = self.get_default_path(self.guest.name)
logging.debug("Default storage path is: %s" % path)
else:
path = self.window.get_widget("config-storage-entry").get_text()
return (path, size, sparse)
2009-03-09 23:16:45 +03:00
def get_config_network_info(self):
net_list = self.window.get_widget("config-netdev")
bridge_ent = self.window.get_widget("config-netdev-bridge")
2009-03-09 23:16:45 +03:00
macaddr = self.window.get_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_sound(self):
2009-03-09 23:16:45 +03:00
if self.conn.is_remote():
return self.config.get_remote_sound()
return self.config.get_local_sound()
def get_config_customize(self):
return self.window.get_widget("summary-customize").get_active()
2009-03-09 23:16:45 +03:00
def is_detect_active(self):
return self.window.get_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.connections[uri]["connection"]
# 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():
2009-03-09 23:16:45 +03:00
return
self.set_conn(conn)
def netdev_changed(self, ignore):
self.check_network_selection()
def check_network_selection(self):
src = self.window.get_widget("config-netdev")
idx = src.get_active()
show_pxe_warn = True
if not idx < 0:
row = src.get_model()[idx]
ntype = row[0]
obj = row[6]
show_pxe_warn = (
(ntype == virtinst.VirtualNetworkInterface.TYPE_USER or
(ntype == virtinst.VirtualNetworkInterface.TYPE_VIRTUAL and
not obj.can_pxe())))
self.set_net_warn(show_pxe_warn,
_("Network selection does not support PXE"), False)
2009-03-09 23:16:45 +03:00
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)
2009-03-09 23:16:45 +03:00
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.window.get_widget("install-url-box").child.flags() &
gtk.HAS_FOCUS):
2009-03-09 23:16:45 +03:00
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_detect_thread(forward=forward)
2009-03-09 23:16:45 +03:00
def toggle_detect_os(self, src):
dodetect = src.get_active()
if dodetect:
self.window.get_widget("install-os-type-label").show()
self.window.get_widget("install-os-version-label").show()
self.window.get_widget("install-os-type").hide()
self.window.get_widget("install-os-version").hide()
self.mediaDetected = False
2009-03-09 23:16:45 +03:00
self.detect_media_os() # Run detection
else:
self.window.get_widget("install-os-type-label").hide()
self.window.get_widget("install-os-version-label").hide()
self.window.get_widget("install-os-type").show()
self.window.get_widget("install-os-version").show()
def change_os_type(self, box):
model = box.get_model()
if box.get_active_iter() != None:
_type = model.get_value(box.get_active_iter(), 0)
self.populate_os_variant_model(_type)
variant = self.window.get_widget("install-os-version")
variant.set_active(0)
2009-11-16 00:36:37 +03:00
def toggle_local_cdrom(self, src):
2009-03-09 23:16:45 +03:00
combo = self.window.get_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.window.get_widget("install-local-cdrom-combo").set_sensitive(is_active)
def toggle_local_iso(self, src):
uselocal = src.get_active()
self.window.get_widget("install-local-box").set_sensitive(uselocal)
2009-03-09 23:16:45 +03:00
self.window.get_widget("install-local-browse").set_sensitive(uselocal)
def detect_visibility_changed(self, src, ignore=None):
is_visible = src.get_property("visible")
detect_chkbox = self.window.get_widget("install-detect-os")
nodetect_label = self.window.get_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_import(self, ignore1=None, ignore2=None):
def set_import_path(ignore, path):
self.window.get_widget("install-import-entry").set_text(path)
self._browse_file(set_import_path, is_media=False)
2009-03-09 23:16:45 +03:00
def browse_iso(self, ignore1=None, ignore2=None):
def set_iso_storage_path(ignore, path):
self.window.get_widget("install-local-box").child.set_text(path)
self._browse_file(set_iso_storage_path, is_media=True)
self.window.get_widget("install-local-box").activate()
2009-03-09 23:16:45 +03:00
def toggle_enable_storage(self, src):
self.window.get_widget("config-storage-box").set_sensitive(src.get_active())
def browse_storage(self, ignore1):
def set_disk_storage_path(ignore, path):
self.window.get_widget("config-storage-entry").set_text(path)
self._browse_file(set_disk_storage_path,
is_media=False)
2009-03-09 23:16:45 +03:00
def toggle_storage_select(self, src):
act = src.get_active()
self.window.get_widget("config-storage-browse-box").set_sensitive(act)
def toggle_macaddr(self, src):
self.window.get_widget("config-macaddr").set_sensitive(src.get_active())
# Navigation methods
def set_install_page(self):
instnotebook = self.window.get_widget("install-method-pages")
detectbox = self.window.get_widget("install-detect-os-box")
instpage = self.get_config_install_page()
# 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 back(self, src):
notebook = self.window.get_widget("create-pages")
curpage = notebook.get_current_page()
is_import = (self.get_config_install_page() == INSTALL_PAGE_IMPORT)
next_page = curpage - 1
2009-03-09 23:16:45 +03:00
if curpage == PAGE_INSTALL:
self.reset_guest_type()
elif curpage == PAGE_FINISH and is_import:
# Skip over storage page
next_page -= 1
2009-03-09 23:16:45 +03:00
notebook.set_current_page(next_page)
2009-03-09 23:16:45 +03:00
def forward(self, ignore=None):
2009-03-09 23:16:45 +03:00
notebook = self.window.get_widget("create-pages")
curpage = notebook.get_current_page()
is_import = (self.get_config_install_page() == INSTALL_PAGE_IMPORT)
2009-03-09 23:16:45 +03:00
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
2009-03-09 23:16:45 +03:00
if self.validate(notebook.get_current_page()) != 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 = curpage + 1
if next_page == PAGE_STORAGE and is_import:
# Skip storage page for import installs
next_page += 1
self.window.get_widget("create-forward").grab_focus()
notebook.set_current_page(next_page)
2009-03-09 23:16:45 +03:00
def page_changed(self, ignore1, ignore2, pagenum):
2009-03-09 23:16:45 +03:00
# Update page number
page_lbl = ("<span color='#59B0E2'>%s</span>" %
_("Step %(current_page)d of %(max_page)d") %
{'current_page': pagenum+1, 'max_page': PAGE_FINISH+1})
self.window.get_widget("config-pagenum").set_markup(page_lbl)
if pagenum == PAGE_NAME:
self.window.get_widget("create-back").set_sensitive(False)
2009-03-09 23:16:45 +03:00
else:
self.window.get_widget("create-back").set_sensitive(True)
2009-03-09 23:16:45 +03:00
if pagenum == PAGE_INSTALL:
self.detect_media_os()
if pagenum != PAGE_FINISH:
2009-03-09 23:16:45 +03:00
self.window.get_widget("create-forward").show()
self.window.get_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.window.get_widget("config-advanced-expander").show()
self.window.get_widget("create-forward").hide()
self.window.get_widget("create-finish").show()
self.window.get_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 build_guest(self, installer, name):
guest = installer.guest_from_installer()
guest.name = self.get_config_name()
# Generate UUID
try:
guest.uuid = virtinst.util.uuidToString(virtinst.util.randomUUID())
except Exception, e:
self.err.show_err(_("Error setting UUID: %s") % str(e),
"".join(traceback.format_exc()))
return None
# Set up graphics device
try:
guest.add_device(virtinst.VirtualGraphics(
type=virtinst.VirtualGraphics.TYPE_VNC,
conn=guest.conn))
guest.add_device(virtinst.VirtualVideoDevice(conn=guest.conn))
except Exception, e:
self.err.show_err(_("Error setting up graphics device:") + str(e),
"".join(traceback.format_exc()))
return None
# Set up sound device (if present)
guest.sound_devs = []
try:
if self.get_config_sound():
guest.sound_devs.append(virtinst.VirtualAudio(conn=guest.conn))
except Exception, e:
self.err.show_err(_("Error setting up sound device:") + str(e),
"".join(traceback.format_exc()))
return None
return guest
2009-03-09 23:16:45 +03:00
def validate(self, pagenum):
try:
if pagenum == PAGE_NAME:
return self.validate_name_page()
elif pagenum == PAGE_INSTALL:
return self.validate_install_page(revalidate=False)
2009-03-09 23:16:45 +03:00
elif pagenum == PAGE_MEM:
return self.validate_mem_page()
elif pagenum == PAGE_STORAGE:
return self.validate_storage_page(revalidate=False)
2009-03-09 23:16:45 +03:00
elif pagenum == PAGE_FINISH:
return self.validate_final_page()
2009-03-09 23:16:45 +03:00
except Exception, e:
self.err.show_err(_("Uncaught error validating install "
"parameters: %s") % str(e),
"".join(traceback.format_exc()))
return
def validate_name_page(self):
name = self.get_config_name()
try:
2009-03-09 23:16:45 +03:00
g = virtinst.Guest(connection=self.conn.vmm)
g.name = name
except Exception, e:
return self.verr(_("Invalid System Name"), str(e))
return True
def validate_install_page(self, revalidate=True):
2009-03-09 23:16:45 +03:00
instmethod = self.get_config_install_page()
installer = None
location = None
extra = None
ks = None
cdrom = False
is_import = False
2009-03-09 23:16:45 +03:00
distro, variant, ignore1, ignore2 = self.get_config_os_info()
if instmethod == INSTALL_PAGE_ISO:
instclass = virtinst.DistroInstaller
2009-03-09 23:16:45 +03:00
media = self.get_config_local_media()
if not media:
return self.verr(_("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.verr(_("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.verr(_("A storage path to import is required."))
2009-03-09 23:16:45 +03:00
# 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
2009-03-09 23:16:45 +03:00
except Exception, e:
return self.verr(_("Error setting installer parameters."), str(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
except Exception, e:
return self.verr(_("Error setting install media location."),
str(e))
# OS distro/variant validation
try:
if distro and distro != OS_GENERIC:
self.guest.os_type = distro
if variant and variant != OS_GENERIC:
self.guest.os_variant = variant
2008-08-25 23:03:51 +04:00
except ValueError, e:
2009-03-09 23:16:45 +03:00
return self.err.val_err(_("Error setting OS information."),
str(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(revalidate):
return False
if not revalidate:
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.config,
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)
2009-03-09 23:16:45 +03:00
return True
2009-03-09 23:16:45 +03:00
def validate_mem_page(self):
cpus = self.window.get_widget("config-cpus").get_value()
mem = self.window.get_widget("config-mem").get_value()
# VCPUS
try:
self.guest.vcpus = int(cpus)
except Exception, e:
return self.verr(_("Error setting CPUs."), str(e))
# Memory
try:
self.guest.memory = int(mem)
self.guest.maxmemory = int(mem)
except Exception, e:
return self.verr(_("Error setting guest memory."), str(e))
return True
def validate_storage_page(self, revalidate=True):
2009-03-09 23:16:45 +03:00
use_storage = self.window.get_widget("enable-storage").get_active()
instcd = self.get_config_install_page() == INSTALL_PAGE_ISO
2009-03-09 23:16:45 +03:00
# CD/ISO install and no disks implies LiveCD
if instcd:
self.guest.installer.livecd = not use_storage
if self.disk and self.disk in self.guest.get_devices("disk"):
self.guest.remove_device(self.disk)
self.disk = None
2009-03-09 23:16:45 +03:00
# 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
2009-03-09 23:16:45 +03:00
try:
# This can error out
diskpath, disksize, sparse = self.get_storage_info()
if self.is_default_storage() and not revalidate:
# 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.config,
self.guest.name)
do_exist = False
ret = True
try:
do_exist = virtinst.VirtualDisk.path_exists(
self.conn.vmm, ideal)
ret = virtinst.VirtualDisk.path_in_use_by(self.conn.vmm,
ideal)
except:
logging.exception("Error checking default path usage")
if do_exist and not ret:
do_use = self.err.yes_no(
_("The following path already exists, but is not\n"
"in use by any virtual machine:\n\n%s\n\n"
"Would you like to use this path?") % ideal)
if do_use:
diskpath = ideal
2009-03-09 23:16:45 +03:00
if not diskpath:
return self.verr(_("A storage path must be specified."))
disk = virtinst.VirtualDisk(conn = self.conn.vmm,
path = diskpath,
size = disksize,
sparse = sparse)
2009-03-09 23:16:45 +03:00
except Exception, e:
return self.verr(_("Storage parameter error."), str(e))
isfatal, errmsg = disk.is_size_conflict()
if not revalidate and not isfatal and errmsg:
2009-03-09 23:16:45 +03:00
# 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 revalidate 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 revalidate:
uihelpers.check_path_search_for_qemu(self.topwin, self.config,
self.conn, disk.path)
self.disk = disk
self.guest.add_device(self.disk)
return True
2009-03-09 23:16:45 +03:00
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
2009-03-09 23:16:45 +03:00
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.verr(_("Network device required for %s install.") %
methname)
nic = uihelpers.validate_network(self.topwin,
self.conn, nettype, devname, macaddr)
if nic == False:
return False
if self.nic and self.nic in self.guest.get_devices("interface"):
self.guest.remove_device(self.nic)
self.nic = nic
self.guest.add_device(self.nic)
2009-03-09 23:16:45 +03:00
return True
# Interesting methods
def build_installer(self, instclass):
installer = instclass(conn = self.conn.vmm,
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():
2009-03-09 23:16:45 +03:00
return
# FIXME: some things are dependent on domain type (vcpu max)
if instmeth == INSTALL_PAGE_URL:
2010-05-28 19:52:00 +04:00
self.change_caps(gtype = "xen")
else:
2010-05-28 19:52:00 +04:00
self.change_caps(gtype = "hvm")
2009-03-09 23:16:45 +03:00
def reset_guest_type(self):
self.change_caps()
def finish(self, src):
# Validate the final page
page = self.window.get_widget("create-pages").get_current_page()
if self.validate(page) != True:
return False
guest = self.guest
disk = len(guest.disks) and guest.disks[0]
2009-03-09 23:16:45 +03:00
logging.debug("Creating a VM %s" % guest.name +
"\n Type: %s,%s" % (guest.type,
guest.installer.os_type) +
"\n UUID: %s" % guest.uuid +
"\n Install Source: %s" % guest.location +
"\n OS: %s:%s" % (guest.os_type, guest.os_variant) +
"\n Kernel args: %s" % guest.extraargs +
"\n Memory: %s" % guest.memory +
"\n Max Memory: %s" % guest.maxmemory +
"\n # VCPUs: %s" % str(guest.vcpus) +
"\n Filesize: %s" % (disk and disk.size) or "None" +
"\n Disk image: %s" % (disk and disk.path) or "None" +
"\n Audio?: %s" % str(self.get_config_sound()))
# Start the install
self.failed_guest = None
self.topwin.set_sensitive(False)
self.topwin.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.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 _check_start_error(self, cb, *args, **kwargs):
try:
cb(*args, **kwargs)
except Exception, e:
self.topwin.set_sensitive(True)
self.topwin.window.set_cursor(
gtk.gdk.Cursor(gtk.gdk.TOP_LEFT_ARROW))
self.err.show_err(_("Error starting installation: ") + str(e),
"".join(traceback.format_exc()))
def customize(self, guest):
virtinst_guest = vmmDomainVirtinst(self.config, self.conn, guest,
self.guest.uuid)
if self.config_window:
self.config_window.disconnect(self.config_window_signal)
self.config_window.close()
del(self.config_window)
def start_install_wrapper(ignore, guest):
if not self.is_visible():
return
self._check_start_error(self.start_install, guest)
self.config_window = vmmDetails(self.config,
virtinst_guest,
self.engine,
self.topwin)
self.config_window_signal = self.config_window.connect(
"details-closed",
start_install_wrapper,
guest)
self.config_window.show()
def start_install(self, guest):
progWin = vmmAsyncJob(self.config, self.do_install, [guest],
title=_("Creating Virtual Machine"),
2009-03-09 23:16:45 +03:00
text=_("The virtual machine is now being "
"created. Allocation of disk storage "
"and retrieval of the installation "
"images may take a few minutes to "
"complete."))
progWin.run()
error, details = progWin.get_error()
if error != None:
self.err.show_err(error, details)
self.topwin.set_sensitive(True)
self.topwin.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.TOP_LEFT_ARROW))
if error:
self.failed_guest = self.guest
return
vm = self.conn.get_vm(guest.uuid)
if self.config.get_console_popup() == 1:
# user has requested console on new created vms only
gtype = vm.get_graphics_console()[0]
if gtype == "vnc":
2009-03-09 23:16:45 +03:00
self.emit("action-show-console", self.conn.get_uri(),
guest.uuid)
else:
2009-03-09 23:16:45 +03:00
self.emit("action-show-terminal", self.conn.get_uri(),
guest.uuid)
self.close()
2009-03-09 23:16:45 +03:00
def do_install(self, guest, asyncjob):
meter = vmmCreateMeter(asyncjob)
error = None
details = None
try:
logging.debug("Starting background install process")
2009-03-09 23:16:45 +03:00
guest.conn = util.dup_conn(self.config, self.conn)
for dev in guest.get_all_devices():
dev.conn = guest.conn
dom = guest.start_install(False, meter = meter)
if dom == None:
error = _("Guest installation failed to complete")
details = error
logging.error("Guest install did not return a domain")
else:
logging.debug("Install completed")
# Make sure we pick up the domain object
self.conn.tick(noStatsUpdate=True)
vm = self.conn.get_vm(guest.uuid)
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()
else:
# Register a status listener, which will restart the
# guest after the install has finished
util.connect_opt_out(vm, "status-changed",
self.check_install_status, guest)
except:
(_type, value, stacktrace) = sys.exc_info ()
# Detailed error message, in English so it can be Googled.
2009-03-09 23:16:45 +03:00
details = ("Unable to complete install '%s'" %
(str(_type) + " " + str(value) + "\n" +
traceback.format_exc (stacktrace)))
error = (_("Unable to complete install: '%s'") % str(value))
if error:
asyncjob.set_error(error, details)
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()
util.connect_opt_out(vm, "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),
"".join(traceback.format_exc()))
return True
2009-03-09 23:16:45 +03:00
def pretty_storage(self, size):
return "%.1f Gb" % float(size)
2009-03-09 23:16:45 +03:00
def pretty_memory(self, mem):
return "%d MB" % (mem/1024.0)
# Distro detection methods
# Create and launch a detection thread (if no detection already running)
def start_detect_thread(self, forward):
if not self.detectThreadEvent.isSet():
2009-03-09 23:16:45 +03:00
# We are already checking (some) media, so let that continue
return
self.detectThreadEvent.clear()
detectThread = threading.Thread(target=self.do_detect,
args=(forward,),
name="Detect OS")
detectThread.setDaemon(True)
detectThread.start()
2009-03-09 23:16:45 +03:00
def set_distro_labels(self, distro, ver):
# Helper to set auto detect result labels
if not self.is_detect_active():
return
2009-03-09 23:16:45 +03:00
self.window.get_widget("install-os-type-label").set_text(distro)
self.window.get_widget("install-os-version-label").set_text(ver)
2009-03-09 23:16:45 +03:00
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()
idx = 0
2009-03-09 23:16:45 +03:00
for idx in range(0, len(model)):
row = model[idx]
if value and row[0] == value:
2009-03-09 23:16:45 +03:00
break
2007-03-21 19:28:36 +03:00
2009-03-09 23:16:45 +03:00
if idx == len(os_widget.get_model()) - 1:
idx = -1
2009-03-09 23:16:45 +03:00
os_widget.set_active(idx)
if idx == -1:
os_widget.set_active(0)
2009-03-09 23:16:45 +03:00
if idx >= 0:
return row[1]
return _("Unknown")
2009-03-09 23:16:45 +03:00
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
2009-03-09 23:16:45 +03:00
dl = self.set_os_val(self.window.get_widget("install-os-type"),
distro)
vl = self.set_os_val(self.window.get_widget("install-os-version"),
ver)
self.set_distro_labels(dl, vl)
2009-03-09 23:16:45 +03:00
def _safe_wrapper(self, func, args):
gtk.gdk.threads_enter()
try:
return func(*args)
finally:
gtk.gdk.threads_leave()
2009-03-09 23:16:45 +03:00
def _set_forward_sensitive(self, val):
self.window.get_widget("create-forward").set_sensitive(val)
2009-03-09 23:16:45 +03:00
# The actual detection routine
def do_detect(self, forward):
2009-03-09 23:16:45 +03:00
try:
media = self._safe_wrapper(self.get_config_detectable_media, ())
if not media:
return
2009-03-09 23:16:45 +03:00
self.detectedDistro = None
2009-03-09 23:16:45 +03:00
logging.debug("Starting OS detection thread for media=%s" % media)
self._safe_wrapper(self._set_forward_sensitive, (False,))
2009-03-09 23:16:45 +03:00
detectThread = threading.Thread(target=self.actually_detect,
name="Actual media detection",
args=(media,))
detectThread.setDaemon(True)
detectThread.start()
2009-03-09 23:16:45 +03:00
base = _("Detecting")
for i in range(1, DETECT_TIMEOUT * 2):
if self.detectedDistro != None:
break
detect_str = base + ("." * (((i + 2) % 3) + 1))
self._safe_wrapper(self.set_distro_labels,
(detect_str, detect_str))
time.sleep(.5)
2009-03-09 23:16:45 +03:00
results = self.detectedDistro
if results == None:
results = (None, None)
2009-03-09 23:16:45 +03:00
self._safe_wrapper(self.set_distro_selection, results)
finally:
self._safe_wrapper(self._set_forward_sensitive, (True,))
self.detectThreadEvent.set()
self.mediaDetected = True
2009-03-09 23:16:45 +03:00
logging.debug("Leaving OS detection thread.")
if forward:
util.safe_idle_add(self.forward, ())
2009-03-09 23:16:45 +03:00
return
2009-03-09 23:16:45 +03:00
def actually_detect(self, media):
try:
installer = self.build_installer(virtinst.DistroInstaller)
installer.location = media
2009-03-09 23:16:45 +03:00
self.detectedDistro = installer.detect_distro()
except:
logging.exception("Error detecting distro.")
self.detectedDistro = (None, None)
def _browse_file(self, callback, is_media=False):
if is_media:
reason = self.config.CONFIG_DIR_MEDIA
else:
reason = self.config.CONFIG_DIR_IMAGE
if self.storage_browser == None:
self.storage_browser = vmmStorageBrowser(self.config, self.conn)
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.conn)
2009-03-09 23:16:45 +03:00
def show_help(self, ignore):
# No help available yet.
pass
2009-03-09 23:16:45 +03:00
def verr(self, msg, extra=None):
return self.err.val_err(msg, extra)
gobject.type_register(vmmCreate)