File: //lib64/python2.7/site-packages/pyanaconda/installclass.py
#
# installclass.py: This is the prototypical class for workstation, server, and
# kickstart installs. The interface to BaseInstallClass is *public* --
# ISVs/OEMs can customize the install by creating a new derived type of this
# class.
#
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
# Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from distutils.sysconfig import get_python_lib
import os
import sys
from blivet.partspec import PartSpec
from blivet.devicelibs import swap
from blivet.platform import platform
from blivet.size import Size
from pyanaconda.kickstart import getAvailableDiskSpace
from pyanaconda.constants import DEFAULT_AUTOPART_TYPE
from pyanaconda.ui.common import collect
import logging
log = logging.getLogger("anaconda")
class BaseInstallClass(object):
# default to not being hidden
sortPriority = 0
hidden = False
name = "base"
bootloaderTimeoutDefault = None
bootloaderExtraArgs = []
# Anaconda flags several packages to be installed based on the configuration
# of the system -- things like fs utilities, bootloader, &c. This is a list
# of packages that we should not try to install using the aforementioned
# mechanism.
ignoredPackages = []
# This flag controls whether or not Anaconda should provide an option to
# install the latest updates during installation source selection.
installUpdates = True
_l10n_domain = None
# The default filesystem type to use. If None, we will use whatever
# Blivet uses by default.
defaultFS = None
# The default partitioning scheme to use for autopartitioning.
# It has to be always set.
default_autopart_type = DEFAULT_AUTOPART_TYPE
# help
help_folder = "/usr/share/anaconda/help/rhel"
help_main_page = "Installation_Guide.xml"
help_placeholder = None
help_placeholder_with_links = None
# geolocation
use_geolocation_with_kickstart = False
@property
def l10n_domain(self):
if self._l10n_domain is None:
raise RuntimeError("Localization domain for '%s' not set." %
self.name)
return self._l10n_domain
def setPackageSelection(self, anaconda):
pass
def getBackend(self):
# The default is to return None here, which means anaconda should
# use live or yum (whichever can be detected). This method is
# provided as a way for other products to specify their own.
return None
def setDefaultPartitioning(self, storage):
autorequests = [PartSpec(mountpoint="/", fstype=storage.defaultFSType,
size=Size("1GiB"),
maxSize=Size("50GiB"),
grow=True,
btr=True, lv=True, thin=True, encrypted=True),
PartSpec(mountpoint="/home",
fstype=storage.defaultFSType,
size=Size("500MiB"), grow=True,
requiredSpace=Size("50GiB"),
btr=True, lv=True, thin=True, encrypted=True)]
bootreqs = platform.setDefaultPartitioning()
if bootreqs:
autorequests.extend(bootreqs)
disk_space = getAvailableDiskSpace(storage)
swp = swap.swapSuggestion(disk_space=disk_space)
autorequests.append(PartSpec(fstype="swap", size=swp, grow=False,
lv=True, encrypted=True))
for autoreq in autorequests:
if autoreq.fstype is None:
if autoreq.mountpoint == "/boot":
autoreq.fstype = storage.defaultBootFSType
else:
autoreq.fstype = storage.defaultFSType
storage.autoPartitionRequests = autorequests
def customizeDefaultPartitioning(self, storage, data):
# Customize the default partitioning with kickstart data.
skipped_mountpoints = set()
# Create a set of mountpoints to remove from autorequests.
# Add /home to the set if --nohome is selected.
if data.autopart.autopart and data.autopart.nohome:
skipped_mountpoints.add("/home")
# Skip mountpoints we want to remove.
storage.autoPartitionRequests = [req for req in storage.autoPartitionRequests
if req.mountpoint not in skipped_mountpoints]
def configure(self, anaconda):
anaconda.bootloader.timeout = self.bootloaderTimeoutDefault
anaconda.bootloader.boot_args.update(self.bootloaderExtraArgs)
# The default partitioning should be always set.
self.setDefaultPartitioning(anaconda.storage)
# Customize the default partitioning with kickstart data.
self.customizeDefaultPartitioning(anaconda.storage, anaconda.ksdata)
def setStorageChecker(self, storage_checker):
# Update constraints and add or remove some checks in
# the storage checker to customize the storage sanity
# checking.
pass
# sets default ONBOOT values and updates ksdata accordingly
def setNetworkOnbootDefault(self, ksdata):
pass
def filterSupportedLangs(self, ksdata, langs):
return langs
def filterSupportedLocales(self, ksdata, lang, locales):
return locales
def __init__(self):
pass
class InstallClassFactory(object):
"""Class used to get an install class instance."""
def __init__(self):
self._classes = []
self._visible_classes = []
self._paths = []
def get_install_class_by_name(self, name):
"""Return an instance of an install class with a requested name."""
for install_class in self.classes:
if install_class.name == name:
log.info("Using the requested install class %s.",
self._get_class_description(install_class))
return install_class()
raise RuntimeError("Unable to find the install class %s.", name)
def get_best_install_class(self):
"""Return the instance of the best found install class.
We choose an install class with the highest priority. The priority
of an install class is based on its visibility (we prefer visible),
its sort priority (we prefer higher number) and its name (in reverse
alphabetical order, so Fedora Workstation is preferred before Fedora).
"""
if self.visible_classes:
install_class = self.visible_classes[0]
log.info("Using a visible install class %s.",
self._get_class_description(install_class))
elif self.classes:
install_class = self.classes[0]
log.info("Using a hidden install class %s.",
self._get_class_description(install_class))
else:
raise RuntimeError("Unable to find an install class to use.")
return install_class()
@property
def paths(self):
"""Return paths where to look for install classes."""
if not self._paths:
self._paths = self._get_install_class_paths()
return self._paths
@property
def classes(self):
"""Return all available install classes."""
if not self._classes:
self._classes = self._get_available_classes(self.paths)
return self._classes
@property
def visible_classes(self):
"""Return only install classes that are not hidden."""
if not self._visible_classes:
self._visible_classes = list(filter(self._is_visible_class, self.classes))
return self._visible_classes
@staticmethod
def _is_visible_class(obj):
"""Is the class visible?"""
return not obj.hidden
@staticmethod
def _is_install_class(obj):
"""Is the class the install class?"""
return issubclass(obj, BaseInstallClass) and obj != BaseInstallClass
@staticmethod
def _get_install_class_key(obj):
"""Return the install class key for sorting."""
return obj.sortPriority, obj.name
@staticmethod
def _get_class_description(install_class):
"""Return the description of the install class."""
return "%s (%s)" % (install_class.name, install_class.__name__)
def _get_install_class_paths(self):
"""Return a list of paths to directories with install classes."""
path = []
if "ANACONDA_INSTALL_CLASSES" in os.environ:
path += os.environ["ANACONDA_INSTALL_CLASSES"].split(":")
path += [
"installclasses",
"/tmp/updates/pyanaconda/installclasses",
"/tmp/product/pyanaconda/installclasses",
"%s/pyanaconda/installclasses" % get_python_lib(plat_specific=1)
]
return list(filter(lambda d: os.access(d, os.R_OK), path))
def _get_available_classes(self, paths):
"""Return a list of available install classes."""
# Append the location of install classes to the python path
# so install classes can import and inherit correct classes.
sys.path = paths + sys.path
classes = set()
for path in paths:
log.debug("Searching %s.", path)
for install_class in collect("%s", path, self._is_install_class):
log.debug("Found %s.", self._get_class_description(install_class))
classes.add(install_class)
# Classes are sorted by their priority and name in the reversed order,
# so classes with the highest priority and longer name are preferred.
# For example, Fedora Workstation doesn't have higher priority.
return sorted(classes, key=self._get_install_class_key, reverse=True)
factory = InstallClassFactory()