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
|
2011-01-18 09:24:57 +00:00
|
|
|
import os, sys, iutil
|
|
|
|
import isys
|
|
|
|
import string
|
|
|
|
import imputil
|
|
|
|
import types
|
|
|
|
|
|
|
|
from constants import *
|
|
|
|
from product import *
|
|
|
|
from storage.partspec import *
|
2013-01-23 17:28:19 +00:00
|
|
|
from storage.devicelibs import swap
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
import gettext
|
|
|
|
_ = lambda x: gettext.ldgettext("anaconda", x)
|
|
|
|
|
|
|
|
import logging
|
|
|
|
log = logging.getLogger("anaconda")
|
|
|
|
|
|
|
|
from flags import flags
|
|
|
|
|
|
|
|
class BaseInstallClass(object):
|
|
|
|
# default to not being hidden
|
|
|
|
hidden = 0
|
|
|
|
pixmap = None
|
|
|
|
showMinimal = 1
|
|
|
|
showLoginChoice = 0
|
|
|
|
_description = ""
|
|
|
|
_descriptionFields = ()
|
|
|
|
name = "base"
|
|
|
|
pkgstext = ""
|
2011-04-03 11:57:05 +00:00
|
|
|
# default to showing the upgrade option
|
2011-01-18 09:24:57 +00:00
|
|
|
showUpgrade = True
|
|
|
|
bootloaderTimeoutDefault = None
|
2013-01-23 17:28:19 +00:00
|
|
|
bootloaderExtraArgs = []
|
|
|
|
_l10n_domain = None
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
# list of of (txt, grplist) tuples for task selection screen
|
|
|
|
tasks = []
|
|
|
|
|
|
|
|
# don't select this class by default
|
|
|
|
default = 0
|
|
|
|
|
|
|
|
# by default, place this under the "install" category; it gets it's
|
|
|
|
# own toplevel category otherwise
|
|
|
|
parentClass = ( _("Install on System"), "install.png" )
|
|
|
|
|
|
|
|
def _get_description(self):
|
|
|
|
return _(self._description) % self._descriptionFields
|
|
|
|
description = property(_get_description)
|
|
|
|
|
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 postAction(self, anaconda):
|
|
|
|
anaconda.backend.postAction(anaconda)
|
|
|
|
|
|
|
|
# modifies the uri from installmethod.getMethodUri() to take into
|
|
|
|
# account any installclass specific things including multiple base
|
2013-01-23 17:28:19 +00:00
|
|
|
# repositories. takes a string or list of strings, returns a dict
|
2011-01-18 09:24:57 +00:00
|
|
|
# with string keys and list values {%repo: %uri_list}
|
|
|
|
def getPackagePaths(self, uri):
|
|
|
|
if not type(uri) == types.ListType:
|
|
|
|
uri = [uri,]
|
|
|
|
|
|
|
|
return {'base': uri}
|
|
|
|
|
|
|
|
def setPackageSelection(self, anaconda):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def setGroupSelection(self, anaconda):
|
|
|
|
grps = anaconda.backend.getDefaultGroups(anaconda)
|
|
|
|
map(lambda x: anaconda.backend.selectGroup(x), grps)
|
|
|
|
|
|
|
|
def getBackend(self):
|
2013-01-23 17:28:19 +00:00
|
|
|
# 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
|
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,
|
2013-01-23 17:28:19 +00:00
|
|
|
size=1024, maxSize=50*1024, grow=True,
|
|
|
|
btr=True, lv=True, encrypted=True),
|
|
|
|
PartSpec(mountpoint="/home", fstype=storage.defaultFSType,
|
|
|
|
size=500, grow=True, requiredSpace=50*1024,
|
|
|
|
btr=True, lv=True, encrypted=True)]
|
|
|
|
|
|
|
|
bootreqs = storage.platform.setDefaultPartitioning()
|
|
|
|
if bootreqs:
|
|
|
|
autorequests.extend(bootreqs)
|
|
|
|
|
|
|
|
swp = swap.swapSuggestion()
|
|
|
|
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
|
|
|
|
|
|
|
def versionMatches(self, oldver):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def productMatches(self, oldprod):
|
|
|
|
pass
|
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
def productUpgradable(self, arch, oldprod, oldver):
|
|
|
|
""" Return a tuple with:
|
|
|
|
(Upgradable True|False, dict of tests and status)
|
|
|
|
|
|
|
|
The dict has True|False for: product, version, arch tests.
|
|
|
|
"""
|
|
|
|
def archesEq(a, b):
|
|
|
|
import re
|
|
|
|
|
|
|
|
if re.match("i.86", a) and re.match("i.86", b):
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return a == b
|
|
|
|
|
|
|
|
result = { "product" : self.productMatches(oldprod),
|
|
|
|
"version" : self.versionMatches(oldver),
|
|
|
|
"arch" : archesEq(arch, productArch)
|
|
|
|
}
|
|
|
|
|
|
|
|
return (all(result.values()), result)
|
|
|
|
|
|
|
|
# sets default ONBOOT values and updates ksdata accordingly
|
|
|
|
def setNetworkOnbootDefault(self, ksdata):
|
|
|
|
pass
|
2011-01-18 09:24:57 +00:00
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
allClasses = []
|
|
|
|
allClasses_hidden = []
|
|
|
|
|
|
|
|
# returns ( className, classObject, classLogo ) tuples
|
|
|
|
def availableClasses(showHidden=0):
|
|
|
|
global allClasses
|
|
|
|
global allClasses_hidden
|
|
|
|
|
|
|
|
def _ordering(first, second):
|
|
|
|
((name1, obj, logo), priority1) = first
|
|
|
|
((name2, obj, logo), priority2) = second
|
|
|
|
|
|
|
|
if priority1 < priority2:
|
|
|
|
return -1
|
|
|
|
elif priority1 > priority2:
|
|
|
|
return 1
|
|
|
|
|
|
|
|
if name1 < name2:
|
|
|
|
return -1
|
|
|
|
elif name1 > name2:
|
|
|
|
return 1
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
if not showHidden:
|
|
|
|
if allClasses: return allClasses
|
|
|
|
else:
|
|
|
|
if allClasses_hidden: return allClasses_hidden
|
|
|
|
|
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(":")
|
|
|
|
|
|
|
|
for dir in env_path + ["installclasses",
|
|
|
|
"/tmp/updates/pyanaconda/installclasses",
|
|
|
|
"/tmp/product/pyanaconda/installclasses",
|
|
|
|
"%s/pyanaconda/installclasses" % get_python_lib(plat_specific=1) ]:
|
|
|
|
if os.access(dir, os.R_OK):
|
|
|
|
path.append(dir)
|
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 = {}
|
|
|
|
list = []
|
|
|
|
for file in files:
|
|
|
|
if file[0] == '.': continue
|
|
|
|
if len (file) < 4:
|
|
|
|
continue
|
|
|
|
if file[-3:] != ".py" and file[-4:-1] != ".py":
|
|
|
|
continue
|
|
|
|
mainName = string.split(file, ".")[0]
|
|
|
|
if done.has_key(mainName): continue
|
|
|
|
done[mainName] = 1
|
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
|
2011-01-18 09:24:57 +00:00
|
|
|
try:
|
|
|
|
found = imputil.imp.find_module(mainName)
|
2013-01-23 17:28:19 +00:00
|
|
|
except ImportError as e:
|
2011-01-18 09:24:57 +00:00
|
|
|
log.warning ("module import of %s failed: %s" % (mainName, sys.exc_type))
|
|
|
|
continue
|
|
|
|
|
|
|
|
try:
|
|
|
|
loaded = imputil.imp.load_module(mainName, found[0], found[1], found[2])
|
|
|
|
|
|
|
|
obj = loaded.InstallClass
|
|
|
|
|
|
|
|
if obj.__dict__.has_key('sortPriority'):
|
|
|
|
sortOrder = obj.sortPriority
|
|
|
|
else:
|
|
|
|
sortOrder = 0
|
|
|
|
|
|
|
|
if obj.__dict__.has_key('arch'):
|
|
|
|
if obj.arch != iutil.getArch():
|
|
|
|
obj.hidden = 1
|
2013-01-23 17:28:19 +00:00
|
|
|
|
2011-01-18 09:24:57 +00:00
|
|
|
if obj.hidden == 0 or showHidden == 1:
|
|
|
|
list.append(((obj.name, obj, obj.pixmap), sortOrder))
|
2013-01-23 17:28:19 +00:00
|
|
|
except ImportError as e:
|
2011-01-18 09:24:57 +00:00
|
|
|
log.warning ("module import of %s failed: %s" % (mainName, sys.exc_type))
|
|
|
|
if flags.debug: raise
|
|
|
|
else: continue
|
|
|
|
|
|
|
|
list.sort(_ordering)
|
|
|
|
for (item, priority) in list:
|
|
|
|
if showHidden:
|
|
|
|
allClasses_hidden.append(item)
|
|
|
|
else:
|
|
|
|
allClasses.append(item)
|
|
|
|
|
|
|
|
if showHidden:
|
|
|
|
return allClasses_hidden
|
|
|
|
else:
|
|
|
|
return allClasses
|
|
|
|
|
|
|
|
def getBaseInstallClass():
|
|
|
|
# figure out what installclass we should base on.
|
|
|
|
allavail = availableClasses(showHidden = 1)
|
|
|
|
avail = availableClasses(showHidden = 0)
|
2013-01-23 17:28:19 +00:00
|
|
|
|
2011-01-18 09:24:57 +00:00
|
|
|
if len(avail) == 1:
|
|
|
|
(cname, cobject, clogo) = avail[0]
|
|
|
|
log.info("using only installclass %s" %(cname,))
|
|
|
|
elif len(allavail) == 1:
|
|
|
|
(cname, cobject, clogo) = allavail[0]
|
|
|
|
log.info("using only installclass %s" %(cname,))
|
|
|
|
|
|
|
|
# Use the highest priority install class if more than one found.
|
|
|
|
elif len(avail) > 1:
|
|
|
|
(cname, cobject, clogo) = avail.pop()
|
|
|
|
log.info('%s is the highest priority installclass, using it' % cname)
|
|
|
|
elif len(allavail) > 1:
|
|
|
|
(cname, cobject, clogo) = allavail.pop()
|
|
|
|
log.info('%s is the highest priority installclass, using it' % cname)
|
|
|
|
|
|
|
|
# Default to the base installclass if nothing else is found.
|
|
|
|
else:
|
|
|
|
raise RuntimeError, "Unable to find an install class to use!!!"
|
|
|
|
|
|
|
|
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)
|