2015-01-28 00:04:18 +08:00
|
|
|
# Copyright (C) 2008, 2013, 2014, 2015 Red Hat, Inc.
|
2009-03-10 04:16:45 +08:00
|
|
|
# Copyright (C) 2008 Cole Robinson <crobinso@redhat.com>
|
2006-08-09 23:40:34 +08:00
|
|
|
#
|
2018-04-04 21:35:41 +08:00
|
|
|
# This work is licensed under the GNU GPLv2 or later.
|
2018-03-21 03:00:02 +08:00
|
|
|
# See the COPYING file in the top-level directory.
|
2006-08-09 23:40:34 +08:00
|
|
|
|
2017-10-11 19:35:50 +08:00
|
|
|
import io
|
2017-07-06 00:51:18 +08:00
|
|
|
import pkgutil
|
2017-07-06 00:51:19 +08:00
|
|
|
import os
|
2013-07-07 08:03:42 +08:00
|
|
|
import threading
|
|
|
|
import time
|
2006-08-09 23:40:34 +08:00
|
|
|
|
2018-03-15 17:53:58 +08:00
|
|
|
from gi.repository import Gtk
|
2015-04-12 00:57:32 +08:00
|
|
|
from gi.repository import Pango
|
2011-04-29 04:17:44 +08:00
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
import virtinst
|
2019-06-08 06:16:53 +08:00
|
|
|
import virtinst.generatename
|
2019-06-17 09:12:39 +08:00
|
|
|
from virtinst import log
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2019-06-17 10:19:17 +08:00
|
|
|
from .lib import uiutil
|
2014-09-13 04:10:45 +08:00
|
|
|
from .asyncjob import vmmAsyncJob
|
2018-03-15 01:13:22 +08:00
|
|
|
from .baseclass import vmmGObjectUI
|
2019-05-06 04:25:35 +08:00
|
|
|
from .connmanager import vmmConnectionManager
|
2019-06-17 09:45:19 +08:00
|
|
|
from .device.addstorage import vmmAddStorage
|
|
|
|
from .device.mediacombo import vmmMediaCombo
|
|
|
|
from .device.netlist import vmmNetworkList
|
2018-03-15 06:58:22 +08:00
|
|
|
from .engine import vmmEngine
|
2019-06-17 09:40:46 +08:00
|
|
|
from .object.domain import vmmDomainVirtinst
|
2018-05-01 19:51:23 +08:00
|
|
|
from .oslist import vmmOSList
|
2018-09-30 04:04:05 +08:00
|
|
|
from .storagebrowse import vmmStorageBrowser
|
2019-05-06 04:25:35 +08:00
|
|
|
from .vmwindow import vmmVMWindow
|
2006-08-17 04:00:28 +08:00
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
# Number of seconds to wait for media detection
|
|
|
|
DETECT_TIMEOUT = 20
|
2006-08-10 06:53:30 +08:00
|
|
|
|
2011-04-28 22:39:12 +08:00
|
|
|
DEFAULT_MEM = 1024
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
(PAGE_NAME,
|
|
|
|
PAGE_INSTALL,
|
|
|
|
PAGE_MEM,
|
|
|
|
PAGE_STORAGE,
|
|
|
|
PAGE_FINISH) = range(5)
|
2008-02-24 04:26:26 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
(INSTALL_PAGE_ISO,
|
|
|
|
INSTALL_PAGE_URL,
|
2020-01-26 22:52:18 +08:00
|
|
|
INSTALL_PAGE_MANUAL,
|
2020-01-30 01:15:32 +08:00
|
|
|
INSTALL_PAGE_IMPORT,
|
2015-09-13 01:03:51 +08:00
|
|
|
INSTALL_PAGE_CONTAINER_APP,
|
2017-03-13 20:01:51 +08:00
|
|
|
INSTALL_PAGE_CONTAINER_OS,
|
|
|
|
INSTALL_PAGE_VZ_TEMPLATE) = range(7)
|
2009-11-21 00:39:22 +08:00
|
|
|
|
2015-09-13 03:14:40 +08:00
|
|
|
# Column numbers for os type/version list models
|
|
|
|
(OS_COL_ID,
|
|
|
|
OS_COL_LABEL,
|
|
|
|
OS_COL_IS_SEP,
|
|
|
|
OS_COL_IS_SHOW_ALL) = range(4)
|
|
|
|
|
2012-02-03 00:32:29 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
#####################
|
|
|
|
# Pretty UI helpers #
|
|
|
|
#####################
|
|
|
|
|
|
|
|
def _pretty_arch(_a):
|
2013-10-03 01:19:40 +08:00
|
|
|
if _a == "armv7l":
|
|
|
|
return "arm"
|
|
|
|
return _a
|
|
|
|
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _pretty_storage(size):
|
2016-07-26 15:32:14 +08:00
|
|
|
return _("%.1f GiB") % float(size)
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
def _pretty_memory(mem):
|
2016-07-26 15:32:14 +08:00
|
|
|
return _("%d MiB") % (mem / 1024.0)
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
|
2015-09-15 04:05:58 +08:00
|
|
|
###########################################################
|
|
|
|
# Helpers for tracking devices we create from this wizard #
|
|
|
|
###########################################################
|
|
|
|
|
2022-01-18 04:12:42 +08:00
|
|
|
def is_virt_bootstrap_installed(conn):
|
|
|
|
ret = pkgutil.find_loader('virtBootstrap') is not None
|
|
|
|
return ret or conn.config.CLITestOptions.fake_virtbootstrap
|
2015-09-15 04:05:58 +08:00
|
|
|
|
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
class _GuestData:
|
|
|
|
"""
|
|
|
|
Wrapper to hold all data that will go into the Guest object,
|
|
|
|
so we can rebuild it as needed.
|
|
|
|
"""
|
|
|
|
def __init__(self, conn, capsinfo):
|
|
|
|
self.conn = conn
|
|
|
|
self.capsinfo = capsinfo
|
|
|
|
self.failed_guest = None
|
|
|
|
|
|
|
|
self.default_graphics_type = None
|
|
|
|
self.skip_default_sound = None
|
|
|
|
self.x86_cpu_default = None
|
|
|
|
|
|
|
|
self.disk = None
|
|
|
|
self.filesystem = None
|
|
|
|
self.interface = None
|
|
|
|
self.init = None
|
|
|
|
|
|
|
|
self.machine = None
|
|
|
|
self.os_variant = None
|
2022-01-27 00:17:41 +08:00
|
|
|
self.uefi_requested = None
|
2020-01-30 00:25:12 +08:00
|
|
|
self.name = None
|
|
|
|
|
|
|
|
self.vcpus = None
|
|
|
|
self.memory = None
|
|
|
|
self.currentMemory = None
|
|
|
|
|
|
|
|
self.location = None
|
|
|
|
self.cdrom = None
|
|
|
|
self.extra_args = None
|
|
|
|
self.livecd = False
|
|
|
|
|
|
|
|
def build_installer(self):
|
|
|
|
kwargs = {}
|
|
|
|
if self.location:
|
|
|
|
kwargs["location"] = self.location
|
|
|
|
if self.cdrom:
|
|
|
|
kwargs["cdrom"] = self.cdrom
|
|
|
|
|
|
|
|
installer = virtinst.Installer(self.conn, **kwargs)
|
|
|
|
if self.extra_args:
|
|
|
|
installer.set_extra_args([self.extra_args])
|
|
|
|
if self.livecd:
|
|
|
|
installer.livecd = True
|
|
|
|
return installer
|
|
|
|
|
|
|
|
def build_guest(self):
|
|
|
|
guest = virtinst.Guest(self.conn)
|
|
|
|
guest.set_capabilities_defaults(self.capsinfo)
|
|
|
|
|
|
|
|
if self.machine:
|
|
|
|
# If no machine was explicitly selected, we don't overwrite
|
|
|
|
# it, because we want to
|
|
|
|
guest.os.machine = self.machine
|
|
|
|
if self.os_variant:
|
|
|
|
guest.set_os_name(self.os_variant)
|
2022-01-27 00:17:41 +08:00
|
|
|
if self.uefi_requested:
|
|
|
|
guest.uefi_requested = self.uefi_requested
|
2020-01-30 00:25:12 +08:00
|
|
|
|
|
|
|
if self.filesystem:
|
|
|
|
guest.add_device(self.filesystem)
|
|
|
|
if self.disk:
|
|
|
|
guest.add_device(self.disk)
|
|
|
|
if self.interface:
|
|
|
|
guest.add_device(self.interface)
|
|
|
|
|
|
|
|
if self.init:
|
|
|
|
guest.os.init = self.init
|
|
|
|
if self.name:
|
|
|
|
guest.name = self.name
|
|
|
|
if self.vcpus:
|
|
|
|
guest.vcpus = self.vcpus
|
|
|
|
if self.currentMemory:
|
|
|
|
guest.currentMemory = self.currentMemory
|
|
|
|
if self.memory:
|
|
|
|
guest.memory = self.memory
|
2015-09-15 04:05:58 +08:00
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
return guest
|
2017-07-06 00:51:18 +08:00
|
|
|
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
##############
|
|
|
|
# Main class #
|
|
|
|
##############
|
|
|
|
|
2019-06-17 10:00:57 +08:00
|
|
|
class vmmCreateVM(vmmGObjectUI):
|
2018-03-15 17:53:58 +08:00
|
|
|
@classmethod
|
|
|
|
def show_instance(cls, parentobj, uri=None):
|
|
|
|
try:
|
|
|
|
if not cls._instance:
|
2019-06-17 10:00:57 +08:00
|
|
|
cls._instance = vmmCreateVM()
|
2018-03-17 06:58:11 +08:00
|
|
|
cls._instance.show(parentobj and parentobj.topwin or None, uri=uri)
|
2020-02-06 03:58:51 +08:00
|
|
|
except Exception as e: # pragma: no cover
|
2018-03-17 06:58:11 +08:00
|
|
|
if not parentobj:
|
|
|
|
raise
|
2018-03-15 17:53:58 +08:00
|
|
|
parentobj.err.show_err(
|
|
|
|
_("Error launching create dialog: %s") % str(e))
|
2012-05-14 21:24:56 +08:00
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
def __init__(self):
|
2019-06-17 10:00:57 +08:00
|
|
|
vmmGObjectUI.__init__(self, "createvm.ui", "vmm-create")
|
2018-03-15 19:43:56 +08:00
|
|
|
self._cleanup_on_app_close()
|
2010-12-01 03:33:21 +08:00
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
self.conn = None
|
2015-09-14 00:45:35 +08:00
|
|
|
self._capsinfo = None
|
2010-12-08 05:48:13 +08:00
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata = None
|
2010-12-08 05:48:13 +08:00
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
# Distro detection state variables
|
2015-09-13 03:14:40 +08:00
|
|
|
self._detect_os_in_progress = False
|
|
|
|
self._os_already_detected_for_media = False
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
self._customize_window = None
|
2010-02-08 01:18:28 +08:00
|
|
|
|
2015-09-14 00:45:35 +08:00
|
|
|
self._storage_browser = None
|
|
|
|
self._netlist = None
|
2014-01-28 05:58:45 +08:00
|
|
|
|
2015-09-14 00:45:35 +08:00
|
|
|
self._addstorage = vmmAddStorage(self.conn, self.builder, self.topwin)
|
2015-09-14 06:01:39 +08:00
|
|
|
self.widget("storage-align").add(self._addstorage.top_box)
|
2015-09-13 01:03:51 +08:00
|
|
|
def _browse_file_cb(ignore, widget):
|
|
|
|
self._browse_file(widget)
|
2015-09-14 00:45:35 +08:00
|
|
|
self._addstorage.connect("browse-clicked", _browse_file_cb)
|
2014-01-29 05:53:11 +08:00
|
|
|
|
2018-10-07 02:26:31 +08:00
|
|
|
self._mediacombo = vmmMediaCombo(self.conn, self.builder, self.topwin)
|
|
|
|
self._mediacombo.connect("changed", self._iso_changed_cb)
|
|
|
|
self._mediacombo.connect("activate", self._iso_activated_cb)
|
|
|
|
self._mediacombo.set_mnemonic_label(
|
|
|
|
self.widget("install-iso-label"))
|
|
|
|
self.widget("install-iso-align").add(self._mediacombo.top_box)
|
|
|
|
|
2013-02-17 02:31:46 +08:00
|
|
|
self.builder.connect_signals({
|
2017-08-05 14:39:32 +08:00
|
|
|
"on_vmm_newcreate_delete_event": self._close_requested,
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-07 02:42:55 +08:00
|
|
|
"on_create_cancel_clicked": self._close_requested,
|
2017-08-05 14:39:32 +08:00
|
|
|
"on_create_back_clicked": self._back_clicked,
|
|
|
|
"on_create_forward_clicked": self._forward_clicked,
|
|
|
|
"on_create_finish_clicked": self._finish_clicked,
|
2015-09-13 01:03:51 +08:00
|
|
|
"on_create_pages_switch_page": self._page_changed,
|
|
|
|
|
|
|
|
"on_create_conn_changed": self._conn_changed,
|
|
|
|
"on_method_changed": self._method_changed,
|
2015-09-15 06:31:56 +08:00
|
|
|
"on_xen_type_changed": self._xen_type_changed,
|
2015-09-14 06:01:39 +08:00
|
|
|
"on_arch_changed": self._arch_changed,
|
2015-09-15 06:31:56 +08:00
|
|
|
"on_virt_type_changed": self._virt_type_changed,
|
|
|
|
"on_machine_changed": self._machine_changed,
|
2017-03-13 20:01:51 +08:00
|
|
|
"on_vz_virt_type_changed": self._vz_virt_type_changed,
|
2015-09-13 01:03:51 +08:00
|
|
|
|
2015-09-13 03:14:40 +08:00
|
|
|
"on_install_iso_browse_clicked": self._browse_iso,
|
|
|
|
"on_install_url_entry_changed": self._url_changed,
|
|
|
|
"on_install_url_entry_activate": self._url_activated,
|
2015-09-13 01:03:51 +08:00
|
|
|
"on_install_import_browse_clicked": self._browse_import,
|
|
|
|
"on_install_app_browse_clicked": self._browse_app,
|
|
|
|
"on_install_oscontainer_browse_clicked": self._browse_oscontainer,
|
2017-07-06 00:51:18 +08:00
|
|
|
"on_install_container_source_toggle": self._container_source_toggle,
|
2015-09-13 01:03:51 +08:00
|
|
|
|
2018-09-30 04:04:05 +08:00
|
|
|
"on_install_detect_os_toggled": self._detect_os_toggled_cb,
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
"on_enable_storage_toggled": self._toggle_enable_storage,
|
2015-09-15 04:22:17 +08:00
|
|
|
|
|
|
|
"on_create_vm_name_changed": self._name_changed,
|
2009-03-10 04:16:45 +08:00
|
|
|
})
|
2011-04-18 23:25:28 +08:00
|
|
|
self.bind_escape_key_close()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
self._init_state()
|
|
|
|
|
|
|
|
|
2018-03-15 19:43:56 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
###########################
|
|
|
|
# Standard window methods #
|
|
|
|
###########################
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2018-03-15 19:43:56 +08:00
|
|
|
def show(self, parent, uri):
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Showing new vm wizard")
|
2011-04-14 20:47:42 +08:00
|
|
|
|
2012-02-14 05:19:34 +08:00
|
|
|
if not self.is_visible():
|
2015-09-13 01:03:51 +08:00
|
|
|
self._reset_state(uri)
|
2012-02-14 05:19:34 +08:00
|
|
|
self.topwin.set_transient_for(parent)
|
2018-03-15 07:06:30 +08:00
|
|
|
vmmEngine.get_instance().increment_window_counter()
|
2012-02-14 05:19:34 +08:00
|
|
|
|
2006-09-13 05:49:29 +08:00
|
|
|
self.topwin.present()
|
2006-08-09 23:40:34 +08:00
|
|
|
|
2015-09-07 02:42:55 +08:00
|
|
|
def _close(self, ignore1=None, ignore2=None):
|
2014-02-06 03:25:01 +08:00
|
|
|
if self.is_visible():
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Closing new vm wizard")
|
2018-03-15 07:06:30 +08:00
|
|
|
vmmEngine.get_instance().decrement_window_counter()
|
2016-05-20 21:27:17 +08:00
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
self.topwin.hide()
|
2009-09-22 04:09:51 +08:00
|
|
|
|
2015-11-22 08:25:02 +08:00
|
|
|
self._cleanup_customize_window()
|
2015-09-14 00:45:35 +08:00
|
|
|
if self._storage_browser:
|
|
|
|
self._storage_browser.close()
|
2018-03-15 19:43:56 +08:00
|
|
|
self._set_conn(None)
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata = None
|
2010-02-08 01:18:28 +08:00
|
|
|
|
2011-07-24 09:16:54 +08:00
|
|
|
def _cleanup(self):
|
2015-09-14 00:45:35 +08:00
|
|
|
if self._storage_browser:
|
|
|
|
self._storage_browser.cleanup()
|
|
|
|
self._storage_browser = None
|
2020-08-29 08:30:03 +08:00
|
|
|
if self._netlist: # pragma: no cover
|
2015-09-14 00:45:35 +08:00
|
|
|
self._netlist.cleanup()
|
|
|
|
self._netlist = None
|
|
|
|
if self._mediacombo:
|
|
|
|
self._mediacombo.cleanup()
|
|
|
|
self._mediacombo = None
|
|
|
|
if self._addstorage:
|
|
|
|
self._addstorage.cleanup()
|
|
|
|
self._addstorage = None
|
2014-01-29 02:51:59 +08:00
|
|
|
|
2018-03-15 19:43:56 +08:00
|
|
|
self.conn = None
|
|
|
|
self._capsinfo = None
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata = None
|
2018-03-15 19:43:56 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
##########################
|
|
|
|
# Initial state handling #
|
|
|
|
##########################
|
|
|
|
|
|
|
|
def _show_startup_error(self, error, hideinstall=True):
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("startup-error-box").show()
|
|
|
|
self.widget("create-forward").set_sensitive(False)
|
2012-02-09 22:04:09 +08:00
|
|
|
if hideinstall:
|
|
|
|
self.widget("install-box").hide()
|
2013-10-05 22:31:02 +08:00
|
|
|
self.widget("arch-expander").hide()
|
2009-09-30 02:00:50 +08:00
|
|
|
|
2020-07-14 15:41:59 +08:00
|
|
|
self.widget("startup-error").set_text(_("Error: %s") % error)
|
2009-03-10 04:16:45 +08:00
|
|
|
return False
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _show_startup_warning(self, error):
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("startup-error-box").show()
|
2015-09-24 04:46:33 +08:00
|
|
|
self.widget("startup-error").set_markup(
|
2020-07-14 15:41:59 +08:00
|
|
|
_("<span size='small'>Warning: %s</span>") % error)
|
2015-09-24 04:46:33 +08:00
|
|
|
|
|
|
|
def _show_arch_warning(self, error):
|
|
|
|
self.widget("arch-warning-box").show()
|
|
|
|
self.widget("arch-warning").set_markup(
|
2020-07-14 15:41:59 +08:00
|
|
|
_("<span size='small'>Warning: %s</span>") % error)
|
2010-02-11 09:26:40 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
def _init_state(self):
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("create-pages").set_show_tabs(False)
|
|
|
|
self.widget("install-method-pages").set_show_tabs(False)
|
2006-08-09 23:40:34 +08:00
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
# Connection list
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("create-conn-label").set_text("")
|
|
|
|
self.widget("startup-error").set_text("")
|
|
|
|
conn_list = self.widget("create-conn")
|
2012-05-14 21:24:56 +08:00
|
|
|
conn_model = Gtk.ListStore(str, str)
|
2009-03-10 04:16:45 +08:00
|
|
|
conn_list.set_model(conn_model)
|
2015-04-12 00:57:32 +08:00
|
|
|
text = uiutil.init_combo_text_column(conn_list, 1)
|
|
|
|
text.set_property("ellipsize", Pango.EllipsizeMode.MIDDLE)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2017-07-06 00:51:21 +08:00
|
|
|
def set_model_list(widget_id):
|
|
|
|
lst = self.widget(widget_id)
|
|
|
|
model = Gtk.ListStore(str)
|
|
|
|
lst.set_model(model)
|
|
|
|
lst.set_entry_text_column(0)
|
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
# Lists for the install urls
|
2017-07-06 00:51:21 +08:00
|
|
|
set_model_list("install-url-combo")
|
|
|
|
|
|
|
|
# Lists for OS container bootstrap
|
|
|
|
set_model_list("install-oscontainer-source-url-combo")
|
2006-10-11 21:07:45 +08:00
|
|
|
|
2018-05-22 03:42:50 +08:00
|
|
|
# Architecture
|
2015-09-14 06:01:39 +08:00
|
|
|
archList = self.widget("arch")
|
2015-09-15 06:31:56 +08:00
|
|
|
# [label, guest.os.arch value]
|
2014-01-27 08:18:22 +08:00
|
|
|
archModel = Gtk.ListStore(str, str)
|
2008-03-10 06:18:33 +08:00
|
|
|
archList.set_model(archModel)
|
2015-09-15 06:31:56 +08:00
|
|
|
uiutil.init_combo_text_column(archList, 0)
|
2013-10-03 01:10:11 +08:00
|
|
|
archList.set_row_separator_func(
|
|
|
|
lambda m, i, ignore: m[i][0] is None, None)
|
2007-02-20 12:11:21 +08:00
|
|
|
|
2015-09-15 06:31:56 +08:00
|
|
|
# guest.os.type value for xen (hvm vs. xen)
|
|
|
|
hyperList = self.widget("xen-type")
|
|
|
|
# [label, guest.os_type value]
|
2014-01-27 08:18:22 +08:00
|
|
|
hyperModel = Gtk.ListStore(str, str)
|
2008-03-10 06:18:33 +08:00
|
|
|
hyperList.set_model(hyperModel)
|
2015-04-11 01:04:02 +08:00
|
|
|
uiutil.init_combo_text_column(hyperList, 0)
|
2007-02-20 12:11:21 +08:00
|
|
|
|
2015-09-15 06:31:56 +08:00
|
|
|
# guest.os.machine value
|
2015-09-14 06:01:39 +08:00
|
|
|
lst = self.widget("machine")
|
2015-09-15 06:31:56 +08:00
|
|
|
# [machine ID]
|
2014-01-27 08:18:22 +08:00
|
|
|
model = Gtk.ListStore(str)
|
2013-10-02 05:40:44 +08:00
|
|
|
lst.set_model(model)
|
2015-04-11 01:04:02 +08:00
|
|
|
uiutil.init_combo_text_column(lst, 0)
|
2013-10-03 01:10:11 +08:00
|
|
|
lst.set_row_separator_func(lambda m, i, ignore: m[i][0] is None, None)
|
2013-10-02 05:40:44 +08:00
|
|
|
|
2015-09-15 06:31:56 +08:00
|
|
|
# guest.type value for xen (qemu vs kvm)
|
|
|
|
lst = self.widget("virt-type")
|
|
|
|
# [label, guest.type value]
|
|
|
|
model = Gtk.ListStore(str, str)
|
|
|
|
lst.set_model(model)
|
|
|
|
uiutil.init_combo_text_column(lst, 0)
|
|
|
|
|
2018-09-30 04:04:05 +08:00
|
|
|
# OS distro list
|
2018-05-01 19:51:23 +08:00
|
|
|
self._os_list = vmmOSList()
|
2018-09-30 04:04:05 +08:00
|
|
|
self.widget("install-os-align").add(self._os_list.search_entry)
|
|
|
|
self.widget("os-label").set_mnemonic_widget(self._os_list.search_entry)
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
def _reset_state(self, urihint=None):
|
|
|
|
"""
|
|
|
|
Reset all UI state to default values. Conn specific state is
|
2015-11-03 03:08:09 +08:00
|
|
|
populated in _populate_conn_state
|
2015-09-13 01:03:51 +08:00
|
|
|
"""
|
2017-04-28 03:00:17 +08:00
|
|
|
self.reset_finish_cursor()
|
2010-12-08 05:48:13 +08:00
|
|
|
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("create-pages").set_current_page(PAGE_NAME)
|
2015-09-13 01:03:51 +08:00
|
|
|
self._page_changed(None, None, PAGE_NAME)
|
2006-11-07 00:36:55 +08:00
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
# Name page state
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("create-vm-name").set_text("")
|
|
|
|
self.widget("method-local").set_active(True)
|
|
|
|
self.widget("create-conn").set_active(-1)
|
2015-09-13 01:03:51 +08:00
|
|
|
activeconn = self._populate_conn_list(urihint)
|
2013-10-02 03:18:34 +08:00
|
|
|
self.widget("arch-expander").set_expanded(False)
|
2017-03-13 20:01:51 +08:00
|
|
|
self.widget("vz-virt-type-hvm").set_active(True)
|
2010-02-11 09:26:40 +08:00
|
|
|
|
2015-11-03 03:08:09 +08:00
|
|
|
if self._set_conn(activeconn) is False:
|
|
|
|
return False
|
2010-02-11 09:26:40 +08:00
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
# Everything from this point forward should be connection independent
|
|
|
|
|
|
|
|
# Distro/Variant
|
2018-09-30 04:04:05 +08:00
|
|
|
self._os_list.reset_state()
|
|
|
|
self._os_already_detected_for_media = False
|
2007-04-24 03:08:56 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _populate_media_model(media_model, urls):
|
|
|
|
media_model.clear()
|
2020-08-29 08:30:03 +08:00
|
|
|
for url in (urls or []):
|
2015-09-13 01:03:51 +08:00
|
|
|
media_model.append([url])
|
|
|
|
|
2018-10-07 02:26:31 +08:00
|
|
|
# Install local
|
|
|
|
self._mediacombo.reset_state()
|
2007-07-10 09:13:56 +08:00
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
# Install URL
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("install-urlopts-entry").set_text("")
|
2015-09-13 03:14:40 +08:00
|
|
|
self.widget("install-url-entry").set_text("")
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("install-url-options").set_expanded(False)
|
2015-09-13 03:14:40 +08:00
|
|
|
urlmodel = self.widget("install-url-combo").get_model()
|
2015-09-13 01:03:51 +08:00
|
|
|
_populate_media_model(urlmodel, self.config.get_media_urls())
|
2007-07-15 02:43:52 +08:00
|
|
|
|
2010-03-23 06:15:18 +08:00
|
|
|
# Install import
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("install-import-entry").set_text("")
|
2010-03-23 06:15:18 +08:00
|
|
|
|
2011-06-08 05:42:50 +08:00
|
|
|
# Install container app
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("install-app-entry").set_text("/bin/sh")
|
2011-06-08 05:42:50 +08:00
|
|
|
|
2011-06-21 23:04:22 +08:00
|
|
|
# Install container OS
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("install-oscontainer-fs").set_text("")
|
2017-07-06 00:51:18 +08:00
|
|
|
self.widget("install-oscontainer-source-url-entry").set_text("")
|
|
|
|
self.widget("install-oscontainer-source-user").set_text("")
|
|
|
|
self.widget("install-oscontainer-source-passwd").set_text("")
|
|
|
|
self.widget("install-oscontainer-source-insecure").set_active(False)
|
|
|
|
self.widget("install-oscontainer-bootstrap").set_active(False)
|
|
|
|
self.widget("install-oscontainer-auth-options").set_expanded(False)
|
2017-12-20 00:32:18 +08:00
|
|
|
self.widget("install-oscontainer-rootpw").set_text("")
|
2017-07-06 00:51:21 +08:00
|
|
|
src_model = (self.widget("install-oscontainer-source-url-combo")
|
|
|
|
.get_model())
|
|
|
|
_populate_media_model(src_model, self.config.get_container_urls())
|
2011-06-21 23:04:22 +08:00
|
|
|
|
2017-03-13 20:01:51 +08:00
|
|
|
# Install VZ container from template
|
|
|
|
self.widget("install-container-template").set_text("centos-7-x86_64")
|
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
# Storage
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("enable-storage").set_active(True)
|
2015-09-14 00:45:35 +08:00
|
|
|
self._addstorage.reset_state()
|
2015-09-14 06:01:39 +08:00
|
|
|
self._addstorage.widget("storage-create").set_active(True)
|
|
|
|
self._addstorage.widget("storage-entry").set_text("")
|
2014-01-15 05:03:58 +08:00
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
# Final page
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("summary-customize").set_active(False)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
def _set_caps_state(self):
|
|
|
|
"""
|
|
|
|
Set state that is dependent on when capsinfo changes
|
|
|
|
"""
|
2015-09-24 04:46:33 +08:00
|
|
|
self.widget("arch-warning-box").hide()
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata = self._build_guestdata()
|
|
|
|
guest = self._gdata.build_guest()
|
2013-10-02 23:56:51 +08:00
|
|
|
|
2012-02-09 22:50:54 +08:00
|
|
|
# Helper state
|
2009-03-10 04:16:45 +08:00
|
|
|
is_local = not self.conn.is_remote()
|
2020-01-25 01:09:23 +08:00
|
|
|
is_storage_capable = self.conn.support.conn_storage()
|
2012-02-09 22:50:54 +08:00
|
|
|
can_storage = (is_local or is_storage_capable)
|
2018-09-13 01:43:56 +08:00
|
|
|
is_pv = guest.os.is_xenpv()
|
2020-08-23 01:22:51 +08:00
|
|
|
is_container_only = self.conn.is_container_only()
|
2017-03-13 20:01:51 +08:00
|
|
|
is_vz = self.conn.is_vz()
|
2018-09-13 01:43:56 +08:00
|
|
|
is_vz_container = is_vz and guest.os.is_container()
|
2013-10-06 22:08:04 +08:00
|
|
|
can_remote_url = self.conn.get_backend().support_remote_url_install()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2018-09-13 01:43:56 +08:00
|
|
|
installable_arch = bool(guest.os.is_x86() or
|
|
|
|
guest.os.is_ppc64() or
|
|
|
|
guest.os.is_s390x())
|
2013-10-02 23:56:51 +08:00
|
|
|
|
2022-02-01 03:10:03 +08:00
|
|
|
default_efi = (
|
|
|
|
self.config.get_default_firmware_setting() == "uefi" and
|
|
|
|
guest.os.is_x86() and
|
|
|
|
guest.os.is_hvm())
|
2022-01-26 08:48:19 +08:00
|
|
|
if default_efi:
|
|
|
|
log.debug("UEFI default requested via app preferences")
|
|
|
|
|
|
|
|
if guest.prefers_uefi() or default_efi:
|
2015-02-22 23:01:02 +08:00
|
|
|
try:
|
2022-01-27 00:17:41 +08:00
|
|
|
# We call this for validation
|
|
|
|
guest.enable_uefi()
|
|
|
|
self._gdata.uefi_requested = True
|
2015-02-22 23:01:02 +08:00
|
|
|
installable_arch = True
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("UEFI found, setting it as default.")
|
2017-05-06 00:47:21 +08:00
|
|
|
except Exception as e:
|
2015-02-22 23:01:02 +08:00
|
|
|
installable_arch = False
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Error checking for UEFI default", exc_info=True)
|
2018-08-09 02:27:27 +08:00
|
|
|
msg = _("Failed to setup UEFI: %s\n"
|
2015-02-22 23:01:02 +08:00
|
|
|
"Install options are limited.") % e
|
2015-09-24 04:46:33 +08:00
|
|
|
self._show_arch_warning(msg)
|
2015-02-22 23:01:02 +08:00
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
# Install Options
|
2011-07-15 01:13:13 +08:00
|
|
|
method_tree = self.widget("method-tree")
|
2020-01-26 22:52:18 +08:00
|
|
|
method_manual = self.widget("method-manual")
|
2011-07-15 01:13:13 +08:00
|
|
|
method_local = self.widget("method-local")
|
2012-02-09 22:50:54 +08:00
|
|
|
method_import = self.widget("method-import")
|
2011-07-15 01:13:13 +08:00
|
|
|
method_container_app = self.widget("method-container-app")
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2013-10-02 23:56:51 +08:00
|
|
|
method_tree.set_sensitive((is_local or can_remote_url) and
|
|
|
|
installable_arch)
|
|
|
|
method_local.set_sensitive(not is_pv and can_storage and
|
|
|
|
installable_arch)
|
2020-08-23 01:22:51 +08:00
|
|
|
method_manual.set_sensitive(not is_container_only)
|
2012-02-09 22:50:54 +08:00
|
|
|
method_import.set_sensitive(can_storage)
|
2020-01-26 22:52:18 +08:00
|
|
|
virt_methods = [method_local, method_tree,
|
|
|
|
method_manual, method_import]
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
local_tt = None
|
|
|
|
tree_tt = None
|
2012-02-09 22:50:54 +08:00
|
|
|
import_tt = None
|
|
|
|
|
|
|
|
if not is_local:
|
|
|
|
if not can_remote_url:
|
|
|
|
tree_tt = _("Libvirt version does not "
|
|
|
|
"support remote URL installs.")
|
2020-08-29 08:30:03 +08:00
|
|
|
if not is_storage_capable: # pragma: no cover
|
2012-02-09 22:50:54 +08:00
|
|
|
local_tt = _("Connection does not support storage management.")
|
|
|
|
import_tt = local_tt
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
if is_pv:
|
2020-07-14 15:42:00 +08:00
|
|
|
local_tt = _("CDROM/ISO installs not available for paravirt guests.")
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2013-10-02 23:56:51 +08:00
|
|
|
if not installable_arch:
|
|
|
|
msg = (_("Architecture '%s' is not installable") %
|
2018-09-13 01:43:56 +08:00
|
|
|
guest.os.arch)
|
2013-10-02 23:56:51 +08:00
|
|
|
tree_tt = msg
|
|
|
|
local_tt = msg
|
|
|
|
|
2014-01-13 03:41:25 +08:00
|
|
|
if not any([w.get_active() and w.get_sensitive()
|
|
|
|
for w in virt_methods]):
|
|
|
|
for w in virt_methods:
|
|
|
|
if w.get_sensitive():
|
|
|
|
w.set_active(True)
|
|
|
|
break
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2020-08-23 01:22:51 +08:00
|
|
|
if not (is_container_only or
|
2013-04-12 04:32:00 +08:00
|
|
|
[w for w in virt_methods if w.get_sensitive()]):
|
2020-08-29 08:30:03 +08:00
|
|
|
return self._show_startup_error( # pragma: no cover
|
2012-02-09 22:50:54 +08:00
|
|
|
_("No install methods available for this connection."),
|
|
|
|
hideinstall=False)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
method_tree.set_tooltip_text(tree_tt or "")
|
|
|
|
method_local.set_tooltip_text(local_tt or "")
|
|
|
|
method_import.set_tooltip_text(import_tt or "")
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2011-06-08 05:42:50 +08:00
|
|
|
# Container install options
|
|
|
|
method_container_app.set_active(True)
|
2020-08-23 01:22:51 +08:00
|
|
|
self.widget("container-install-box").set_visible(is_container_only)
|
2017-03-13 20:01:51 +08:00
|
|
|
self.widget("vz-install-box").set_visible(is_vz)
|
2017-03-22 23:31:53 +08:00
|
|
|
self.widget("virt-install-box").set_visible(
|
2020-08-23 01:22:51 +08:00
|
|
|
not is_container_only and not is_vz_container)
|
2011-06-08 05:42:50 +08:00
|
|
|
|
2020-01-26 22:38:22 +08:00
|
|
|
self.widget("kernel-info-box").set_visible(not installable_arch)
|
2013-10-02 23:56:51 +08:00
|
|
|
|
2015-11-03 03:08:09 +08:00
|
|
|
def _populate_conn_state(self):
|
2015-09-13 01:03:51 +08:00
|
|
|
"""
|
|
|
|
Update all state that has some dependency on the current connection
|
|
|
|
"""
|
2013-10-02 19:35:02 +08:00
|
|
|
self.conn.schedule_priority_tick(pollnet=True,
|
2020-01-26 09:28:43 +08:00
|
|
|
pollpool=True,
|
2015-04-08 01:56:48 +08:00
|
|
|
pollnodedev=True)
|
2013-10-02 19:35:02 +08:00
|
|
|
|
|
|
|
self.widget("install-box").show()
|
|
|
|
self.widget("create-forward").set_sensitive(True)
|
|
|
|
|
2015-11-03 03:08:09 +08:00
|
|
|
self._capsinfo = None
|
2015-07-20 15:19:57 +08:00
|
|
|
self.conn.invalidate_caps()
|
|
|
|
|
2020-08-30 21:29:55 +08:00
|
|
|
if not self.conn.caps.has_install_options():
|
2013-10-02 19:35:02 +08:00
|
|
|
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.")
|
2015-09-13 01:03:51 +08:00
|
|
|
return self._show_startup_error(error)
|
2013-10-02 19:35:02 +08:00
|
|
|
|
2020-08-30 21:29:55 +08:00
|
|
|
self._change_caps()
|
|
|
|
|
2015-09-15 06:31:56 +08:00
|
|
|
# A bit out of order, but populate the xen/virt/arch/machine lists
|
|
|
|
# so we can work with a default.
|
|
|
|
self._populate_xen_type()
|
2015-09-13 01:03:51 +08:00
|
|
|
self._populate_arch()
|
2015-09-15 06:31:56 +08:00
|
|
|
self._populate_virt_type()
|
2013-10-02 19:35:02 +08:00
|
|
|
|
2015-09-15 06:31:56 +08:00
|
|
|
show_arch = (self.widget("xen-type").get_visible() or
|
|
|
|
self.widget("virt-type").get_visible() or
|
2015-09-14 06:01:39 +08:00
|
|
|
self.widget("arch").get_visible() or
|
|
|
|
self.widget("machine").get_visible())
|
2014-01-27 07:15:50 +08:00
|
|
|
uiutil.set_grid_row_visible(self.widget("arch-expander"), show_arch)
|
2013-10-02 19:35:02 +08:00
|
|
|
|
2020-08-30 21:02:07 +08:00
|
|
|
if self.conn.is_qemu():
|
2015-09-14 00:45:35 +08:00
|
|
|
if not self._capsinfo.guest.is_kvm_available():
|
2013-10-02 19:35:02 +08:00
|
|
|
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.")
|
2015-09-13 01:03:51 +08:00
|
|
|
self._show_startup_warning(error)
|
2013-10-02 19:35:02 +08:00
|
|
|
|
2017-03-13 20:01:51 +08:00
|
|
|
elif self.conn.is_vz():
|
|
|
|
has_hvm_guests = False
|
|
|
|
has_exe_guests = False
|
|
|
|
for g in self.conn.caps.guests:
|
|
|
|
if g.os_type == "hvm":
|
|
|
|
has_hvm_guests = True
|
|
|
|
if g.os_type == "exe":
|
|
|
|
has_exe_guests = True
|
|
|
|
|
|
|
|
self.widget("vz-virt-type-hvm").set_sensitive(has_hvm_guests)
|
|
|
|
self.widget("vz-virt-type-exe").set_sensitive(has_exe_guests)
|
2017-03-22 23:31:53 +08:00
|
|
|
self.widget("vz-virt-type-hvm").set_active(has_hvm_guests)
|
|
|
|
self.widget("vz-virt-type-exe").set_active(
|
|
|
|
not has_hvm_guests and has_exe_guests)
|
2017-03-13 20:01:51 +08:00
|
|
|
|
2018-10-07 02:26:31 +08:00
|
|
|
# ISO media
|
|
|
|
# Dependent on connection so we need to do this here
|
|
|
|
self._mediacombo.set_conn(self.conn)
|
2015-09-14 00:45:35 +08:00
|
|
|
self._mediacombo.reset_state()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2017-07-06 00:51:18 +08:00
|
|
|
# Allow container bootstrap only for local connection and
|
|
|
|
# only if virt-bootstrap is installed. Otherwise, show message.
|
2020-08-30 21:29:55 +08:00
|
|
|
is_local = not self.conn.is_remote()
|
2022-01-18 04:12:42 +08:00
|
|
|
vb_installed = is_virt_bootstrap_installed(self.conn)
|
2017-07-06 00:51:18 +08:00
|
|
|
vb_enabled = is_local and vb_installed
|
|
|
|
|
|
|
|
oscontainer_widget_conf = {
|
|
|
|
"install-oscontainer-notsupport-conn": not is_local,
|
|
|
|
"install-oscontainer-notsupport": not vb_installed,
|
|
|
|
"install-oscontainer-bootstrap": vb_enabled,
|
2017-12-20 00:32:18 +08:00
|
|
|
"install-oscontainer-source": vb_enabled,
|
|
|
|
"install-oscontainer-rootpw-box": vb_enabled
|
2017-07-06 00:51:18 +08:00
|
|
|
}
|
2021-10-05 03:38:24 +08:00
|
|
|
for wname, val in oscontainer_widget_conf.items():
|
|
|
|
self.widget(wname).set_visible(val)
|
2017-07-06 00:51:18 +08:00
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
# Memory
|
|
|
|
memory = int(self.conn.host_memory_size())
|
2010-12-11 00:47:07 +08:00
|
|
|
mem_label = (_("Up to %(maxmem)s available on the host") %
|
2015-09-13 01:03:51 +08:00
|
|
|
{'maxmem': _pretty_memory(memory)})
|
2020-02-02 06:16:45 +08:00
|
|
|
mem_label = ("<span size='small'>%s</span>" % mem_label)
|
2017-10-11 19:35:55 +08:00
|
|
|
self.widget("mem").set_range(50, memory // 1024)
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("phys-mem-label").set_markup(mem_label)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
# CPU
|
2013-07-07 00:36:07 +08:00
|
|
|
phys_cpus = int(self.conn.host_active_processor_count())
|
2020-07-14 15:41:58 +08:00
|
|
|
cpu_label = (ngettext("Up to %(numcpus)d available",
|
|
|
|
"Up to %(numcpus)d available",
|
|
|
|
phys_cpus) %
|
2010-12-11 00:47:07 +08:00
|
|
|
{'numcpus': int(phys_cpus)})
|
2020-02-02 06:16:45 +08:00
|
|
|
cpu_label = ("<span size='small'>%s</span>" % cpu_label)
|
2020-02-06 03:58:51 +08:00
|
|
|
self.widget("cpus").set_range(1, max(phys_cpus, 1))
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("phys-cpu-label").set_markup(cpu_label)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
# Storage
|
2015-09-14 00:45:35 +08:00
|
|
|
self._addstorage.conn = self.conn
|
|
|
|
self._addstorage.reset_state()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
# Networking
|
2015-09-14 06:01:39 +08:00
|
|
|
self.widget("advanced-expander").set_expanded(False)
|
2014-01-29 02:59:31 +08:00
|
|
|
|
2015-09-14 00:45:35 +08:00
|
|
|
self._netlist = vmmNetworkList(self.conn, self.builder, self.topwin)
|
2015-09-14 06:01:39 +08:00
|
|
|
self.widget("netdev-ui-align").add(self._netlist.top_box)
|
2015-09-14 00:45:35 +08:00
|
|
|
self._netlist.reset_state()
|
2010-12-05 01:28:44 +08:00
|
|
|
|
2018-03-15 19:43:56 +08:00
|
|
|
def _conn_state_changed(self, conn):
|
|
|
|
if conn.is_disconnected():
|
|
|
|
self._close()
|
|
|
|
|
2015-11-03 03:08:09 +08:00
|
|
|
def _set_conn(self, newconn):
|
|
|
|
self.widget("startup-error-box").hide()
|
|
|
|
self.widget("arch-warning-box").hide()
|
|
|
|
|
2018-03-15 19:43:56 +08:00
|
|
|
oldconn = self.conn
|
2015-11-03 03:08:09 +08:00
|
|
|
self.conn = newconn
|
2018-03-15 19:43:56 +08:00
|
|
|
if oldconn:
|
|
|
|
oldconn.disconnect_by_obj(self)
|
|
|
|
if self._netlist:
|
|
|
|
self.widget("netdev-ui-align").remove(self._netlist.top_box)
|
|
|
|
self._netlist.cleanup()
|
|
|
|
self._netlist = None
|
|
|
|
|
2015-11-03 03:08:09 +08:00
|
|
|
if not self.conn:
|
|
|
|
return self._show_startup_error(
|
|
|
|
_("No active connection to install on."))
|
2018-03-15 19:43:56 +08:00
|
|
|
self.conn.connect("state-changed", self._conn_state_changed)
|
2015-11-03 03:08:09 +08:00
|
|
|
|
|
|
|
try:
|
2020-08-30 21:29:55 +08:00
|
|
|
return self._populate_conn_state()
|
2020-02-06 03:58:51 +08:00
|
|
|
except Exception as e: # pragma: no cover
|
2019-06-17 09:12:39 +08:00
|
|
|
log.exception("Error setting create wizard conn state.")
|
2015-11-03 03:08:09 +08:00
|
|
|
return self._show_startup_error(str(e))
|
|
|
|
|
|
|
|
|
2015-09-15 06:31:56 +08:00
|
|
|
def _change_caps(self, gtype=None, arch=None, domtype=None):
|
2015-09-13 01:03:51 +08:00
|
|
|
"""
|
|
|
|
Change the cached capsinfo for the passed values, and trigger
|
|
|
|
all needed UI refreshing
|
|
|
|
"""
|
|
|
|
if gtype is None:
|
|
|
|
# If none specified, prefer HVM so install options aren't limited
|
|
|
|
# with a default PV choice.
|
|
|
|
for g in self.conn.caps.guests:
|
|
|
|
if g.os_type == "hvm":
|
|
|
|
gtype = "hvm"
|
|
|
|
break
|
|
|
|
|
2015-09-15 06:31:56 +08:00
|
|
|
capsinfo = self.conn.caps.guest_lookup(os_type=gtype,
|
|
|
|
arch=arch,
|
|
|
|
typ=domtype)
|
2015-09-13 01:03:51 +08:00
|
|
|
|
2015-09-14 00:45:35 +08:00
|
|
|
if self._capsinfo:
|
|
|
|
if (self._capsinfo.guest == capsinfo.guest and
|
|
|
|
self._capsinfo.domain == capsinfo.domain):
|
2015-09-13 01:03:51 +08:00
|
|
|
return
|
|
|
|
|
2015-09-14 00:45:35 +08:00
|
|
|
self._capsinfo = capsinfo
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Guest type set to os_type=%s, arch=%s, dom_type=%s",
|
2015-09-14 00:45:35 +08:00
|
|
|
self._capsinfo.os_type,
|
|
|
|
self._capsinfo.arch,
|
|
|
|
self._capsinfo.hypervisor_type)
|
2018-09-13 02:08:54 +08:00
|
|
|
self._populate_machine()
|
2015-09-13 01:03:51 +08:00
|
|
|
self._set_caps_state()
|
|
|
|
|
|
|
|
|
|
|
|
##################################################
|
|
|
|
# Helpers for populating hv/arch/machine/conn UI #
|
|
|
|
##################################################
|
|
|
|
|
2015-09-15 06:31:56 +08:00
|
|
|
def _populate_xen_type(self):
|
|
|
|
model = self.widget("xen-type").get_model()
|
2009-03-10 04:16:45 +08:00
|
|
|
model.clear()
|
|
|
|
|
|
|
|
default = 0
|
2015-09-15 06:31:56 +08:00
|
|
|
guests = []
|
2017-06-28 02:13:36 +08:00
|
|
|
if self.conn.is_xen() or self.conn.is_test():
|
2015-09-15 06:31:56 +08:00
|
|
|
guests = self.conn.caps.guests[:]
|
2013-10-02 05:27:58 +08:00
|
|
|
|
2015-09-15 06:31:56 +08:00
|
|
|
for guest in guests:
|
2013-10-02 05:27:58 +08:00
|
|
|
if not guest.domains:
|
2020-02-06 03:58:51 +08:00
|
|
|
continue # pragma: no cover
|
2015-09-15 06:31:56 +08:00
|
|
|
|
|
|
|
gtype = guest.os_type
|
2013-10-02 05:27:58 +08:00
|
|
|
dom = guest.domains[0]
|
|
|
|
domtype = dom.hypervisor_type
|
2014-01-27 06:42:24 +08:00
|
|
|
label = self.conn.pretty_hv(gtype, domtype)
|
2013-10-02 05:27:58 +08:00
|
|
|
|
|
|
|
# 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
|
2015-09-14 00:45:35 +08:00
|
|
|
if (gtype == self._capsinfo.os_type and
|
2015-09-15 06:31:56 +08:00
|
|
|
domtype == self._capsinfo.hypervisor_type):
|
2013-10-02 05:27:58 +08:00
|
|
|
default = len(model)
|
2006-08-09 23:40:34 +08:00
|
|
|
|
2013-10-02 05:27:58 +08:00
|
|
|
model.append([label, gtype])
|
|
|
|
|
2015-09-15 06:31:56 +08:00
|
|
|
show = bool(len(model))
|
|
|
|
uiutil.set_grid_row_visible(self.widget("xen-type"), show)
|
2013-10-02 05:27:58 +08:00
|
|
|
if show:
|
2015-09-15 06:31:56 +08:00
|
|
|
self.widget("xen-type").set_active(default)
|
2006-09-13 05:49:29 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _populate_arch(self):
|
2015-09-15 06:31:56 +08:00
|
|
|
model = self.widget("arch").get_model()
|
2009-03-10 04:16:45 +08:00
|
|
|
model.clear()
|
|
|
|
|
|
|
|
default = 0
|
2013-10-02 05:27:58 +08:00
|
|
|
archs = []
|
2014-03-12 23:42:50 +08:00
|
|
|
for guest in self.conn.caps.guests:
|
2015-09-14 00:45:35 +08:00
|
|
|
if guest.os_type == self._capsinfo.os_type:
|
2013-10-02 05:27:58 +08:00
|
|
|
archs.append(guest.arch)
|
|
|
|
|
|
|
|
# Combine x86/i686 to avoid confusion
|
2014-01-19 02:23:30 +08:00
|
|
|
if (self.conn.caps.host.cpu.arch == "x86_64" and
|
2013-10-03 01:10:11 +08:00
|
|
|
"x86_64" in archs and "i686" in archs):
|
2013-10-02 05:27:58 +08:00
|
|
|
archs.remove("i686")
|
2013-10-03 01:10:11 +08:00
|
|
|
archs.sort()
|
|
|
|
|
2015-07-13 19:35:24 +08:00
|
|
|
prios = ["x86_64", "i686", "aarch64", "armv7l", "ppc64", "ppc64le",
|
|
|
|
"s390x"]
|
2014-01-19 02:23:30 +08:00
|
|
|
if self.conn.caps.host.cpu.arch not in prios:
|
2020-08-29 08:30:03 +08:00
|
|
|
prios = [] # pragma: no cover
|
2020-02-06 03:58:51 +08:00
|
|
|
for p in prios[:]:
|
|
|
|
if p not in archs:
|
|
|
|
prios.remove(p)
|
|
|
|
else:
|
|
|
|
archs.remove(p)
|
2013-10-03 01:10:11 +08:00
|
|
|
if prios:
|
|
|
|
if archs:
|
|
|
|
prios += [None]
|
|
|
|
archs = prios + archs
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2013-10-02 05:27:58 +08:00
|
|
|
default = 0
|
2015-09-14 00:45:35 +08:00
|
|
|
if self._capsinfo.arch in archs:
|
|
|
|
default = archs.index(self._capsinfo.arch)
|
2013-10-03 01:10:11 +08:00
|
|
|
|
2013-10-02 05:27:58 +08:00
|
|
|
for arch in archs:
|
2015-09-15 06:31:56 +08:00
|
|
|
model.append([_pretty_arch(arch), arch])
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2013-10-02 05:27:58 +08:00
|
|
|
show = not (len(archs) < 2)
|
2015-09-15 06:31:56 +08:00
|
|
|
uiutil.set_grid_row_visible(self.widget("arch"), show)
|
|
|
|
self.widget("arch").set_active(default)
|
|
|
|
|
|
|
|
def _populate_virt_type(self):
|
|
|
|
model = self.widget("virt-type").get_model()
|
|
|
|
model.clear()
|
|
|
|
|
|
|
|
# Allow choosing between qemu and kvm for archs that traditionally
|
2015-09-29 08:00:01 +08:00
|
|
|
# have a decent amount of TCG usage, like armv7l. Also include
|
|
|
|
# aarch64 which can be used for arm32 VMs as well
|
2015-09-15 06:31:56 +08:00
|
|
|
domains = [d.hypervisor_type for d in self._capsinfo.guest.domains[:]]
|
|
|
|
if not self.conn.is_qemu():
|
|
|
|
domains = []
|
2015-09-29 08:00:01 +08:00
|
|
|
elif self._capsinfo.arch in ["i686", "x86_64", "ppc64", "ppc64le"]:
|
2015-09-15 06:31:56 +08:00
|
|
|
domains = []
|
|
|
|
|
|
|
|
default = 0
|
|
|
|
if self._capsinfo.hypervisor_type in domains:
|
|
|
|
default = domains.index(self._capsinfo.hypervisor_type)
|
|
|
|
|
|
|
|
prios = ["kvm"]
|
|
|
|
for domain in prios:
|
|
|
|
if domain not in domains:
|
|
|
|
continue
|
|
|
|
domains.remove(domain)
|
|
|
|
domains.insert(0, domain)
|
|
|
|
|
|
|
|
for domain in domains:
|
|
|
|
label = self.conn.pretty_hv(self._capsinfo.os_type, domain)
|
|
|
|
model.append([label, domain])
|
|
|
|
|
|
|
|
show = bool(len(model) > 1)
|
|
|
|
uiutil.set_grid_row_visible(self.widget("virt-type"), show)
|
|
|
|
self.widget("virt-type").set_active(default)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _populate_machine(self):
|
2015-09-15 06:31:56 +08:00
|
|
|
model = self.widget("machine").get_model()
|
2013-10-02 05:40:44 +08:00
|
|
|
|
2015-09-14 00:45:35 +08:00
|
|
|
machines = self._capsinfo.machines[:]
|
|
|
|
if self._capsinfo.arch in ["i686", "x86_64"]:
|
2013-10-02 05:40:44 +08:00
|
|
|
machines = []
|
2013-10-03 01:10:11 +08:00
|
|
|
machines.sort()
|
2013-10-02 05:40:44 +08:00
|
|
|
|
|
|
|
defmachine = None
|
2013-10-03 01:10:11 +08:00
|
|
|
prios = []
|
2018-09-07 07:07:15 +08:00
|
|
|
recommended_machine = virtinst.Guest.get_recommended_machine(
|
|
|
|
self._capsinfo)
|
2014-09-24 04:05:48 +08:00
|
|
|
if recommended_machine:
|
|
|
|
defmachine = recommended_machine
|
|
|
|
prios = [defmachine]
|
2013-10-03 01:10:11 +08:00
|
|
|
|
|
|
|
for p in prios[:]:
|
|
|
|
if p not in machines:
|
2020-08-29 08:30:03 +08:00
|
|
|
prios.remove(p) # pragma: no cover
|
2013-10-03 01:10:11 +08:00
|
|
|
else:
|
|
|
|
machines.remove(p)
|
|
|
|
if prios:
|
|
|
|
machines = prios + [None] + machines
|
2013-10-02 05:40:44 +08:00
|
|
|
|
|
|
|
default = 0
|
2013-10-03 01:10:11 +08:00
|
|
|
if defmachine and defmachine in machines:
|
2013-10-02 05:40:44 +08:00
|
|
|
default = machines.index(defmachine)
|
|
|
|
|
2018-09-13 02:08:54 +08:00
|
|
|
self.widget("machine").disconnect_by_func(self._machine_changed)
|
|
|
|
try:
|
|
|
|
model.clear()
|
|
|
|
for m in machines:
|
|
|
|
model.append([m])
|
2013-10-02 05:40:44 +08:00
|
|
|
|
2018-09-13 02:08:54 +08:00
|
|
|
show = (len(machines) > 1)
|
|
|
|
uiutil.set_grid_row_visible(self.widget("machine"), show)
|
|
|
|
if show:
|
|
|
|
self.widget("machine").set_active(default)
|
|
|
|
finally:
|
|
|
|
self.widget("machine").connect("changed", self._machine_changed)
|
2013-10-02 05:40:44 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _populate_conn_list(self, urihint=None):
|
2011-07-15 01:13:13 +08:00
|
|
|
conn_list = self.widget("create-conn")
|
2009-03-10 04:16:45 +08:00
|
|
|
model = conn_list.get_model()
|
|
|
|
model.clear()
|
|
|
|
|
|
|
|
default = -1
|
2018-03-15 01:13:22 +08:00
|
|
|
connmanager = vmmConnectionManager.get_instance()
|
|
|
|
for connobj in connmanager.conns.values():
|
2009-03-10 04:16:45 +08:00
|
|
|
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)
|
|
|
|
|
2015-04-12 00:57:32 +08:00
|
|
|
model.append([connobj.get_uri(), connobj.get_pretty_desc()])
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
no_conns = (len(model) == 0)
|
|
|
|
|
|
|
|
if default < 0 and not no_conns:
|
2020-08-29 08:30:03 +08:00
|
|
|
default = 0 # pragma: no cover
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
activeuri = ""
|
|
|
|
activedesc = ""
|
|
|
|
activeconn = None
|
|
|
|
if not no_conns:
|
|
|
|
conn_list.set_active(default)
|
|
|
|
activeuri, activedesc = model[default]
|
2018-03-15 01:13:22 +08:00
|
|
|
activeconn = connmanager.conns[activeuri]
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("create-conn-label").set_text(activedesc)
|
2009-03-10 04:16:45 +08:00
|
|
|
if len(model) <= 1:
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("create-conn").hide()
|
|
|
|
self.widget("create-conn-label").show()
|
2006-09-13 05:49:29 +08:00
|
|
|
else:
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("create-conn").show()
|
|
|
|
self.widget("create-conn-label").hide()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
return activeconn
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
###############################
|
|
|
|
# Misc UI populating routines #
|
|
|
|
###############################
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-15 04:22:17 +08:00
|
|
|
def _populate_summary_storage(self, path=None):
|
2020-02-02 06:16:45 +08:00
|
|
|
storagetmpl = "<span size='small'>%s</span>"
|
2015-09-15 04:05:58 +08:00
|
|
|
storagesize = ""
|
|
|
|
storagepath = ""
|
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
disk = self._gdata.disk
|
|
|
|
fs = self._gdata.filesystem
|
2015-09-15 04:05:58 +08:00
|
|
|
if disk:
|
|
|
|
if disk.wants_storage_creation():
|
|
|
|
storagesize = "%s" % _pretty_storage(disk.get_size())
|
2015-09-15 04:22:17 +08:00
|
|
|
if not path:
|
2020-11-12 04:38:34 +08:00
|
|
|
path = disk.get_source_path()
|
2015-09-15 04:22:17 +08:00
|
|
|
storagepath = (storagetmpl % path)
|
2020-01-30 00:25:12 +08:00
|
|
|
elif fs:
|
2015-09-15 04:05:58 +08:00
|
|
|
storagepath = storagetmpl % fs.source
|
|
|
|
else:
|
|
|
|
storagepath = _("None")
|
|
|
|
|
|
|
|
self.widget("summary-storage").set_markup(storagesize)
|
|
|
|
self.widget("summary-storage").set_visible(bool(storagesize))
|
|
|
|
self.widget("summary-storage-path").set_markup(storagepath)
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _populate_summary(self):
|
2020-01-30 00:25:12 +08:00
|
|
|
guest = self._gdata.build_guest()
|
|
|
|
mem = _pretty_memory(int(guest.memory))
|
|
|
|
cpu = str(int(guest.vcpus))
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
instmethod = self._get_config_install_page()
|
2009-03-10 04:16:45 +08:00
|
|
|
install = ""
|
|
|
|
if instmethod == INSTALL_PAGE_ISO:
|
|
|
|
install = _("Local CDROM/ISO")
|
|
|
|
elif instmethod == INSTALL_PAGE_URL:
|
|
|
|
install = _("URL Install Tree")
|
2010-03-23 06:15:18 +08:00
|
|
|
elif instmethod == INSTALL_PAGE_IMPORT:
|
|
|
|
install = _("Import existing OS image")
|
2020-01-26 22:52:18 +08:00
|
|
|
elif instmethod == INSTALL_PAGE_MANUAL:
|
|
|
|
install = _("Manual install")
|
2011-06-08 05:42:50 +08:00
|
|
|
elif instmethod == INSTALL_PAGE_CONTAINER_APP:
|
|
|
|
install = _("Application container")
|
2011-06-21 23:04:22 +08:00
|
|
|
elif instmethod == INSTALL_PAGE_CONTAINER_OS:
|
2011-06-08 05:42:50 +08:00
|
|
|
install = _("Operating system container")
|
2017-03-13 20:01:51 +08:00
|
|
|
elif instmethod == INSTALL_PAGE_VZ_TEMPLATE:
|
|
|
|
install = _("Virtuozzo container")
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
self.widget("summary-os").set_text(guest.osinfo.label)
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("summary-install").set_text(install)
|
|
|
|
self.widget("summary-mem").set_text(mem)
|
|
|
|
self.widget("summary-cpu").set_text(cpu)
|
2015-09-15 04:05:58 +08:00
|
|
|
self._populate_summary_storage()
|
2006-09-13 05:49:29 +08:00
|
|
|
|
2022-01-26 04:52:04 +08:00
|
|
|
nsource = self._netlist.get_network_selection()[1]
|
|
|
|
if not nsource:
|
2020-09-02 01:32:47 +08:00
|
|
|
self.widget("advanced-expander").set_expanded(True)
|
2014-01-28 05:58:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
################################
|
|
|
|
# UI state getters and helpers #
|
|
|
|
################################
|
|
|
|
|
|
|
|
def _get_config_name(self):
|
2011-07-15 01:13:13 +08:00
|
|
|
return self.widget("create-vm-name").get_text()
|
2006-09-13 05:49:29 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _get_config_machine(self):
|
2015-09-14 06:01:39 +08:00
|
|
|
return uiutil.get_list_selection(self.widget("machine"),
|
2014-04-03 22:53:54 +08:00
|
|
|
check_visible=True)
|
2013-10-02 23:56:51 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _get_config_install_page(self):
|
2017-03-13 20:01:51 +08:00
|
|
|
if self.widget("vz-install-box").get_visible():
|
|
|
|
if self.widget("vz-virt-type-exe").get_active():
|
|
|
|
return INSTALL_PAGE_VZ_TEMPLATE
|
2013-09-09 23:02:34 +08:00
|
|
|
if self.widget("virt-install-box").get_visible():
|
2011-07-15 01:13:13 +08:00
|
|
|
if self.widget("method-local").get_active():
|
2011-06-08 05:42:50 +08:00
|
|
|
return INSTALL_PAGE_ISO
|
2011-07-15 01:13:13 +08:00
|
|
|
elif self.widget("method-tree").get_active():
|
2011-06-08 05:42:50 +08:00
|
|
|
return INSTALL_PAGE_URL
|
2011-07-15 01:13:13 +08:00
|
|
|
elif self.widget("method-import").get_active():
|
2011-06-08 05:42:50 +08:00
|
|
|
return INSTALL_PAGE_IMPORT
|
2020-01-26 22:52:18 +08:00
|
|
|
elif self.widget("method-manual").get_active():
|
|
|
|
return INSTALL_PAGE_MANUAL
|
2011-06-08 05:42:50 +08:00
|
|
|
else:
|
2011-07-15 01:13:13 +08:00
|
|
|
if self.widget("method-container-app").get_active():
|
2011-06-08 05:42:50 +08:00
|
|
|
return INSTALL_PAGE_CONTAINER_APP
|
2011-07-15 01:13:13 +08:00
|
|
|
if self.widget("method-container-os").get_active():
|
2011-06-08 05:42:50 +08:00
|
|
|
return INSTALL_PAGE_CONTAINER_OS
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _is_container_install(self):
|
|
|
|
return self._get_config_install_page() in [INSTALL_PAGE_CONTAINER_APP,
|
2017-03-13 20:01:51 +08:00
|
|
|
INSTALL_PAGE_CONTAINER_OS,
|
|
|
|
INSTALL_PAGE_VZ_TEMPLATE]
|
2017-07-06 00:51:19 +08:00
|
|
|
|
|
|
|
|
|
|
|
def _get_config_oscontainer_bootstrap(self):
|
|
|
|
return self.widget("install-oscontainer-bootstrap").get_active()
|
|
|
|
|
|
|
|
|
2017-07-06 00:51:21 +08:00
|
|
|
def _get_config_oscontainer_source_url(self, store_media=False):
|
|
|
|
src_url = (self.widget("install-oscontainer-source-url-entry")
|
|
|
|
.get_text().strip())
|
|
|
|
|
|
|
|
if src_url and store_media:
|
|
|
|
self.config.add_container_url(src_url)
|
|
|
|
|
|
|
|
return src_url
|
2017-07-06 00:51:19 +08:00
|
|
|
|
|
|
|
|
|
|
|
def _get_config_oscontainer_source_username(self):
|
|
|
|
return (self.widget("install-oscontainer-source-user")
|
|
|
|
.get_text().strip())
|
|
|
|
|
|
|
|
|
|
|
|
def _get_config_oscontainer_source_password(self):
|
|
|
|
return self.widget("install-oscontainer-source-passwd").get_text()
|
|
|
|
|
|
|
|
|
|
|
|
def _get_config_oscontainer_isecure(self):
|
|
|
|
return self.widget("install-oscontainer-source-insecure").get_active()
|
|
|
|
|
|
|
|
|
2017-12-20 00:32:18 +08:00
|
|
|
def _get_config_oscontainer_root_password(self):
|
|
|
|
return self.widget("install-oscontainer-rootpw").get_text()
|
|
|
|
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _should_skip_disk_page(self):
|
|
|
|
return self._get_config_install_page() in [INSTALL_PAGE_IMPORT,
|
|
|
|
INSTALL_PAGE_CONTAINER_APP,
|
2017-03-13 20:01:51 +08:00
|
|
|
INSTALL_PAGE_CONTAINER_OS,
|
|
|
|
INSTALL_PAGE_VZ_TEMPLATE]
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
def _get_config_local_media(self, store_media=False):
|
2018-10-07 02:26:31 +08:00
|
|
|
return self._mediacombo.get_path(store_media=store_media)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _get_config_detectable_media(self):
|
|
|
|
instpage = self._get_config_install_page()
|
2019-02-04 05:03:56 +08:00
|
|
|
cdrom = None
|
|
|
|
location = None
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
if instpage == INSTALL_PAGE_ISO:
|
2019-02-04 05:03:56 +08:00
|
|
|
cdrom = self._get_config_local_media()
|
2009-03-10 04:16:45 +08:00
|
|
|
elif instpage == INSTALL_PAGE_URL:
|
2019-02-04 05:03:56 +08:00
|
|
|
location = self.widget("install-url-entry").get_text()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2019-02-04 05:03:56 +08:00
|
|
|
return cdrom, location
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _get_config_url_info(self, store_media=False):
|
2015-09-13 03:14:40 +08:00
|
|
|
media = self.widget("install-url-entry").get_text().strip()
|
2011-07-15 01:13:13 +08:00
|
|
|
extra = self.widget("install-urlopts-entry").get_text().strip()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2009-05-11 23:00:03 +08:00
|
|
|
if media and store_media:
|
2009-03-10 04:16:45 +08:00
|
|
|
self.config.add_media_url(media)
|
|
|
|
|
2017-05-17 19:53:38 +08:00
|
|
|
return (media, extra)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _get_config_import_path(self):
|
2011-07-15 01:13:13 +08:00
|
|
|
return self.widget("install-import-entry").get_text()
|
2010-03-23 06:15:18 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _is_default_storage(self):
|
2015-09-14 00:45:35 +08:00
|
|
|
return (self._addstorage.is_default_storage() and
|
2015-09-13 01:03:51 +08:00
|
|
|
not self._should_skip_disk_page())
|
2010-03-04 07:16:08 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _is_os_detect_active(self):
|
2011-07-15 01:13:13 +08:00
|
|
|
return self.widget("install-detect-os").get_active()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
|
2015-09-07 02:42:55 +08:00
|
|
|
################
|
|
|
|
# UI Listeners #
|
|
|
|
################
|
|
|
|
|
|
|
|
def _close_requested(self, *ignore1, **ignore2):
|
2015-09-13 01:03:51 +08:00
|
|
|
"""
|
|
|
|
When user tries to close the dialog, check for any disks that
|
|
|
|
we should auto cleanup
|
|
|
|
"""
|
2020-01-30 00:25:12 +08:00
|
|
|
if (not self._gdata or
|
|
|
|
not self._gdata.failed_guest):
|
2015-09-07 02:42:55 +08:00
|
|
|
self._close()
|
2020-01-30 00:25:12 +08:00
|
|
|
return 1
|
|
|
|
|
|
|
|
def _cleanup_disks(asyncjob, _failed_guest):
|
|
|
|
meter = asyncjob.get_meter()
|
|
|
|
virtinst.Installer.cleanup_created_disks(_failed_guest, meter)
|
|
|
|
|
|
|
|
def _cleanup_disks_finished(error, details):
|
|
|
|
if error: # pragma: no cover
|
|
|
|
log.debug("Error cleaning up disk images:"
|
|
|
|
"\nerror=%s\ndetails=%s", error, details)
|
|
|
|
self.idle_add(self._close)
|
|
|
|
|
|
|
|
progWin = vmmAsyncJob(
|
|
|
|
_cleanup_disks, [self._gdata.failed_guest],
|
|
|
|
_cleanup_disks_finished, [],
|
|
|
|
_("Removing disk images"),
|
|
|
|
_("Removing disk images we created for this virtual machine."),
|
|
|
|
self.topwin)
|
|
|
|
progWin.run()
|
2015-09-07 02:42:55 +08:00
|
|
|
|
|
|
|
return 1
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
# Intro page listeners
|
|
|
|
def _conn_changed(self, src):
|
2015-05-20 05:17:53 +08:00
|
|
|
uri = uiutil.get_list_selection(src)
|
2015-11-03 03:08:09 +08:00
|
|
|
newconn = None
|
2018-03-15 01:13:22 +08:00
|
|
|
connmanager = vmmConnectionManager.get_instance()
|
2014-01-27 09:21:12 +08:00
|
|
|
if uri:
|
2018-03-15 01:13:22 +08:00
|
|
|
newconn = connmanager.conns[uri]
|
2010-02-11 09:26:40 +08:00
|
|
|
|
|
|
|
# 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-10 04:16:45 +08:00
|
|
|
return
|
|
|
|
|
2015-11-03 03:08:09 +08:00
|
|
|
if self.conn is not newconn:
|
|
|
|
self._set_conn(newconn)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _method_changed(self, src):
|
2011-06-22 01:04:46 +08:00
|
|
|
ignore = src
|
2015-09-13 01:03:51 +08:00
|
|
|
# Reset the page number, since the total page numbers depend
|
|
|
|
# on the chosen install method
|
|
|
|
self._set_page_num_text(0)
|
2011-06-22 01:04:46 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _machine_changed(self, ignore):
|
2018-09-13 02:08:54 +08:00
|
|
|
self._set_caps_state()
|
2013-10-02 23:56:51 +08:00
|
|
|
|
2015-09-15 06:31:56 +08:00
|
|
|
def _xen_type_changed(self, ignore):
|
|
|
|
os_type = uiutil.get_list_selection(self.widget("xen-type"), column=1)
|
|
|
|
if not os_type:
|
2009-03-10 04:16:45 +08:00
|
|
|
return
|
|
|
|
|
2015-09-15 06:31:56 +08:00
|
|
|
self._change_caps(os_type)
|
2015-09-13 01:03:51 +08:00
|
|
|
self._populate_arch()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-15 06:31:56 +08:00
|
|
|
def _arch_changed(self, ignore):
|
|
|
|
arch = uiutil.get_list_selection(self.widget("arch"), column=1)
|
2014-01-27 09:21:12 +08:00
|
|
|
if not arch:
|
2009-03-10 04:16:45 +08:00
|
|
|
return
|
|
|
|
|
2015-09-14 00:45:35 +08:00
|
|
|
self._change_caps(self._capsinfo.os_type, arch)
|
2015-09-15 06:31:56 +08:00
|
|
|
self._populate_virt_type()
|
|
|
|
|
|
|
|
def _virt_type_changed(self, ignore):
|
|
|
|
domtype = uiutil.get_list_selection(self.widget("virt-type"), column=1)
|
|
|
|
if not domtype:
|
|
|
|
return
|
|
|
|
|
|
|
|
self._change_caps(self._capsinfo.os_type, self._capsinfo.arch, domtype)
|
2015-09-13 01:03:51 +08:00
|
|
|
|
2017-03-13 20:01:51 +08:00
|
|
|
def _vz_virt_type_changed(self, ignore):
|
|
|
|
is_hvm = self.widget("vz-virt-type-hvm").get_active()
|
|
|
|
if is_hvm:
|
|
|
|
self._change_caps("hvm")
|
|
|
|
else:
|
|
|
|
self._change_caps("exe")
|
2009-05-12 01:18:14 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
# Install page listeners
|
2015-09-13 03:14:40 +08:00
|
|
|
def _detectable_media_widget_changed(self, widget, checkfocus=True):
|
|
|
|
self._os_already_detected_for_media = False
|
|
|
|
|
|
|
|
# If the text entry widget has focus, don't fire detect_media_os,
|
|
|
|
# it means the user is probably typing. It will be detected
|
|
|
|
# when the user activates the widget, or we try to switch pages
|
|
|
|
if (checkfocus and
|
|
|
|
hasattr(widget, "get_text") and widget.has_focus()):
|
2009-03-10 04:16:45 +08:00
|
|
|
return
|
2014-03-20 08:09:58 +08:00
|
|
|
|
2015-09-13 03:14:40 +08:00
|
|
|
self._start_detect_os_if_needed()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 03:14:40 +08:00
|
|
|
def _url_changed(self, src):
|
|
|
|
self._detectable_media_widget_changed(src)
|
|
|
|
def _url_activated(self, src):
|
|
|
|
self._detectable_media_widget_changed(src, checkfocus=False)
|
2018-10-07 02:26:31 +08:00
|
|
|
def _iso_changed_cb(self, mediacombo, entry):
|
|
|
|
self._detectable_media_widget_changed(entry)
|
|
|
|
def _iso_activated_cb(self, mediacombo, entry):
|
|
|
|
self._detectable_media_widget_changed(entry, checkfocus=False)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2018-09-30 04:04:05 +08:00
|
|
|
def _detect_os_toggled_cb(self, src):
|
|
|
|
if not src.is_visible():
|
2020-08-29 08:30:03 +08:00
|
|
|
return # pragma: no cover
|
2013-10-05 22:29:16 +08:00
|
|
|
|
2018-09-30 04:04:05 +08:00
|
|
|
# We are only here if the user explicitly changed detection UI
|
|
|
|
dodetect = src.get_active()
|
|
|
|
self._change_os_detect(not dodetect)
|
2009-03-10 04:16:45 +08:00
|
|
|
if dodetect:
|
2015-09-13 03:14:40 +08:00
|
|
|
self._os_already_detected_for_media = False
|
|
|
|
self._start_detect_os_if_needed()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _browse_oscontainer(self, ignore):
|
2013-10-02 23:56:51 +08:00
|
|
|
self._browse_file("install-oscontainer-fs", is_dir=True)
|
2015-09-13 01:03:51 +08:00
|
|
|
def _browse_app(self, ignore):
|
2013-10-02 23:56:51 +08:00
|
|
|
self._browse_file("install-app-entry")
|
2015-09-13 01:03:51 +08:00
|
|
|
def _browse_import(self, ignore):
|
2013-10-02 23:56:51 +08:00
|
|
|
self._browse_file("install-import-entry")
|
2015-09-13 01:03:51 +08:00
|
|
|
def _browse_iso(self, ignore):
|
2011-06-21 23:04:22 +08:00
|
|
|
def set_path(ignore, path):
|
2018-10-07 02:26:31 +08:00
|
|
|
self._mediacombo.set_path(path)
|
2013-10-02 23:56:51 +08:00
|
|
|
self._browse_file(None, cb=set_path, is_media=True)
|
2011-06-21 23:04:22 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
# Storage page listeners
|
|
|
|
def _toggle_enable_storage(self, src):
|
2015-09-14 06:01:39 +08:00
|
|
|
self.widget("storage-align").set_sensitive(src.get_active())
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
# Summary page listeners
|
2015-09-15 04:22:17 +08:00
|
|
|
def _name_changed(self, src):
|
|
|
|
newname = src.get_text()
|
|
|
|
if not src.is_visible():
|
|
|
|
return
|
|
|
|
if not newname:
|
|
|
|
return
|
|
|
|
|
|
|
|
try:
|
|
|
|
path, ignore = self._get_storage_path(newname, do_log=False)
|
|
|
|
self._populate_summary_storage(path=path)
|
2020-02-06 03:58:51 +08:00
|
|
|
except Exception: # pragma: no cover
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Error generating storage path on name change "
|
2015-09-15 04:22:17 +08:00
|
|
|
"for name=%s", newname, exc_info=True)
|
|
|
|
|
|
|
|
|
2017-07-06 00:51:18 +08:00
|
|
|
# Enable/Disable container source URL entry on checkbox click
|
|
|
|
def _container_source_toggle(self, ignore):
|
|
|
|
enable_src = self.widget("install-oscontainer-bootstrap").get_active()
|
|
|
|
self.widget("install-oscontainer-source").set_sensitive(enable_src)
|
2017-12-20 00:32:18 +08:00
|
|
|
self.widget("install-oscontainer-rootpw-box").set_sensitive(enable_src)
|
2017-07-06 00:51:18 +08:00
|
|
|
|
2017-07-24 16:26:45 +08:00
|
|
|
# Auto-generate a path if not specified
|
|
|
|
if enable_src and not self.widget("install-oscontainer-fs").get_text():
|
2020-02-06 03:58:51 +08:00
|
|
|
fs_dir = ['/var/lib/libvirt/filesystems/']
|
|
|
|
if os.geteuid() != 0:
|
|
|
|
fs_dir = [os.path.expanduser("~"),
|
2017-07-24 16:26:45 +08:00
|
|
|
'.local/share/libvirt/filesystems/']
|
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
guest = self._gdata.build_guest()
|
|
|
|
default_name = virtinst.Guest.generate_name(guest)
|
2019-06-11 23:51:27 +08:00
|
|
|
fs = fs_dir + [default_name]
|
2017-07-24 16:26:45 +08:00
|
|
|
self.widget("install-oscontainer-fs").set_text(os.path.join(*fs))
|
|
|
|
|
2017-07-06 00:51:18 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
########################
|
|
|
|
# Misc helper routines #
|
|
|
|
########################
|
|
|
|
|
|
|
|
def _browse_file(self, cbwidget, cb=None, 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 cb:
|
|
|
|
callback = cb
|
|
|
|
else:
|
|
|
|
def callback(ignore, text):
|
|
|
|
widget = cbwidget
|
2017-10-11 19:35:41 +08:00
|
|
|
if isinstance(cbwidget, str):
|
2015-09-13 01:03:51 +08:00
|
|
|
widget = self.widget(cbwidget)
|
|
|
|
widget.set_text(text)
|
|
|
|
|
2015-09-14 00:45:35 +08:00
|
|
|
if self._storage_browser and self._storage_browser.conn != self.conn:
|
|
|
|
self._storage_browser.cleanup()
|
|
|
|
self._storage_browser = None
|
|
|
|
if self._storage_browser is None:
|
|
|
|
self._storage_browser = vmmStorageBrowser(self.conn)
|
2015-09-13 01:03:51 +08:00
|
|
|
|
2015-09-14 00:45:35 +08:00
|
|
|
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)
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
######################
|
|
|
|
# Navigation methods #
|
|
|
|
######################
|
|
|
|
|
|
|
|
def _set_page_num_text(self, cur):
|
|
|
|
"""
|
|
|
|
Set the 'page 1 of 4' style text in the wizard header
|
|
|
|
"""
|
|
|
|
cur += 1
|
|
|
|
final = PAGE_FINISH + 1
|
|
|
|
if self._should_skip_disk_page():
|
|
|
|
final -= 1
|
|
|
|
cur = min(cur, final)
|
|
|
|
|
2020-02-02 06:16:45 +08:00
|
|
|
page_lbl = (_("Step %(current_page)d of %(max_page)d") %
|
2015-09-13 01:03:51 +08:00
|
|
|
{'current_page': cur, 'max_page': final})
|
|
|
|
|
|
|
|
self.widget("header-pagenum").set_markup(page_lbl)
|
|
|
|
|
2018-09-30 04:04:05 +08:00
|
|
|
def _change_os_detect(self, sensitive):
|
|
|
|
self._os_list.set_sensitive(sensitive)
|
|
|
|
if not sensitive and not self._os_list.get_selected_os():
|
|
|
|
self._os_list.search_entry.set_text(
|
|
|
|
_("Waiting for install media / source"))
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _set_install_page(self):
|
|
|
|
instpage = self._get_config_install_page()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2018-09-30 04:04:05 +08:00
|
|
|
# Setting OS value for container doesn't matter presently
|
|
|
|
self.widget("install-os-distro-box").set_visible(
|
|
|
|
not self._is_container_install())
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2018-09-30 04:04:05 +08:00
|
|
|
enabledetect = False
|
|
|
|
if instpage == INSTALL_PAGE_URL:
|
|
|
|
enabledetect = True
|
|
|
|
elif instpage == INSTALL_PAGE_ISO and not self.conn.is_remote():
|
|
|
|
enabledetect = True
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2018-09-30 04:04:05 +08:00
|
|
|
self.widget("install-detect-os-box").set_visible(enabledetect)
|
|
|
|
dodetect = (enabledetect and
|
|
|
|
self.widget("install-detect-os").get_active())
|
|
|
|
self._change_os_detect(not dodetect)
|
2011-06-08 05:42:50 +08:00
|
|
|
|
2020-01-26 22:52:18 +08:00
|
|
|
# Manual installs have nothing to ask for
|
2020-01-26 23:24:38 +08:00
|
|
|
has_install = instpage != INSTALL_PAGE_MANUAL
|
|
|
|
self.widget("install-method-pages").set_visible(has_install)
|
|
|
|
if not has_install:
|
|
|
|
self._os_list.search_entry.grab_focus()
|
2018-09-30 04:04:05 +08:00
|
|
|
self.widget("install-method-pages").set_current_page(instpage)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _back_clicked(self, src_ignore):
|
2011-07-15 01:13:13 +08:00
|
|
|
notebook = self.widget("create-pages")
|
2009-03-10 04:16:45 +08:00
|
|
|
curpage = notebook.get_current_page()
|
2010-06-02 22:07:34 +08:00
|
|
|
next_page = curpage - 1
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
if curpage == PAGE_FINISH and self._should_skip_disk_page():
|
2010-06-02 22:07:34 +08:00
|
|
|
# Skip over storage page
|
|
|
|
next_page -= 1
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2010-06-02 22:07:34 +08:00
|
|
|
notebook.set_current_page(next_page)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2011-07-19 09:31:06 +08:00
|
|
|
def _get_next_pagenum(self, curpage):
|
|
|
|
next_page = curpage + 1
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
if next_page == PAGE_STORAGE and self._should_skip_disk_page():
|
2011-07-19 09:31:06 +08:00
|
|
|
# Skip storage page for import installs
|
|
|
|
next_page += 1
|
|
|
|
|
|
|
|
return next_page
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _forward_clicked(self, src_ignore=None):
|
2011-07-15 01:13:13 +08:00
|
|
|
notebook = self.widget("create-pages")
|
2009-03-10 04:16:45 +08:00
|
|
|
curpage = notebook.get_current_page()
|
|
|
|
|
2015-09-13 03:14:40 +08:00
|
|
|
if curpage == PAGE_INSTALL:
|
2010-12-04 01:55:56 +08:00
|
|
|
# Make sure we have detected the OS before validating the page
|
2015-09-13 03:14:40 +08:00
|
|
|
did_start = self._start_detect_os_if_needed(
|
|
|
|
forward_after_finish=True)
|
|
|
|
if did_start:
|
|
|
|
return
|
2010-12-04 01:55:56 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
if self._validate(curpage) is not True:
|
2009-03-10 04:16:45 +08:00
|
|
|
return
|
|
|
|
|
2020-01-26 23:24:38 +08:00
|
|
|
self.widget("create-forward").grab_focus()
|
2009-03-10 04:16:45 +08:00
|
|
|
if curpage == PAGE_NAME:
|
2015-09-13 01:03:51 +08:00
|
|
|
self._set_install_page()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2011-07-19 09:31:06 +08:00
|
|
|
next_page = self._get_next_pagenum(curpage)
|
2010-03-23 06:15:18 +08:00
|
|
|
notebook.set_current_page(next_page)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _page_changed(self, ignore1, ignore2, pagenum):
|
2018-09-30 04:04:05 +08:00
|
|
|
if pagenum == PAGE_FINISH:
|
2014-06-01 01:31:08 +08:00
|
|
|
try:
|
2015-09-13 01:03:51 +08:00
|
|
|
self._populate_summary()
|
2020-02-06 03:58:51 +08:00
|
|
|
except Exception as e: # pragma: no cover
|
2014-06-01 01:31:08 +08:00
|
|
|
self.err.show_err(_("Error populating summary page: %s") %
|
|
|
|
str(e))
|
|
|
|
return
|
|
|
|
|
2013-10-03 00:12:26 +08:00
|
|
|
self.widget("create-finish").grab_focus()
|
2014-06-01 01:31:08 +08:00
|
|
|
|
|
|
|
self.widget("create-back").set_sensitive(pagenum != PAGE_NAME)
|
|
|
|
self.widget("create-forward").set_visible(pagenum != PAGE_FINISH)
|
|
|
|
self.widget("create-finish").set_visible(pagenum == PAGE_FINISH)
|
2013-10-03 00:12:26 +08:00
|
|
|
|
2015-09-13 03:14:40 +08:00
|
|
|
# Hide all other pages, so the dialog isn't all stretched out
|
|
|
|
# because of one large page.
|
2013-10-03 00:12:26 +08:00
|
|
|
for nr in range(self.widget("create-pages").get_n_pages()):
|
|
|
|
page = self.widget("create-pages").get_nth_page(nr)
|
|
|
|
page.set_visible(nr == pagenum)
|
2010-12-05 01:28:44 +08:00
|
|
|
|
2020-09-09 20:41:27 +08:00
|
|
|
self._set_page_num_text(pagenum)
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
############################
|
|
|
|
# Page validation routines #
|
|
|
|
############################
|
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
def _build_guestdata(self):
|
|
|
|
gdata = _GuestData(self.conn.get_backend(), self._capsinfo)
|
2010-02-06 06:58:26 +08:00
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
gdata.default_graphics_type = self.config.get_graphics_type()
|
|
|
|
gdata.x86_cpu_default = self.config.get_default_cpu_setting()
|
2010-02-06 06:58:26 +08:00
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
return gdata
|
2010-02-06 06:58:26 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _validate(self, pagenum):
|
2009-03-10 04:16:45 +08:00
|
|
|
try:
|
|
|
|
if pagenum == PAGE_NAME:
|
2015-09-13 01:03:51 +08:00
|
|
|
return self._validate_intro_page()
|
2009-03-10 04:16:45 +08:00
|
|
|
elif pagenum == PAGE_INSTALL:
|
2015-09-13 01:03:51 +08:00
|
|
|
return self._validate_install_page()
|
2009-03-10 04:16:45 +08:00
|
|
|
elif pagenum == PAGE_MEM:
|
2015-09-13 01:03:51 +08:00
|
|
|
return self._validate_mem_page()
|
2009-03-10 04:16:45 +08:00
|
|
|
elif pagenum == PAGE_STORAGE:
|
2015-09-13 01:03:51 +08:00
|
|
|
return self._validate_storage_page()
|
2009-03-10 04:16:45 +08:00
|
|
|
elif pagenum == PAGE_FINISH:
|
2015-09-13 01:03:51 +08:00
|
|
|
return self._validate_final_page()
|
2020-08-29 08:30:03 +08:00
|
|
|
except Exception as e: # pragma: no cover
|
2009-03-10 04:16:45 +08:00
|
|
|
self.err.show_err(_("Uncaught error validating install "
|
2011-04-06 23:22:03 +08:00
|
|
|
"parameters: %s") % str(e))
|
2009-03-10 04:16:45 +08:00
|
|
|
return
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _validate_intro_page(self):
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata.machine = self._get_config_machine()
|
|
|
|
return bool(self._gdata.build_guest())
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2020-08-24 02:05:24 +08:00
|
|
|
def _validate_oscontainer_bootstrap(self, fs, src_url, user, passwd):
|
|
|
|
# Check if the source path was provided
|
|
|
|
if not src_url:
|
|
|
|
return self.err.val_err(_("Source URL is required"))
|
|
|
|
|
|
|
|
# Require username and password when authenticate
|
|
|
|
# to source registry.
|
|
|
|
if user and not passwd:
|
2020-08-24 02:15:17 +08:00
|
|
|
msg = _("Please specify password for accessing source registry")
|
|
|
|
return self.err.val_err(msg)
|
2020-08-24 02:05:24 +08:00
|
|
|
|
|
|
|
# Validate destination path
|
|
|
|
if not os.path.exists(fs):
|
2020-08-29 08:30:03 +08:00
|
|
|
return # pragma: no cover
|
2020-08-24 02:05:24 +08:00
|
|
|
|
|
|
|
if not os.path.isdir(fs):
|
2020-08-24 02:15:17 +08:00
|
|
|
msg = _("Destination path is not directory: %s") % fs
|
|
|
|
return self.err.val_err(msg)
|
2020-08-24 02:05:24 +08:00
|
|
|
if not os.access(fs, os.W_OK):
|
2020-08-24 02:15:17 +08:00
|
|
|
msg = _("No write permissions for directory path: %s") % fs
|
|
|
|
return self.err.val_err(msg)
|
2020-08-24 02:05:24 +08:00
|
|
|
if os.listdir(fs) == []:
|
|
|
|
return
|
|
|
|
|
|
|
|
# Show Yes/No dialog if the destination is not empty
|
|
|
|
return self.err.yes_no(
|
|
|
|
_("OS root directory is not empty"),
|
|
|
|
_("Creating root file system in a non-empty "
|
|
|
|
"directory might fail due to file conflicts.\n"
|
|
|
|
"Would you like to continue?"))
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _validate_install_page(self):
|
|
|
|
instmethod = self._get_config_install_page()
|
2009-03-10 04:16:45 +08:00
|
|
|
installer = None
|
|
|
|
location = None
|
|
|
|
extra = None
|
2018-10-13 06:35:09 +08:00
|
|
|
cdrom = None
|
2010-03-23 06:15:18 +08:00
|
|
|
is_import = False
|
2011-06-08 05:42:50 +08:00
|
|
|
init = None
|
2011-06-21 23:04:22 +08:00
|
|
|
fs = None
|
2017-03-13 20:01:51 +08:00
|
|
|
template = None
|
2018-09-30 04:04:05 +08:00
|
|
|
osobj = self._os_list.get_selected_os()
|
2014-04-24 22:58:11 +08:00
|
|
|
|
2009-03-10 04:16:45 +08:00
|
|
|
if instmethod == INSTALL_PAGE_ISO:
|
2015-09-13 01:03:51 +08:00
|
|
|
media = self._get_config_local_media()
|
2009-03-10 04:16:45 +08:00
|
|
|
if not media:
|
2020-08-24 02:15:17 +08:00
|
|
|
msg = _("An install media selection is required.")
|
|
|
|
return self.err.val_err(msg)
|
2018-10-13 06:35:09 +08:00
|
|
|
cdrom = media
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
elif instmethod == INSTALL_PAGE_URL:
|
2015-11-22 09:21:09 +08:00
|
|
|
media, extra = self._get_config_url_info()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
if not media:
|
2011-08-31 02:50:50 +08:00
|
|
|
return self.err.val_err(_("An install tree is required."))
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
location = media
|
|
|
|
|
2010-03-23 06:15:18 +08:00
|
|
|
elif instmethod == INSTALL_PAGE_IMPORT:
|
|
|
|
is_import = True
|
2015-09-13 01:03:51 +08:00
|
|
|
import_path = self._get_config_import_path()
|
2010-03-23 06:15:18 +08:00
|
|
|
if not import_path:
|
2020-08-24 02:15:17 +08:00
|
|
|
msg = _("A storage path to import is required.")
|
|
|
|
return self.err.val_err(msg)
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2018-03-21 00:18:35 +08:00
|
|
|
if not virtinst.DeviceDisk.path_definitely_exists(
|
2016-06-07 19:55:58 +08:00
|
|
|
self.conn.get_backend(),
|
|
|
|
import_path):
|
2020-08-24 02:15:17 +08:00
|
|
|
msg = _("The import path must point to an existing storage.")
|
|
|
|
return self.err.val_err(msg)
|
2016-06-07 19:55:58 +08:00
|
|
|
|
2011-06-08 05:42:50 +08:00
|
|
|
elif instmethod == INSTALL_PAGE_CONTAINER_APP:
|
2015-09-13 01:03:51 +08:00
|
|
|
init = self.widget("install-app-entry").get_text()
|
2011-06-08 05:42:50 +08:00
|
|
|
if not init:
|
2011-08-31 02:50:50 +08:00
|
|
|
return self.err.val_err(_("An application path is required."))
|
2011-06-08 05:42:50 +08:00
|
|
|
|
2011-06-21 23:04:22 +08:00
|
|
|
elif instmethod == INSTALL_PAGE_CONTAINER_OS:
|
2015-09-13 01:03:51 +08:00
|
|
|
fs = self.widget("install-oscontainer-fs").get_text()
|
2011-06-21 23:04:22 +08:00
|
|
|
if not fs:
|
2011-08-31 02:50:50 +08:00
|
|
|
return self.err.val_err(_("An OS directory path is required."))
|
2011-06-21 23:04:22 +08:00
|
|
|
|
2017-07-06 00:51:19 +08:00
|
|
|
if self._get_config_oscontainer_bootstrap():
|
|
|
|
src_url = self._get_config_oscontainer_source_url()
|
|
|
|
user = self._get_config_oscontainer_source_username()
|
|
|
|
passwd = self._get_config_oscontainer_source_password()
|
2020-08-24 02:05:24 +08:00
|
|
|
ret = self._validate_oscontainer_bootstrap(
|
|
|
|
fs, src_url, user, passwd)
|
|
|
|
if ret is False:
|
|
|
|
return False
|
2017-07-06 00:51:19 +08:00
|
|
|
|
2017-03-13 20:01:51 +08:00
|
|
|
elif instmethod == INSTALL_PAGE_VZ_TEMPLATE:
|
|
|
|
template = self.widget("install-container-template").get_text()
|
|
|
|
if not template:
|
|
|
|
return self.err.val_err(_("A template name is required."))
|
|
|
|
|
2020-08-29 08:30:03 +08:00
|
|
|
if not self._is_container_install() and not osobj:
|
|
|
|
msg = _("You must select an OS.")
|
|
|
|
msg += "\n\n" + self._os_list.eol_text
|
|
|
|
return self.err.val_err(msg)
|
|
|
|
|
2020-08-24 02:26:51 +08:00
|
|
|
# Build the installer and Guest instance
|
2009-03-10 04:16:45 +08:00
|
|
|
try:
|
2011-06-08 05:42:50 +08:00
|
|
|
if init:
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata.init = init
|
2011-06-08 05:42:50 +08:00
|
|
|
|
2011-06-21 23:04:22 +08:00
|
|
|
if fs:
|
2020-01-30 00:25:12 +08:00
|
|
|
fsdev = virtinst.DeviceFilesystem(self._gdata.conn)
|
2011-06-21 23:04:22 +08:00
|
|
|
fsdev.target = "/"
|
|
|
|
fsdev.source = fs
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata.filesystem = fsdev
|
2017-03-13 20:01:51 +08:00
|
|
|
|
|
|
|
if template:
|
2020-01-30 00:25:12 +08:00
|
|
|
fsdev = virtinst.DeviceFilesystem(self._gdata.conn)
|
2017-03-13 20:01:51 +08:00
|
|
|
fsdev.target = "/"
|
|
|
|
fsdev.type = "template"
|
|
|
|
fsdev.source = template
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata.filesystem = fsdev
|
2017-03-13 20:01:51 +08:00
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata.location = location
|
|
|
|
self._gdata.cdrom = cdrom
|
|
|
|
self._gdata.extra_args = extra
|
|
|
|
self._gdata.livecd = False
|
|
|
|
self._gdata.os_variant = osobj and osobj.name or None
|
|
|
|
guest = self._gdata.build_guest()
|
|
|
|
installer = self._gdata.build_installer()
|
|
|
|
except Exception as e:
|
2020-08-24 02:15:17 +08:00
|
|
|
msg = _("Error setting installer parameters.")
|
|
|
|
return self.err.val_err(msg, e)
|
2020-01-30 00:25:12 +08:00
|
|
|
|
2013-10-02 03:18:34 +08:00
|
|
|
try:
|
2020-01-30 00:25:12 +08:00
|
|
|
name = virtinst.Guest.generate_name(guest)
|
|
|
|
virtinst.Guest.validate_name(self._gdata.conn, name)
|
|
|
|
self._gdata.name = name
|
2020-08-29 08:30:03 +08:00
|
|
|
except Exception as e: # pragma: no cover
|
2013-10-02 03:18:34 +08:00
|
|
|
return self.err.val_err(_("Error setting default name."), e)
|
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
self.widget("create-vm-name").set_text(self._gdata.name)
|
|
|
|
|
2010-03-23 06:15:18 +08:00
|
|
|
# Kind of wonky, run storage validation now, which will assign
|
|
|
|
# the import path. Import installer skips the storage page.
|
|
|
|
if is_import:
|
2015-09-13 01:03:51 +08:00
|
|
|
if not self._validate_storage_page():
|
2010-03-23 06:15:18 +08:00
|
|
|
return False
|
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
for path in installer.get_search_paths(guest):
|
2015-09-14 00:45:35 +08:00
|
|
|
self._addstorage.check_path_search(
|
2014-01-29 05:53:11 +08:00
|
|
|
self, self.conn, path)
|
2009-12-02 01:41:45 +08:00
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
res = guest.osinfo.get_recommended_resources()
|
|
|
|
ram = res.get_recommended_ram(guest.os.arch)
|
|
|
|
n_cpus = res.get_recommended_ncpus(guest.os.arch)
|
|
|
|
storage = res.get_recommended_storage(guest.os.arch)
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Recommended resources for os=%s: "
|
2019-05-12 06:05:59 +08:00
|
|
|
"ram=%s ncpus=%s storage=%s",
|
2020-01-30 00:25:12 +08:00
|
|
|
guest.osinfo.name, ram, n_cpus, storage)
|
2014-02-17 23:40:05 +08:00
|
|
|
|
|
|
|
# Change the default values suggested to the user.
|
|
|
|
ram_size = DEFAULT_MEM
|
2019-05-12 06:05:59 +08:00
|
|
|
if ram:
|
|
|
|
ram_size = ram // (1024 ** 2)
|
2015-09-14 06:01:39 +08:00
|
|
|
self.widget("mem").set_value(ram_size)
|
2014-02-17 23:40:05 +08:00
|
|
|
|
2019-05-12 06:05:59 +08:00
|
|
|
self.widget("cpus").set_value(n_cpus or 1)
|
2014-02-17 23:40:05 +08:00
|
|
|
|
2019-05-12 06:05:59 +08:00
|
|
|
if storage:
|
|
|
|
storage_size = storage // (1024 ** 3)
|
2015-09-14 07:30:10 +08:00
|
|
|
self._addstorage.widget("storage-size").set_value(storage_size)
|
2014-02-17 23:40:05 +08:00
|
|
|
|
2009-05-11 23:00:03 +08:00
|
|
|
# Validation passed, store the install path (if there is one) in
|
2014-09-28 19:37:16 +08:00
|
|
|
# gsettings
|
2017-07-06 00:51:21 +08:00
|
|
|
self._get_config_oscontainer_source_url(store_media=True)
|
2015-09-13 01:03:51 +08:00
|
|
|
self._get_config_local_media(store_media=True)
|
|
|
|
self._get_config_url_info(store_media=True)
|
2009-03-10 04:16:45 +08:00
|
|
|
return True
|
2007-02-02 03:16:44 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
def _validate_mem_page(self):
|
2015-09-14 06:01:39 +08:00
|
|
|
cpus = self.widget("cpus").get_value()
|
|
|
|
mem = self.widget("mem").get_value()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata.vcpus = int(cpus)
|
|
|
|
self._gdata.currentMemory = int(mem) * 1024
|
|
|
|
self._gdata.memory = int(mem) * 1024
|
2009-03-10 04:16:45 +08:00
|
|
|
|
|
|
|
return True
|
|
|
|
|
2015-09-15 04:22:17 +08:00
|
|
|
def _get_storage_path(self, vmname, do_log):
|
2015-09-07 02:42:55 +08:00
|
|
|
failed_disk = None
|
2020-01-30 00:25:12 +08:00
|
|
|
if self._gdata.failed_guest:
|
|
|
|
failed_disk = self._gdata.disk
|
2010-12-08 05:48:13 +08:00
|
|
|
|
2014-01-29 05:53:11 +08:00
|
|
|
path = None
|
2015-09-07 02:42:55 +08:00
|
|
|
path_already_created = False
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
if self._get_config_install_page() == INSTALL_PAGE_IMPORT:
|
|
|
|
path = self._get_config_import_path()
|
2015-09-07 02:42:55 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
elif self._is_default_storage():
|
2015-09-15 04:05:58 +08:00
|
|
|
if failed_disk:
|
|
|
|
# Don't generate a new path if the install failed
|
2020-11-12 04:38:34 +08:00
|
|
|
path = failed_disk.get_source_path()
|
2015-09-07 02:42:55 +08:00
|
|
|
path_already_created = failed_disk.storage_was_created
|
2015-09-15 04:22:17 +08:00
|
|
|
if do_log:
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Reusing failed disk path=%s "
|
2015-09-15 04:22:17 +08:00
|
|
|
"already_created=%s", path, path_already_created)
|
2015-09-07 02:42:55 +08:00
|
|
|
else:
|
2015-09-15 04:22:17 +08:00
|
|
|
path = self._addstorage.get_default_path(vmname)
|
|
|
|
if do_log:
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Default storage path is: %s", path)
|
2015-09-15 04:22:17 +08:00
|
|
|
|
|
|
|
return path, path_already_created
|
|
|
|
|
|
|
|
def _validate_storage_page(self):
|
|
|
|
path, path_already_created = self._get_storage_path(
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata.name, do_log=True)
|
2012-02-14 03:49:00 +08:00
|
|
|
|
2015-09-15 04:05:58 +08:00
|
|
|
disk = None
|
2015-09-14 06:42:10 +08:00
|
|
|
storage_enabled = self.widget("enable-storage").get_active()
|
2015-09-14 04:02:35 +08:00
|
|
|
try:
|
2015-09-14 06:42:10 +08:00
|
|
|
if storage_enabled:
|
2019-04-15 07:30:42 +08:00
|
|
|
disk = self._addstorage.build_device(
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata.name, path=path)
|
2019-04-15 07:30:42 +08:00
|
|
|
|
|
|
|
if disk and self._addstorage.validate_device(disk) is False:
|
|
|
|
return False
|
2017-05-06 00:47:21 +08:00
|
|
|
except Exception as e:
|
2015-09-14 04:02:35 +08:00
|
|
|
return self.err.val_err(_("Storage parameter error."), e)
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
if self._get_config_install_page() == INSTALL_PAGE_ISO:
|
2014-01-29 05:53:11 +08:00
|
|
|
# CD/ISO install and no disks implies LiveCD
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata.livecd = not storage_enabled
|
2015-09-15 04:05:58 +08:00
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata.disk = disk
|
2015-09-14 06:42:10 +08:00
|
|
|
if not storage_enabled:
|
|
|
|
return True
|
2009-09-24 23:41:49 +08:00
|
|
|
|
2015-09-15 04:05:58 +08:00
|
|
|
disk.storage_was_created = path_already_created
|
2009-09-24 23:41:49 +08:00
|
|
|
return True
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
def _validate_final_page(self):
|
2010-12-08 03:20:11 +08:00
|
|
|
# HV + Arch selection
|
2015-09-13 01:03:51 +08:00
|
|
|
name = self._get_config_name()
|
2020-01-30 00:25:12 +08:00
|
|
|
if name != self._gdata.name:
|
2015-04-03 05:54:47 +08:00
|
|
|
try:
|
2020-01-30 00:25:12 +08:00
|
|
|
virtinst.Guest.validate_name(self._gdata.conn, name)
|
|
|
|
self._gdata.name = name
|
2017-05-06 00:47:21 +08:00
|
|
|
except Exception as e:
|
2015-04-03 05:54:47 +08:00
|
|
|
return self.err.val_err(_("Invalid guest name"), str(e))
|
2015-09-13 01:03:51 +08:00
|
|
|
if self._is_default_storage():
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("User changed VM name and using default "
|
2015-05-04 04:37:42 +08:00
|
|
|
"storage, re-validating with new default storage path.")
|
2015-09-13 01:03:51 +08:00
|
|
|
if not self._validate_storage_page():
|
2020-08-29 08:30:03 +08:00
|
|
|
return False # pragma: no cover
|
2010-12-08 03:20:11 +08:00
|
|
|
|
2018-03-21 00:18:35 +08:00
|
|
|
macaddr = virtinst.DeviceInterface.generate_mac(
|
2015-04-08 06:52:35 +08:00
|
|
|
self.conn.get_backend())
|
2019-04-15 07:46:51 +08:00
|
|
|
|
|
|
|
net = self._netlist.build_device(macaddr)
|
2020-08-25 02:10:49 +08:00
|
|
|
|
|
|
|
self._netlist.validate_device(net)
|
|
|
|
self._gdata.interface = net
|
2009-03-10 04:16:45 +08:00
|
|
|
return True
|
|
|
|
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
#############################
|
|
|
|
# Distro detection handling #
|
|
|
|
#############################
|
|
|
|
|
2018-09-30 04:04:05 +08:00
|
|
|
def _start_detect_os_if_needed(self, forward_after_finish=False):
|
2015-09-13 03:14:40 +08:00
|
|
|
"""
|
|
|
|
Will kick off the OS detection thread if all conditions are met,
|
|
|
|
like we actually have media to detect, detection isn't already
|
|
|
|
in progress, etc.
|
|
|
|
|
|
|
|
Returns True if we actually start the detection process
|
|
|
|
"""
|
|
|
|
is_install_page = (self.widget("create-pages").get_current_page() ==
|
|
|
|
PAGE_INSTALL)
|
2019-02-04 05:03:56 +08:00
|
|
|
cdrom, location = self._get_config_detectable_media()
|
2015-09-13 03:14:40 +08:00
|
|
|
|
|
|
|
if self._detect_os_in_progress:
|
2020-08-29 08:30:03 +08:00
|
|
|
return # pragma: no cover
|
2018-09-30 04:04:05 +08:00
|
|
|
if not is_install_page:
|
2020-08-29 08:30:03 +08:00
|
|
|
return # pragma: no cover
|
2019-02-04 05:03:56 +08:00
|
|
|
if not cdrom and not location:
|
2015-09-13 03:14:40 +08:00
|
|
|
return
|
|
|
|
if not self._is_os_detect_active():
|
|
|
|
return
|
|
|
|
if self._os_already_detected_for_media:
|
2015-09-13 01:03:51 +08:00
|
|
|
return
|
|
|
|
|
2019-02-04 05:03:56 +08:00
|
|
|
self._do_start_detect_os(cdrom, location, forward_after_finish)
|
2015-09-13 03:14:40 +08:00
|
|
|
return True
|
2015-09-13 01:03:51 +08:00
|
|
|
|
2019-02-04 05:03:56 +08:00
|
|
|
def _do_start_detect_os(self, cdrom, location, forward_after_finish):
|
2015-09-13 03:14:40 +08:00
|
|
|
self._detect_os_in_progress = False
|
2015-09-13 01:03:51 +08:00
|
|
|
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Starting OS detection thread for cdrom=%s location=%s",
|
2019-02-04 05:03:56 +08:00
|
|
|
cdrom, location)
|
2015-09-13 03:14:40 +08:00
|
|
|
self.widget("create-forward").set_sensitive(False)
|
2015-09-13 01:03:51 +08:00
|
|
|
|
2015-09-13 03:14:40 +08:00
|
|
|
class ThreadResults(object):
|
|
|
|
"""
|
|
|
|
Helper object to track results from the detection thread
|
|
|
|
"""
|
|
|
|
_DETECT_FAILED = 1
|
|
|
|
_DETECT_INPROGRESS = 2
|
|
|
|
def __init__(self):
|
|
|
|
self._results = self._DETECT_INPROGRESS
|
|
|
|
|
|
|
|
def in_progress(self):
|
|
|
|
return self._results == self._DETECT_INPROGRESS
|
|
|
|
|
|
|
|
def set_failed(self):
|
|
|
|
self._results = self._DETECT_FAILED
|
|
|
|
|
|
|
|
def set_distro(self, distro):
|
|
|
|
self._results = distro
|
|
|
|
def get_distro(self):
|
|
|
|
if self._results == self._DETECT_FAILED:
|
|
|
|
return None
|
|
|
|
return self._results
|
|
|
|
|
|
|
|
thread_results = ThreadResults()
|
|
|
|
detectThread = threading.Thread(target=self._detect_thread_cb,
|
|
|
|
name="Actual media detection",
|
2019-02-04 05:03:56 +08:00
|
|
|
args=(cdrom, location, thread_results))
|
2022-01-12 01:32:02 +08:00
|
|
|
detectThread.daemon = True
|
2015-09-13 03:14:40 +08:00
|
|
|
detectThread.start()
|
2015-09-13 01:03:51 +08:00
|
|
|
|
2018-09-30 04:04:05 +08:00
|
|
|
self._os_list.search_entry.set_text(_("Detecting..."))
|
2018-05-01 19:51:23 +08:00
|
|
|
spin = self.widget("install-detect-os-spinner")
|
|
|
|
spin.start()
|
|
|
|
|
2015-09-13 03:14:40 +08:00
|
|
|
self._report_detect_os_progress(0, thread_results,
|
|
|
|
forward_after_finish)
|
2015-09-13 01:03:51 +08:00
|
|
|
|
2019-02-04 05:03:56 +08:00
|
|
|
def _detect_thread_cb(self, cdrom, location, thread_results):
|
2015-09-13 03:14:40 +08:00
|
|
|
"""
|
|
|
|
Thread callback that does the actual detection
|
|
|
|
"""
|
|
|
|
try:
|
2018-10-13 06:35:09 +08:00
|
|
|
installer = virtinst.Installer(self.conn.get_backend(),
|
2019-02-04 05:03:56 +08:00
|
|
|
cdrom=cdrom,
|
|
|
|
location=location)
|
2020-01-30 00:25:12 +08:00
|
|
|
distro = installer.detect_distro(self._gdata.build_guest())
|
2015-09-13 03:14:40 +08:00
|
|
|
thread_results.set_distro(distro)
|
2017-07-24 16:26:48 +08:00
|
|
|
except Exception:
|
2019-06-17 09:12:39 +08:00
|
|
|
log.exception("Error detecting distro.")
|
2015-09-13 03:14:40 +08:00
|
|
|
thread_results.set_failed()
|
2015-09-13 01:03:51 +08:00
|
|
|
|
2015-09-13 03:14:40 +08:00
|
|
|
def _report_detect_os_progress(self, idx, thread_results,
|
|
|
|
forward_after_finish):
|
|
|
|
"""
|
|
|
|
Checks detection progress via the _detect_os_results variable
|
|
|
|
and updates the UI labels, counts the number of iterations,
|
|
|
|
etc.
|
|
|
|
|
|
|
|
We set a hard time limit on the distro detection to avoid the
|
|
|
|
chance of the detection hanging (like slow URL lookup)
|
|
|
|
"""
|
2015-09-13 01:03:51 +08:00
|
|
|
try:
|
2015-09-13 03:14:40 +08:00
|
|
|
if (thread_results.in_progress() and
|
2015-09-13 01:03:51 +08:00
|
|
|
(idx < (DETECT_TIMEOUT * 2))):
|
2015-09-13 03:14:40 +08:00
|
|
|
# Thread is still going and we haven't hit the timeout yet,
|
|
|
|
# so update the UI labels and reschedule this function
|
|
|
|
self.timeout_add(500, self._report_detect_os_progress,
|
|
|
|
idx + 1, thread_results, forward_after_finish)
|
2015-09-13 01:03:51 +08:00
|
|
|
return
|
|
|
|
|
2015-09-13 03:14:40 +08:00
|
|
|
distro = thread_results.get_distro()
|
2020-08-29 08:30:03 +08:00
|
|
|
except Exception: # pragma: no cover
|
2015-09-13 03:14:40 +08:00
|
|
|
distro = None
|
2019-06-17 09:12:39 +08:00
|
|
|
log.exception("Error in distro detect timeout")
|
2015-09-13 01:03:51 +08:00
|
|
|
|
2018-05-01 19:51:23 +08:00
|
|
|
spin = self.widget("install-detect-os-spinner")
|
|
|
|
spin.stop()
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Finished UI OS detection.")
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
self.widget("create-forward").set_sensitive(True)
|
2015-09-13 03:14:40 +08:00
|
|
|
self._os_already_detected_for_media = True
|
|
|
|
self._detect_os_in_progress = False
|
2018-09-30 04:04:05 +08:00
|
|
|
|
|
|
|
if not self._is_os_detect_active():
|
|
|
|
# If the user changed the OS detect checkbox in the meantime,
|
|
|
|
# don't update the UI
|
2020-08-29 08:30:03 +08:00
|
|
|
return # pragma: no cover
|
2018-09-30 04:04:05 +08:00
|
|
|
|
|
|
|
if distro:
|
|
|
|
self._os_list.select_os(virtinst.OSDB.lookup_os(distro))
|
|
|
|
else:
|
|
|
|
self._os_list.reset_state()
|
|
|
|
self._os_list.search_entry.set_text(_("None detected"))
|
2015-09-13 01:03:51 +08:00
|
|
|
|
2015-09-13 03:14:40 +08:00
|
|
|
if forward_after_finish:
|
|
|
|
self.idle_add(self._forward_clicked, ())
|
2015-09-13 01:03:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
##########################
|
|
|
|
# Guest install routines #
|
|
|
|
##########################
|
|
|
|
|
|
|
|
def _finish_clicked(self, src_ignore):
|
2010-02-06 06:58:26 +08:00
|
|
|
# Validate the final page
|
2011-07-15 01:13:13 +08:00
|
|
|
page = self.widget("create-pages").get_current_page()
|
2015-09-13 01:03:51 +08:00
|
|
|
if self._validate(page) is not True:
|
2020-08-29 08:30:03 +08:00
|
|
|
return
|
2008-09-03 00:09:39 +08:00
|
|
|
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Starting create finish() sequence")
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata.failed_guest = None
|
2015-11-22 08:25:02 +08:00
|
|
|
|
|
|
|
try:
|
2020-01-30 00:25:12 +08:00
|
|
|
guest = self._gdata.build_guest()
|
|
|
|
installer = self._gdata.build_installer()
|
2018-09-02 22:26:20 +08:00
|
|
|
self.set_finish_cursor()
|
|
|
|
|
|
|
|
# This encodes all the virtinst defaults up front, so the customize
|
|
|
|
# dialog actually shows disk buses, cache values, default devices,
|
|
|
|
# etc. Not required for straight start_install but doesn't hurt.
|
2020-01-30 00:25:12 +08:00
|
|
|
installer.set_install_defaults(guest)
|
2018-09-02 22:26:20 +08:00
|
|
|
|
|
|
|
if not self.widget("summary-customize").get_active():
|
2020-01-30 00:25:12 +08:00
|
|
|
self._start_install(guest, installer)
|
2018-09-02 22:26:20 +08:00
|
|
|
return
|
|
|
|
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("User requested 'customize', launching dialog")
|
2020-01-30 00:25:12 +08:00
|
|
|
self._show_customize_dialog(guest, installer)
|
2020-08-29 08:30:03 +08:00
|
|
|
except Exception as e: # pragma: no cover
|
2017-04-28 03:00:17 +08:00
|
|
|
self.reset_finish_cursor()
|
2020-07-14 15:41:49 +08:00
|
|
|
self.err.show_err(_("Error starting installation: %s") % str(e))
|
2015-11-22 08:25:02 +08:00
|
|
|
return
|
|
|
|
|
|
|
|
def _cleanup_customize_window(self):
|
|
|
|
if not self._customize_window:
|
|
|
|
return
|
|
|
|
|
|
|
|
# We can re-enter this: cleanup() -> close() -> "details-closed"
|
|
|
|
window = self._customize_window
|
2020-09-09 00:27:38 +08:00
|
|
|
virtinst_domain = self._customize_window.vm
|
2015-11-22 08:25:02 +08:00
|
|
|
self._customize_window = None
|
|
|
|
window.cleanup()
|
2020-09-09 00:27:38 +08:00
|
|
|
virtinst_domain.cleanup()
|
|
|
|
virtinst_domain = None
|
2010-02-08 01:18:28 +08:00
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
def _show_customize_dialog(self, origguest, installer):
|
|
|
|
orig_vdomain = vmmDomainVirtinst(self.conn,
|
|
|
|
origguest, origguest.uuid, installer)
|
2010-02-08 01:18:28 +08:00
|
|
|
|
2019-05-09 04:13:40 +08:00
|
|
|
def customize_finished_cb(src, vdomain):
|
2010-12-08 03:20:11 +08:00
|
|
|
if not self.is_visible():
|
2020-08-29 08:30:03 +08:00
|
|
|
return # pragma: no cover
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("User finished customize dialog, starting install")
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata.failed_guest = None
|
|
|
|
self._start_install(vdomain.get_backend(), installer)
|
2010-12-08 03:20:11 +08:00
|
|
|
|
2019-05-09 04:13:40 +08:00
|
|
|
def config_canceled_cb(src):
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("User closed customize window, closing wizard")
|
2015-09-07 02:42:55 +08:00
|
|
|
self._close_requested()
|
2010-02-08 01:18:28 +08:00
|
|
|
|
2019-05-06 04:25:35 +08:00
|
|
|
# We specifically don't use vmmVMWindow.get_instance here since
|
|
|
|
# it's not a top level VM window
|
2015-11-22 08:25:02 +08:00
|
|
|
self._cleanup_customize_window()
|
2019-05-09 04:13:40 +08:00
|
|
|
self._customize_window = vmmVMWindow(orig_vdomain, self.topwin)
|
2015-11-22 08:25:02 +08:00
|
|
|
self._customize_window.connect(
|
2019-05-09 04:13:40 +08:00
|
|
|
"customize-finished", customize_finished_cb)
|
|
|
|
self._customize_window.connect("closed", config_canceled_cb)
|
2015-09-13 01:03:51 +08:00
|
|
|
self._customize_window.show()
|
2010-02-08 01:18:28 +08:00
|
|
|
|
2019-05-09 04:13:40 +08:00
|
|
|
def _install_finished_cb(self, error, details, guest, parentobj):
|
2017-04-28 03:00:17 +08:00
|
|
|
self.reset_finish_cursor(parentobj.topwin)
|
2009-04-04 02:15:15 +08:00
|
|
|
|
|
|
|
if error:
|
2010-12-10 22:57:42 +08:00
|
|
|
error = (_("Unable to complete install: '%s'") % error)
|
2015-11-22 08:25:02 +08:00
|
|
|
parentobj.err.show_err(error, details=details)
|
2020-01-30 00:25:12 +08:00
|
|
|
self._gdata.failed_guest = guest
|
2009-04-04 02:15:15 +08:00
|
|
|
return
|
|
|
|
|
2018-03-15 17:53:58 +08:00
|
|
|
foundvm = None
|
|
|
|
for vm in self.conn.list_vms():
|
2019-05-09 04:13:40 +08:00
|
|
|
if vm.get_uuid() == guest.uuid:
|
2018-03-15 17:53:58 +08:00
|
|
|
foundvm = vm
|
|
|
|
break
|
|
|
|
|
2015-09-07 02:42:55 +08:00
|
|
|
self._close()
|
2011-04-16 02:43:52 +08:00
|
|
|
|
|
|
|
# Launch details dialog for new VM
|
2019-05-06 04:25:35 +08:00
|
|
|
vmmVMWindow.get_instance(self, foundvm).show()
|
2013-09-07 08:59:01 +08:00
|
|
|
|
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
def _start_install(self, guest, installer):
|
2015-09-13 01:03:51 +08:00
|
|
|
"""
|
|
|
|
Launch the async job to start the install
|
|
|
|
"""
|
2017-07-13 15:49:28 +08:00
|
|
|
bootstrap_args = {}
|
|
|
|
# If creating new container and "container bootstrap" is enabled
|
2019-05-09 04:13:40 +08:00
|
|
|
if (guest.os.is_container() and
|
2017-07-13 15:49:28 +08:00
|
|
|
self._get_config_oscontainer_bootstrap()):
|
|
|
|
bootstrap_arg_keys = {
|
|
|
|
'src': self._get_config_oscontainer_source_url,
|
|
|
|
'dest': self.widget("install-oscontainer-fs").get_text,
|
|
|
|
'user': self._get_config_oscontainer_source_username,
|
|
|
|
'passwd': self._get_config_oscontainer_source_password,
|
2017-12-20 00:32:18 +08:00
|
|
|
'insecure': self._get_config_oscontainer_isecure,
|
|
|
|
'root_password': self._get_config_oscontainer_root_password,
|
2017-07-13 15:49:28 +08:00
|
|
|
}
|
2017-10-11 19:35:45 +08:00
|
|
|
for key, getter in bootstrap_arg_keys.items():
|
2017-07-13 15:49:28 +08:00
|
|
|
bootstrap_args[key] = getter()
|
|
|
|
|
2015-11-22 08:25:02 +08:00
|
|
|
parentobj = self._customize_window or self
|
2020-01-30 00:25:12 +08:00
|
|
|
progWin = vmmAsyncJob(self._do_async_install,
|
|
|
|
[guest, installer, bootstrap_args],
|
2019-05-09 04:13:40 +08:00
|
|
|
self._install_finished_cb, [guest, parentobj],
|
2013-09-07 08:59:01 +08:00
|
|
|
_("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."),
|
2015-11-22 08:25:02 +08:00
|
|
|
parentobj.topwin)
|
2013-09-07 08:59:01 +08:00
|
|
|
progWin.run()
|
2009-03-10 04:16:45 +08:00
|
|
|
|
2020-01-30 00:25:12 +08:00
|
|
|
def _do_async_install(self, asyncjob, guest, installer, bootstrap_args):
|
2015-09-13 01:03:51 +08:00
|
|
|
"""
|
|
|
|
Kick off the actual install
|
|
|
|
"""
|
2012-02-10 23:24:43 +08:00
|
|
|
meter = asyncjob.get_meter()
|
2008-08-19 00:02:49 +08:00
|
|
|
|
2017-07-13 15:49:28 +08:00
|
|
|
if bootstrap_args:
|
|
|
|
# Start container bootstrap
|
2017-07-13 15:49:29 +08:00
|
|
|
self._create_directory_tree(asyncjob, meter, bootstrap_args)
|
2017-07-24 16:26:44 +08:00
|
|
|
if asyncjob.has_error():
|
|
|
|
# Do not continue if virt-bootstrap failed
|
|
|
|
return
|
2017-07-13 15:49:28 +08:00
|
|
|
|
2015-03-27 07:08:04 +08:00
|
|
|
# Build a list of pools we should refresh, if we are creating storage
|
|
|
|
refresh_pools = []
|
2018-03-21 05:23:34 +08:00
|
|
|
for disk in guest.devices.disk:
|
2015-03-27 07:08:04 +08:00
|
|
|
if not disk.wants_storage_creation():
|
|
|
|
continue
|
|
|
|
|
|
|
|
pool = disk.get_parent_pool()
|
|
|
|
if not pool:
|
2020-08-29 08:30:03 +08:00
|
|
|
continue # pragma: no cover
|
2015-03-27 07:08:04 +08:00
|
|
|
|
|
|
|
poolname = pool.name()
|
|
|
|
if poolname not in refresh_pools:
|
|
|
|
refresh_pools.append(poolname)
|
|
|
|
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Starting background install process")
|
2020-01-30 00:25:12 +08:00
|
|
|
installer.start_install(guest, meter=meter)
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Install completed")
|
2010-03-01 08:40:06 +08:00
|
|
|
|
2013-07-07 08:03:42 +08:00
|
|
|
# Wait for VM to show up
|
2013-07-07 23:06:15 +08:00
|
|
|
self.conn.schedule_priority_tick(pollvm=True)
|
2013-07-07 08:03:42 +08:00
|
|
|
count = 0
|
2014-06-03 05:17:47 +08:00
|
|
|
foundvm = None
|
2018-11-01 21:18:34 +08:00
|
|
|
while count < 200:
|
2014-06-03 05:17:47 +08:00
|
|
|
for vm in self.conn.list_vms():
|
|
|
|
if vm.get_uuid() == guest.uuid:
|
|
|
|
foundvm = vm
|
|
|
|
if foundvm:
|
|
|
|
break
|
2013-07-07 08:03:42 +08:00
|
|
|
count += 1
|
|
|
|
time.sleep(.1)
|
|
|
|
|
2014-06-03 05:17:47 +08:00
|
|
|
if not foundvm:
|
2020-08-29 08:30:03 +08:00
|
|
|
raise RuntimeError( # pragma: no cover
|
2014-06-03 05:17:47 +08:00
|
|
|
_("VM '%s' didn't show up after expected time.") % guest.name)
|
|
|
|
vm = foundvm
|
2007-04-11 06:50:04 +08:00
|
|
|
|
2010-12-10 22:57:42 +08:00
|
|
|
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.
|
2020-08-29 08:30:03 +08:00
|
|
|
vm.startup() # pragma: no cover
|
2020-01-30 00:25:12 +08:00
|
|
|
elif installer.has_install_phase():
|
2010-12-10 22:57:42 +08:00
|
|
|
# Register a status listener, which will restart the
|
|
|
|
# guest after the install has finished
|
2012-02-14 03:55:59 +08:00
|
|
|
def cb():
|
2015-04-10 06:02:42 +08:00
|
|
|
vm.connect_opt_out("state-changed",
|
virtinst: guest: drop 'continue_install' concept
continue_install is intended to facilitate windows XP style 3 stage
installs:
stage 1: initial dos style disk setup, reboot
stage 2: actual full installer, reboot
stage 3: OS is functional, virt-install is done
The code assumed that we needed to keep the cdrom as the primary
boot device for the second stage, so virt-install/virt-manager needed
to hang around through the second stage run, wait until the VM shutdown,
then encode the final XML to boot of the disk.
Windows is and always has been smart enough to handle that case though...
after the initial boot, if we set the hd as the primary boot device
for stage 2, the disk bits that windows already installed will make
use of the cdrom as necessary. So the entire premise of continue_install
is irrelevant. Maybe back when it was added, when xen didn't even have
working ACPI support, this served a purpose, but I'm pretty sure we
can safely drop it nowadays.
2016-06-17 04:13:54 +08:00
|
|
|
self._check_install_status)
|
2012-02-14 03:55:59 +08:00
|
|
|
return False
|
|
|
|
self.idle_add(cb)
|
2007-04-11 06:50:04 +08:00
|
|
|
|
2015-03-27 07:08:04 +08:00
|
|
|
# Kick off pool updates
|
|
|
|
for poolname in refresh_pools:
|
|
|
|
try:
|
2020-09-02 00:35:26 +08:00
|
|
|
pool = self.conn.get_pool_by_name(poolname)
|
2015-03-27 07:08:04 +08:00
|
|
|
self.idle_add(pool.refresh)
|
2020-08-29 08:30:03 +08:00
|
|
|
except Exception: # pragma: no cover
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Error looking up pool=%s for refresh after "
|
2015-03-27 07:08:04 +08:00
|
|
|
"VM creation.", poolname, exc_info=True)
|
|
|
|
|
2007-06-23 01:32:13 +08:00
|
|
|
|
virtinst: guest: drop 'continue_install' concept
continue_install is intended to facilitate windows XP style 3 stage
installs:
stage 1: initial dos style disk setup, reboot
stage 2: actual full installer, reboot
stage 3: OS is functional, virt-install is done
The code assumed that we needed to keep the cdrom as the primary
boot device for the second stage, so virt-install/virt-manager needed
to hang around through the second stage run, wait until the VM shutdown,
then encode the final XML to boot of the disk.
Windows is and always has been smart enough to handle that case though...
after the initial boot, if we set the hd as the primary boot device
for stage 2, the disk bits that windows already installed will make
use of the cdrom as necessary. So the entire premise of continue_install
is irrelevant. Maybe back when it was added, when xen didn't even have
working ACPI support, this served a purpose, but I'm pretty sure we
can safely drop it nowadays.
2016-06-17 04:13:54 +08:00
|
|
|
def _check_install_status(self, vm):
|
2015-09-13 01:03:51 +08:00
|
|
|
"""
|
|
|
|
Watch the domain that we are installing, waiting for the state
|
|
|
|
to change, so we can restart it as needed
|
|
|
|
"""
|
2020-08-29 08:30:03 +08:00
|
|
|
if vm.is_crashed(): # pragma: no cover
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("VM crashed, cancelling install plans.")
|
2010-03-01 08:40:06 +08:00
|
|
|
return True
|
|
|
|
|
|
|
|
if not vm.is_shutoff():
|
2020-08-29 08:30:03 +08:00
|
|
|
return # pragma: no cover
|
2010-03-01 08:40:06 +08:00
|
|
|
|
2016-05-13 23:28:03 +08:00
|
|
|
if vm.get_install_abort():
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("User manually shutdown VM, not restarting "
|
2016-05-13 23:28:03 +08:00
|
|
|
"guest after install.")
|
|
|
|
return True
|
|
|
|
|
2020-08-29 08:30:03 +08:00
|
|
|
# Hitting this from the test suite is hard because we can't force
|
|
|
|
# the test driver VM to stop behind virt-manager's back
|
|
|
|
try: # pragma: no cover
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug("Install should be completed, starting VM.")
|
2010-03-01 08:40:06 +08:00
|
|
|
vm.startup()
|
2020-08-29 08:30:03 +08:00
|
|
|
except Exception as e: # pragma: no cover
|
|
|
|
self.err.show_err(_("Error continuing install: %s") % str(e))
|
2010-03-01 08:40:06 +08:00
|
|
|
|
2020-08-29 08:30:03 +08:00
|
|
|
return True # pragma: no cover
|
2017-07-13 15:49:28 +08:00
|
|
|
|
|
|
|
|
2017-07-13 15:49:29 +08:00
|
|
|
def _create_directory_tree(self, asyncjob, meter, bootstrap_args):
|
2017-07-13 15:49:28 +08:00
|
|
|
"""
|
2017-07-13 15:49:31 +08:00
|
|
|
Call bootstrap method from virtBootstrap and show logger messages
|
2017-07-24 16:26:46 +08:00
|
|
|
as state/details.
|
2017-07-13 15:49:28 +08:00
|
|
|
"""
|
2019-06-17 09:12:39 +08:00
|
|
|
import logging
|
2022-01-18 04:12:42 +08:00
|
|
|
|
|
|
|
if self.conn.config.CLITestOptions.fake_virtbootstrap:
|
|
|
|
from .lib.testmock import fakeVirtBootstrap as virtBootstrap
|
|
|
|
else: # pragma: no cover
|
|
|
|
import virtBootstrap # pylint: disable=import-error
|
2017-07-13 15:49:28 +08:00
|
|
|
|
2021-06-10 04:27:21 +08:00
|
|
|
meter.start(_("Bootstraping container"), None)
|
2017-07-13 15:49:29 +08:00
|
|
|
def progress_update_cb(prog):
|
2021-06-10 04:27:21 +08:00
|
|
|
meter.start(_(prog['status']), None)
|
2017-07-13 15:49:29 +08:00
|
|
|
|
2017-07-13 15:49:31 +08:00
|
|
|
asyncjob.details_enable()
|
|
|
|
# Use logging filter to show messages of the progreess on the GUI
|
|
|
|
class SetStateFilter(logging.Filter):
|
|
|
|
def filter(self, record):
|
|
|
|
asyncjob.details_update("%s\n" % record.getMessage())
|
|
|
|
return True
|
|
|
|
|
2017-07-13 15:49:28 +08:00
|
|
|
# Use string buffer to store log messages
|
2017-10-11 19:35:50 +08:00
|
|
|
log_stream = io.StringIO()
|
2017-07-13 15:49:28 +08:00
|
|
|
|
|
|
|
# Get virt-bootstrap logger
|
|
|
|
vbLogger = logging.getLogger('virtBootstrap')
|
|
|
|
vbLogger.setLevel(logging.DEBUG)
|
2018-05-22 03:42:50 +08:00
|
|
|
# Create handler to store log messages in the string buffer
|
2017-07-13 15:49:29 +08:00
|
|
|
hdlr = logging.StreamHandler(log_stream)
|
|
|
|
hdlr.setFormatter(logging.Formatter('%(message)s'))
|
2017-07-13 15:49:31 +08:00
|
|
|
# Use logging filter to show messages on GUI
|
|
|
|
hdlr.addFilter(SetStateFilter())
|
2017-07-13 15:49:29 +08:00
|
|
|
vbLogger.addHandler(hdlr)
|
2017-07-13 15:49:28 +08:00
|
|
|
|
|
|
|
# Key word arguments to be passed
|
|
|
|
kwargs = {'uri': bootstrap_args['src'],
|
|
|
|
'dest': bootstrap_args['dest'],
|
2017-07-13 15:49:29 +08:00
|
|
|
'not_secure': bootstrap_args['insecure'],
|
|
|
|
'progress_cb': progress_update_cb}
|
2017-07-13 15:49:28 +08:00
|
|
|
if bootstrap_args['user'] and bootstrap_args['passwd']:
|
|
|
|
kwargs['username'] = bootstrap_args['user']
|
|
|
|
kwargs['password'] = bootstrap_args['passwd']
|
2017-12-20 00:32:18 +08:00
|
|
|
if bootstrap_args['root_password']:
|
|
|
|
kwargs['root_password'] = bootstrap_args['root_password']
|
2019-06-17 09:12:39 +08:00
|
|
|
log.debug('Start container bootstrap')
|
2017-07-13 15:49:28 +08:00
|
|
|
try:
|
|
|
|
virtBootstrap.bootstrap(**kwargs)
|
|
|
|
# Success - uncheck the 'install-oscontainer-bootstrap' checkbox
|
|
|
|
|
|
|
|
def cb():
|
|
|
|
self.widget("install-oscontainer-bootstrap").set_active(False)
|
|
|
|
self.idle_add(cb)
|
|
|
|
except Exception as err:
|
2017-07-24 16:26:44 +08:00
|
|
|
asyncjob.set_error("virt-bootstrap did not complete successfully",
|
|
|
|
'%s\n%s' % (err, log_stream.getvalue()))
|