2011-01-18 09:24:57 +00:00
|
|
|
#
|
|
|
|
# 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/>.
|
|
|
|
#
|
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
from distutils.sysconfig import get_python_lib
|
2014-04-07 12:38:09 +00:00
|
|
|
import os, sys
|
2016-04-10 04:00:00 +00:00
|
|
|
import imp
|
2011-01-18 09:24:57 +00:00
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
from blivet.partspec import PartSpec
|
2015-05-30 11:20:59 +00:00
|
|
|
from blivet.autopart import swapSuggestion
|
2014-04-07 12:38:09 +00:00
|
|
|
from blivet.platform import platform
|
2015-03-23 11:36:12 +00:00
|
|
|
from blivet.size import Size
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
import logging
|
|
|
|
log = logging.getLogger("anaconda")
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
from pyanaconda.kickstart import getAvailableDiskSpace
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
class BaseInstallClass(object):
|
|
|
|
# default to not being hidden
|
2015-05-30 11:20:59 +00:00
|
|
|
hidden = False
|
2011-01-18 09:24:57 +00:00
|
|
|
name = "base"
|
|
|
|
bootloaderTimeoutDefault = None
|
2013-01-23 17:28:19 +00:00
|
|
|
bootloaderExtraArgs = []
|
2014-04-07 12:38:09 +00:00
|
|
|
|
|
|
|
# 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
|
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
_l10n_domain = None
|
2011-01-18 09:24:57 +00:00
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
# The default filesystem type to use. If None, we will use whatever
|
|
|
|
# Blivet uses by default.
|
|
|
|
defaultFS = None
|
2011-01-18 09:24:57 +00:00
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
# help
|
|
|
|
help_folder = "/usr/share/anaconda/help"
|
|
|
|
help_main_page = "Installation_Guide.xml"
|
|
|
|
help_placeholder = None
|
|
|
|
help_placeholder_with_links = None
|
|
|
|
|
2015-05-30 11:20:59 +00:00
|
|
|
# path to the installclass stylesheet, if any
|
|
|
|
stylesheet = None
|
|
|
|
|
|
|
|
# comps environment id to select by default
|
|
|
|
defaultPackageEnvironment = None
|
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
@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
|
|
|
|
|
2011-01-18 09:24:57 +00:00
|
|
|
def setPackageSelection(self, anaconda):
|
2014-04-07 12:38:09 +00:00
|
|
|
pass
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
def getBackend(self):
|
2013-01-23 17:28:19 +00:00
|
|
|
# The default is to return None here, which means anaconda should
|
2016-04-10 04:00:00 +00:00
|
|
|
# use live or dnf (whichever can be detected). This method is
|
2013-01-23 17:28:19 +00:00
|
|
|
# provided as a way for other products to specify their own.
|
|
|
|
return None
|
2011-01-18 09:24:57 +00:00
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
def setDefaultPartitioning(self, storage):
|
2011-06-23 15:12:14 +00:00
|
|
|
autorequests = [PartSpec(mountpoint="/", fstype=storage.defaultFSType,
|
2015-03-23 11:36:12 +00:00
|
|
|
size=Size("1GiB"),
|
|
|
|
maxSize=Size("50GiB"),
|
|
|
|
grow=True,
|
2014-04-07 12:38:09 +00:00
|
|
|
btr=True, lv=True, thin=True, encrypted=True),
|
2015-03-23 11:36:12 +00:00
|
|
|
PartSpec(mountpoint="/home",
|
|
|
|
fstype=storage.defaultFSType,
|
|
|
|
size=Size("500MiB"), grow=True,
|
|
|
|
requiredSpace=Size("50GiB"),
|
2014-04-07 12:38:09 +00:00
|
|
|
btr=True, lv=True, thin=True, encrypted=True)]
|
2013-01-23 17:28:19 +00:00
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
bootreqs = platform.setDefaultPartitioning()
|
2013-01-23 17:28:19 +00:00
|
|
|
if bootreqs:
|
|
|
|
autorequests.extend(bootreqs)
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
|
|
|
|
disk_space = getAvailableDiskSpace(storage)
|
2015-05-30 11:20:59 +00:00
|
|
|
swp = swapSuggestion(disk_space=disk_space)
|
2013-01-23 17:28:19 +00:00
|
|
|
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
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
storage.autoPartitionRequests = autorequests
|
|
|
|
|
|
|
|
def configure(self, anaconda):
|
|
|
|
anaconda.bootloader.timeout = self.bootloaderTimeoutDefault
|
2013-01-23 17:28:19 +00:00
|
|
|
anaconda.bootloader.boot_args.update(self.bootloaderExtraArgs)
|
2011-01-18 09:24:57 +00:00
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
# sets default ONBOOT values and updates ksdata accordingly
|
|
|
|
def setNetworkOnbootDefault(self, ksdata):
|
|
|
|
pass
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
def __init__(self):
|
2014-04-07 12:38:09 +00:00
|
|
|
pass
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
allClasses = []
|
|
|
|
allClasses_hidden = []
|
|
|
|
|
2015-05-30 11:20:59 +00:00
|
|
|
# returns ( className, classObject ) tuples
|
|
|
|
def availableClasses(showHidden=False):
|
2011-01-18 09:24:57 +00:00
|
|
|
global allClasses
|
|
|
|
global allClasses_hidden
|
|
|
|
|
|
|
|
if not showHidden:
|
2014-04-07 12:38:09 +00:00
|
|
|
if allClasses:
|
|
|
|
return allClasses
|
2011-01-18 09:24:57 +00:00
|
|
|
else:
|
2014-04-07 12:38:09 +00:00
|
|
|
if allClasses_hidden:
|
|
|
|
return allClasses_hidden
|
2011-01-18 09:24:57 +00:00
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
path = []
|
|
|
|
|
|
|
|
env_path = []
|
|
|
|
if "ANACONDA_INSTALL_CLASSES" in os.environ:
|
|
|
|
env_path += os.environ["ANACONDA_INSTALL_CLASSES"].split(":")
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
for d in env_path + ["installclasses",
|
|
|
|
"/tmp/updates/pyanaconda/installclasses",
|
|
|
|
"/tmp/product/pyanaconda/installclasses",
|
2016-04-10 04:00:00 +00:00
|
|
|
"%s/pyanaconda/installclasses" % get_python_lib(plat_specific=1)]:
|
2014-04-07 12:38:09 +00:00
|
|
|
if os.access(d, os.R_OK):
|
|
|
|
path.append(d)
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
# append the location of installclasses to the python path so we
|
|
|
|
# can import them
|
2013-01-23 17:28:19 +00:00
|
|
|
sys.path = path + sys.path
|
|
|
|
|
|
|
|
files = []
|
|
|
|
for p in reversed(path):
|
|
|
|
files += os.listdir(p)
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
done = {}
|
2014-04-07 12:38:09 +00:00
|
|
|
lst = []
|
|
|
|
for fileName in files:
|
|
|
|
if fileName[0] == '.':
|
|
|
|
continue
|
2016-04-10 04:00:00 +00:00
|
|
|
if len(fileName) < 4:
|
2014-04-07 12:38:09 +00:00
|
|
|
continue
|
|
|
|
if fileName[-3:] != ".py" and fileName[-4:-1] != ".py":
|
|
|
|
continue
|
|
|
|
mainName = fileName.split(".")[0]
|
2015-03-23 11:36:12 +00:00
|
|
|
if mainName in done:
|
2014-04-07 12:38:09 +00:00
|
|
|
continue
|
|
|
|
done[mainName] = 1
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
try:
|
2016-04-10 04:00:00 +00:00
|
|
|
found = imp.find_module(mainName)
|
2014-04-07 12:38:09 +00:00
|
|
|
except ImportError:
|
2016-04-10 04:00:00 +00:00
|
|
|
log.warning("module import of %s failed: %s", mainName, sys.exc_info()[0])
|
2011-01-18 09:24:57 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
try:
|
2016-04-10 04:00:00 +00:00
|
|
|
loaded = imp.load_module(mainName, found[0], found[1], found[2])
|
2011-01-18 09:24:57 +00:00
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
for (_key, obj) in loaded.__dict__.items():
|
|
|
|
# If it's got these two methods, it's an InstallClass.
|
|
|
|
if hasattr(obj, "setDefaultPartitioning") and hasattr(obj, "setPackageSelection"):
|
|
|
|
sortOrder = getattr(obj, "sortPriority", 0)
|
2015-05-30 11:20:59 +00:00
|
|
|
if not obj.hidden or showHidden:
|
2015-03-23 11:36:12 +00:00
|
|
|
lst.append(((obj.name, obj), sortOrder))
|
2014-04-07 12:38:09 +00:00
|
|
|
except (ImportError, AttributeError):
|
2016-04-10 04:00:00 +00:00
|
|
|
log.warning("module import of %s failed: %s", mainName, sys.exc_info()[0])
|
2014-04-07 12:38:09 +00:00
|
|
|
|
2016-04-10 04:00:00 +00:00
|
|
|
# sort by sort order first, then by install class name
|
|
|
|
lst.sort(key=lambda x: (x[1], x[0][0]))
|
2014-04-07 12:38:09 +00:00
|
|
|
for (item, _) in lst:
|
2011-01-18 09:24:57 +00:00
|
|
|
if showHidden:
|
2014-04-07 12:38:09 +00:00
|
|
|
allClasses_hidden += [item]
|
2011-01-18 09:24:57 +00:00
|
|
|
else:
|
2014-04-07 12:38:09 +00:00
|
|
|
allClasses += [item]
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
if showHidden:
|
|
|
|
return allClasses_hidden
|
|
|
|
else:
|
|
|
|
return allClasses
|
|
|
|
|
|
|
|
def getBaseInstallClass():
|
|
|
|
# figure out what installclass we should base on.
|
2015-05-30 11:20:59 +00:00
|
|
|
allavail = availableClasses(showHidden=True)
|
|
|
|
avail = availableClasses(showHidden=False)
|
2013-01-23 17:28:19 +00:00
|
|
|
|
2011-01-18 09:24:57 +00:00
|
|
|
if len(avail) == 1:
|
2014-04-07 12:38:09 +00:00
|
|
|
(cname, cobject) = avail[0]
|
|
|
|
log.info("using only installclass %s", cname)
|
2011-01-18 09:24:57 +00:00
|
|
|
elif len(allavail) == 1:
|
2014-04-07 12:38:09 +00:00
|
|
|
(cname, cobject) = allavail[0]
|
|
|
|
log.info("using only installclass %s", cname)
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
# Use the highest priority install class if more than one found.
|
|
|
|
elif len(avail) > 1:
|
2014-04-07 12:38:09 +00:00
|
|
|
(cname, cobject) = avail.pop()
|
|
|
|
log.info('%s is the highest priority installclass, using it', cname)
|
2011-01-18 09:24:57 +00:00
|
|
|
elif len(allavail) > 1:
|
2014-04-07 12:38:09 +00:00
|
|
|
(cname, cobject) = allavail.pop()
|
|
|
|
log.info('%s is the highest priority installclass, using it', cname)
|
2011-01-18 09:24:57 +00:00
|
|
|
else:
|
2014-04-07 12:38:09 +00:00
|
|
|
raise RuntimeError("Unable to find an install class to use!!!")
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
return cobject
|
|
|
|
|
|
|
|
baseclass = getBaseInstallClass()
|
|
|
|
|
|
|
|
# we need to be able to differentiate between this and custom
|
|
|
|
class DefaultInstall(baseclass):
|
|
|
|
def __init__(self):
|
2013-01-23 17:28:19 +00:00
|
|
|
baseclass.__init__(self)
|