unattended: Split out make_installconfig

The building process here is mostly independent of the InstallScript
object. Moving it to its own function makes that more clear, makes
InstallScript smaller, and the code is indented less
This commit is contained in:
Cole Robinson 2019-03-05 14:27:37 -05:00
parent e87e3a71fe
commit 1f6879c811
2 changed files with 133 additions and 126 deletions

View File

@ -175,9 +175,9 @@ class InstallerTreeMedia(object):
def prepare(self, guest, meter):
cmdline = None
if self._unattended_data:
script, config = unattended.prepare_install_script(
script = unattended.prepare_install_script(
guest, self._unattended_data)
path, cmdline = unattended.generate_install_script(script, config)
path, cmdline = unattended.generate_install_script(script)
self.initrd_injections.append(path)
self._tmpfiles.append(path)

View File

@ -18,6 +18,114 @@ from gi.repository import GLib
from . import util
def _make_installconfig(script, osobj, unattended_data, arch, hostname):
"""
Build a Libosinfo.InstallConfig instance
"""
def get_timezone():
TZ_FILE = "/etc/localtime"
localtime = Gio.File.new_for_path(TZ_FILE)
if not localtime.query_exists():
return None
info = localtime.query_info(
Gio.FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS)
if not info:
return None
target = info.get_symlink_target()
if not target:
return None
tokens = target.split("zoneinfo/")
if not tokens or len(tokens) < 2:
return None
return tokens[1]
def get_language():
names = GLib.get_language_names()
if not names or len(names) < 2:
return None
return names[1]
config = Libosinfo.InstallConfig()
# Set user login and name based on the one from the system
config.set_user_login(GLib.get_user_name())
config.set_user_realname(GLib.get_real_name())
# Set user-password.
# In case it's required and not passed, just raise a RuntimeError.
if script.requires_user_password() and not unattended_data.user_password:
raise RuntimeError(
_("%s requires the user-password to be set.") %
osobj.name)
config.set_user_password(
unattended_data.user_password if unattended_data.user_password
else "")
# Set the admin-password:
# In case it's required and not passed, just raise a RuntimeError.
if script.requires_admin_password() and not unattended_data.admin_password:
raise RuntimeError(
_("%s requires the admin-password to be set.") %
osobj.name)
config.set_admin_password(
unattended_data.admin_password if unattended_data.admin_password
else "")
# Set the target disk.
# virtiodisk is the preferred way, in case it's supported, otherwise
# just fallback to scsi.
#
# Note: this is linux specific and will require some changes whenever
# support for Windows will be added.
tgt = "/dev/vda" if osobj.supports_virtiodisk() else "/dev/sda"
config.set_target_disk(tgt)
# Set hardware architecture and hostname
config.set_hardware_arch(arch)
config.set_hostname(hostname)
# Try to guess the timezone from '/etc/localtime', in case it's not
# possible 'America/New_York' will be used.
timezone = get_timezone()
if timezone:
config.set_l10n_timezone(timezone)
else:
logging.warning(
_("'America/New_York' timezone will be used for this "
"unattended installation."))
# Try to guess to language and keyboard layout from the system's
# language.
#
# This method has flows as it's quite common to have language and
# keyboard layout not matching. Otherwise, there's no easy way to guess
# the keyboard layout without relying on a set of APIs of an specific
# Desktop Environment.
language = get_language()
if language:
config.set_l10n_language(language)
config.set_l10n_keyboard(language)
else:
logging.warning(
_("'en_US' will be used as both language and keyboard layout "
"for unattended installation."))
logging.debug("InstallScriptConfig created with the following params:")
logging.debug("username: %s", config.get_user_login())
logging.debug("realname: %s", config.get_user_realname())
logging.debug("user password: %s", config.get_user_password())
logging.debug("admin password: %s", config.get_admin_password())
logging.debug("target disk: %s", config.get_target_disk())
logging.debug("hardware arch: %s", config.get_hardware_arch())
logging.debug("hostname: %s", config.get_hostname())
logging.debug("timezone: %s", config.get_l10n_timezone())
logging.debug("language: %s", config.get_l10n_language())
logging.debug("keyboard: %s", config.get_l10n_keyboard())
return config
class OSInstallScript:
"""
Wrapper for Libosinfo.InstallScript interactions
@ -29,6 +137,7 @@ class OSInstallScript:
def __init__(self, script, osobj):
self._script = script
self._osobj = osobj
self._config = None
if not OSInstallScript.have_new_libosinfo():
raise RuntimeError(_("libosinfo is too old to support unattended "
@ -86,131 +195,27 @@ class OSInstallScript:
logging.debug("Using '%s' installation source", source)
self._script.set_installation_source(installation_source)
def get_config(self, unattended_data, arch, hostname):
def requires_param(config_param):
param = self._script.get_config_param(config_param)
def _requires_param(self, config_param):
param = self._script.get_config_param(config_param)
return bool(param and not param.is_optional())
if not param or param.is_optional():
return False
def requires_user_password(self):
return self._requires_param(
Libosinfo.INSTALL_CONFIG_PROP_USER_PASSWORD)
def requires_admin_password(self):
return self._requires_param(
Libosinfo.INSTALL_CONFIG_PROP_ADMIN_PASSWORD)
return True
def set_config(self, config):
self._config = config
def requires_user_password():
return requires_param(Libosinfo.INSTALL_CONFIG_PROP_USER_PASSWORD)
def requires_admin_password():
return requires_param(Libosinfo.INSTALL_CONFIG_PROP_ADMIN_PASSWORD)
def get_timezone():
TZ_FILE = "/etc/localtime"
localtime = Gio.File.new_for_path(TZ_FILE)
if not localtime.query_exists():
return None
info = localtime.query_info(
Gio.FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS)
if not info:
return None
target = info.get_symlink_target()
if not target:
return None
tokens = target.split("zoneinfo/")
if not tokens or len(tokens) < 2:
return None
return tokens[1]
def get_language():
names = GLib.get_language_names()
if not names or len(names) < 2:
return None
return names[1]
config = Libosinfo.InstallConfig()
# Set user login and name based on the one from the system
config.set_user_login(GLib.get_user_name())
config.set_user_realname(GLib.get_real_name())
# Set user-password.
# In case it's required and not passed, just raise a RuntimeError.
if requires_user_password() and not unattended_data.user_password:
raise RuntimeError(
_("%s requires the user-password to be set.") %
self._osobj.name)
config.set_user_password(
unattended_data.user_password if unattended_data.user_password
else "")
# Set the admin-password:
# In case it's required and not passed, just raise a RuntimeError.
if requires_admin_password() and not unattended_data.admin_password:
raise RuntimeError(
_("%s requires the admin-password to be set.") %
self._osobj.name)
config.set_admin_password(
unattended_data.admin_password if unattended_data.admin_password
else "")
# Set the target disk.
# virtiodisk is the preferred way, in case it's supported, otherwise
# just fallback to scsi.
#
# Note: this is linux specific and will require some changes whenever
# support for Windows will be added.
tgt = "/dev/vda" if self._osobj.supports_virtiodisk() else "/dev/sda"
config.set_target_disk(tgt)
# Set hardware architecture and hostname
config.set_hardware_arch(arch)
config.set_hostname(hostname)
# Try to guess the timezone from '/etc/localtime', in case it's not
# possible 'America/New_York' will be used.
timezone = get_timezone()
if timezone:
config.set_l10n_timezone(timezone)
else:
logging.warning(
_("'America/New_York' timezone will be used for this "
"unattended installation."))
# Try to guess to language and keyboard layout from the system's
# language.
#
# This method has flows as it's quite common to have language and
# keyboard layout not matching. Otherwise, there's no easy way to guess
# the keyboard layout without relying on a set of APIs of an specific
# Desktop Environment.
language = get_language()
if language:
config.set_l10n_language(language)
config.set_l10n_keyboard(language)
else:
logging.warning(
_("'en_US' will be used as both language and keyboard layout "
"for unattended installation."))
logging.debug("InstallScriptConfig created with the following params:")
logging.debug("username: %s", config.get_user_login())
logging.debug("realname: %s", config.get_user_realname())
logging.debug("user password: %s", config.get_user_password())
logging.debug("admin password: %s", config.get_admin_password())
logging.debug("target disk: %s", config.get_target_disk())
logging.debug("hardware arch: %s", config.get_hardware_arch())
logging.debug("hostname: %s", config.get_hostname())
logging.debug("timezone: %s", config.get_l10n_timezone())
logging.debug("language: %s", config.get_l10n_language())
logging.debug("keyboard: %s", config.get_l10n_keyboard())
return config
def generate_output(self, config, output_dir):
def generate_output(self, output_dir):
self._script.generate_output(
self._osobj.get_handle(), config, output_dir)
self._osobj.get_handle(), self._config, output_dir)
def generate_cmdline(self, config):
def generate_cmdline(self):
return self._script.generate_command_line(
self._osobj.get_handle(), config)
self._osobj.get_handle(), self._config)
class UnattendedData():
@ -228,17 +233,19 @@ def prepare_install_script(guest, unattended_data):
script.set_preferred_injection_method("initrd")
script.set_installation_source("network")
config = script.get_config(unattended_data, guest.os.arch, guest.name)
return script, config
config = _make_installconfig(script, guest.osinfo, unattended_data,
guest.os.arch, guest.name)
script.set_config(config)
return script
def generate_install_script(script, config):
def generate_install_script(script):
scratch = os.path.join(util.get_cache_dir(), "unattended")
if not os.path.exists(scratch):
os.makedirs(scratch, 0o751)
script.generate_output(config, Gio.File.new_for_path(scratch))
script.generate_output(Gio.File.new_for_path(scratch))
path = os.path.join(scratch, script.get_expected_filename())
cmdline = script.generate_cmdline(config)
cmdline = script.generate_cmdline()
return path, cmdline