2011-01-18 09:24:57 +00:00
#
# kickstart.py: kickstart install support
#
# 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 pyanaconda . errors import ScriptError , errorHandler
2011-01-18 09:24:57 +00:00
from storage . deviceaction import *
from storage . devices import LUKSDevice
from storage . devicelibs . lvm import getPossiblePhysicalExtents
2013-01-23 17:28:19 +00:00
from storage . devicelibs . mpath import MultipathConfigWriter , MultipathTopology
from storage . devicelibs import swap
2011-01-18 09:24:57 +00:00
from storage . formats import getFormat
2013-01-23 17:28:19 +00:00
from storage . partitioning import doPartitioning
from storage . partitioning import growLVM
2011-01-18 09:24:57 +00:00
import storage . iscsi
import storage . fcoe
import storage . zfcp
2013-01-23 17:28:19 +00:00
import glob
2011-01-18 09:24:57 +00:00
import iutil
import isys
import os
import os . path
import tempfile
from flags import flags
from constants import *
2013-01-23 17:28:19 +00:00
import shlex
2011-01-18 09:24:57 +00:00
import sys
import urlgrabber
import pykickstart . commands as commands
from storage . devices import *
2013-01-23 17:28:19 +00:00
from pyanaconda import keyboard
from pyanaconda import ntp
from pyanaconda import timezone
from pyanaconda import localization
from pyanaconda import network
from pyanaconda . simpleconfig import SimpleConfigFile
from pyanaconda . users import getPassAlgo
from pyanaconda . desktop import Desktop
from pykickstart . base import KickstartCommand
2011-01-18 09:24:57 +00:00
from pykickstart . constants import *
2013-01-23 17:28:19 +00:00
from pykickstart . errors import formatErrorMsg , KickstartError , KickstartValueError
from pykickstart . parser import KickstartParser
from pykickstart . parser import Script as KSScript
from pykickstart . sections import *
from pykickstart . version import returnClassForVersion
2011-01-18 09:24:57 +00:00
import gettext
_ = lambda x : gettext . ldgettext ( " anaconda " , x )
import logging
log = logging . getLogger ( " anaconda " )
stderrLog = logging . getLogger ( " anaconda.stderr " )
2013-01-23 17:28:19 +00:00
storage_log = logging . getLogger ( " storage " )
stdoutLog = logging . getLogger ( " anaconda.stdout " )
2011-01-18 09:24:57 +00:00
from anaconda_log import logger , logLevelMap , setHandlersLevel , \
DEFAULT_TTY_LEVEL
2013-01-23 17:28:19 +00:00
packagesSeen = False
# deviceMatches is called early, before any multipaths can possibly be coalesced
# so it needs to know about them in some additional way: have the topology ready.
topology = None
class AnacondaKSScript ( KSScript ) :
def run ( self , chroot ) :
2011-01-18 09:24:57 +00:00
if self . inChroot :
scriptRoot = chroot
else :
scriptRoot = " / "
( fd , path ) = tempfile . mkstemp ( " " , " ks-script- " , scriptRoot + " /tmp " )
os . write ( fd , self . script )
os . close ( fd )
os . chmod ( path , 0700 )
# Always log stdout/stderr from scripts. Using --logfile just lets you
# pick where it goes. The script will also be logged to program.log
# because of execWithRedirect, and to anaconda.log if the script fails.
if self . logfile :
if self . inChroot :
messages = " %s / %s " % ( scriptRoot , self . logfile )
else :
messages = self . logfile
2013-01-23 17:28:19 +00:00
d = os . path . dirname ( messages )
2011-01-18 09:24:57 +00:00
if not os . path . exists ( d ) :
os . makedirs ( d )
else :
2013-01-23 17:28:19 +00:00
# Always log outside the chroot, we copy those logs into the
# chroot later.
messages = " /tmp/ %s .log " % os . path . basename ( path )
2011-01-18 09:24:57 +00:00
rc = iutil . execWithRedirect ( self . interp , [ " /tmp/ %s " % os . path . basename ( path ) ] ,
stdin = messages , stdout = messages , stderr = messages ,
root = scriptRoot )
# Always log an error. Only fail if we have a handle on the
# windowing system and the kickstart file included --erroronfail.
if rc != 0 :
log . error ( " Error code %s running the kickstart script at line %s " % ( rc , self . lineno ) )
2013-01-23 17:28:19 +00:00
if os . path . isfile ( messages ) :
try :
f = open ( messages , " r " )
except IOError as e :
err = None
else :
err = f . readlines ( )
f . close ( )
for l in err :
log . error ( " \t %s " % l )
2011-01-18 09:24:57 +00:00
if self . errorOnFail :
2013-01-23 17:28:19 +00:00
errorHandler . cb ( ScriptError ( ) , self . lineno , err )
2011-01-18 09:24:57 +00:00
sys . exit ( 0 )
2013-01-23 17:28:19 +00:00
class AnacondaInternalScript ( AnacondaKSScript ) :
def __init__ ( self , * args , * * kwargs ) :
AnacondaKSScript . __init__ ( self , * args , * * kwargs )
self . _hidden = True
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
def __str__ ( self ) :
# Scripts that implement portions of anaconda (copying screenshots and
# log files, setfilecons, etc.) should not be written to the output
# kickstart file.
return " "
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
def getEscrowCertificate ( escrowCerts , url ) :
2011-01-18 09:24:57 +00:00
if not url :
return None
2013-01-23 17:28:19 +00:00
if url in escrowCerts :
return escrowCerts [ url ]
2011-01-18 09:24:57 +00:00
needs_net = not url . startswith ( " / " ) and not url . startswith ( " file: " )
if needs_net and not network . hasActiveNetDev ( ) :
2013-01-23 17:28:19 +00:00
msg = _ ( " Escrow certificate %s requires the network. " ) % url
raise KickstartError ( msg )
2011-01-18 09:24:57 +00:00
log . info ( " escrow: downloading %s " % ( url , ) )
2013-01-23 17:28:19 +00:00
try :
f = urlgrabber . urlopen ( url )
except urlgrabber . grabber . URLGrabError as e :
msg = _ ( " The following error was encountered while downloading the escrow certificate: \n \n %s " % e )
raise KickstartError ( msg )
2011-01-18 09:24:57 +00:00
try :
2013-01-23 17:28:19 +00:00
escrowCerts [ url ] = f . read ( )
2011-01-18 09:24:57 +00:00
finally :
f . close ( )
2013-01-23 17:28:19 +00:00
return escrowCerts [ url ]
def detect_multipaths ( ) :
global topology
mcw = MultipathConfigWriter ( )
cfg = mcw . write ( friendly_names = True )
with open ( " /etc/multipath.conf " , " w+ " ) as mpath_cfg :
mpath_cfg . write ( cfg )
devices = udev_get_block_devices ( )
topology = MultipathTopology ( devices )
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
def deviceMatches ( spec ) :
full_spec = spec
if not full_spec . startswith ( " /dev/ " ) :
full_spec = os . path . normpath ( " /dev/ " + full_spec )
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
# the regular case
matches = udev_resolve_glob ( full_spec )
dev = udev_resolve_devspec ( full_spec )
2011-01-18 09:24:57 +00:00
# udev_resolve_devspec returns None if there's no match, but we don't
# want that ending up in the list.
if dev and dev not in matches :
matches . append ( dev )
2013-01-23 17:28:19 +00:00
# now see if any mpaths and mpath members match
for members in topology . multipaths_iter ( ) :
mpath_name = udev_device_get_multipath_name ( members [ 0 ] )
member_names = map ( udev_device_get_name , members )
if mpath_name == spec or ( dev in member_names ) :
# append the entire mpath
matches . append ( mpath_name )
matches . extend ( member_names )
2011-01-18 09:24:57 +00:00
return matches
2013-01-23 17:28:19 +00:00
def lookupAlias ( devicetree , alias ) :
for dev in devicetree . devices :
if getattr ( dev , " req_name " , None ) == alias :
return dev
return None
2011-01-18 09:24:57 +00:00
# Remove any existing formatting on a device, but do not remove the partition
# itself. This sets up an existing device to be used in a --onpart option.
def removeExistingFormat ( device , storage ) :
deps = storage . deviceDeps ( device )
while deps :
leaves = [ d for d in deps if d . isleaf ]
for leaf in leaves :
storage . destroyDevice ( leaf )
deps . remove ( leaf )
storage . devicetree . registerAction ( ActionDestroyFormat ( device ) )
###
### SUBCLASSES OF PYKICKSTART COMMAND HANDLERS
###
class Authconfig ( commands . authconfig . FC3_Authconfig ) :
2013-01-23 17:28:19 +00:00
def execute ( self , * args ) :
args = [ " --update " , " --nostart " ] + shlex . split ( self . authconfig )
if not flags . automatedInstall and \
( os . path . exists ( ROOT_PATH + " /lib64/security/pam_fprintd.so " ) or \
os . path . exists ( ROOT_PATH + " /lib/security/pam_fprintd.so " ) ) :
args + = [ " --enablefingerprint " ]
try :
iutil . execWithRedirect ( " /usr/sbin/authconfig " , args ,
stdout = " /dev/tty5 " , stderr = " /dev/tty5 " ,
root = ROOT_PATH )
except RuntimeError as msg :
log . error ( " Error running /usr/sbin/authconfig %s : %s " , args , msg )
2013-02-12 01:30:05 +00:00
class AutoPart ( commands . autopart . F18_AutoPart ) :
2013-01-26 21:29:36 +00:00
def __init__ ( self , writePriority = 100 , * args , * * kwargs ) :
if ' encrypted ' not in kwargs :
kwargs [ ' encrypted ' ] = True
2013-02-12 01:30:05 +00:00
super ( AutoPart , self ) . __init__ ( writePriority = writePriority , * args , * * kwargs )
2013-01-26 21:29:36 +00:00
2013-01-23 17:28:19 +00:00
def execute ( self , storage , ksdata , instClass ) :
from pyanaconda . storage . partitioning import doAutoPartition
if not self . autopart :
return
2011-01-18 09:24:57 +00:00
# sets up default autopartitioning. use clearpart separately
# if you want it
2013-01-23 17:28:19 +00:00
instClass . setDefaultPartitioning ( storage )
storage . doAutoPart = True
2011-01-18 09:24:57 +00:00
if self . encrypted :
2013-01-23 17:28:19 +00:00
storage . encryptedAutoPart = True
storage . encryptionPassphrase = self . passphrase
storage . encryptionCipher = self . cipher
storage . autoPartEscrowCert = getEscrowCertificate ( storage . escrowCertificates , self . escrowcert )
storage . autoPartAddBackupPassphrase = self . backuppassphrase
if self . type is not None :
storage . autoPartType = self . type
doAutoPartition ( storage , ksdata )
class Bootloader ( commands . bootloader . F18_Bootloader ) :
def execute ( self , storage , ksdata , instClass ) :
2011-01-18 09:24:57 +00:00
if self . location == " none " :
location = None
elif self . location == " partition " :
location = " boot "
else :
location = self . location
2013-01-23 17:28:19 +00:00
if self . upgrade and not flags . cmdline . has_key ( " preupgrade " ) :
2011-01-18 09:24:57 +00:00
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Selected upgrade mode for bootloader but not doing an upgrade " )
2013-01-23 17:28:19 +00:00
if self . upgrade and storage . bootloader . can_update :
storage . bootloader . update_only = True
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
if not location :
storage . bootloader . skip_bootloader = True
return
if self . appendLine :
args = self . appendLine . split ( )
storage . bootloader . boot_args . update ( args )
if self . password :
if self . isCrypted :
storage . bootloader . encrypted_password = self . password
else :
storage . bootloader . password = self . password
if location :
storage . bootloader . set_preferred_stage1_type ( location )
if self . timeout is not None :
storage . bootloader . timeout = self . timeout
# Throw out drives specified that don't exist.
disk_names = [ d . name for d in storage . disks
if not d . format . hidden and not d . protected ]
for drive in self . driveorder [ : ] :
if drive not in disk_names :
log . warning ( " requested drive %s in boot drive order doesn ' t exist " % drive )
self . driveorder . remove ( drive )
storage . bootloader . disk_order = self . driveorder
if self . bootDrive :
if not self . bootDrive in disk_names :
raise KickstartValueError , formatErrorMsg ( self . lineno ,
msg = " Requested boot drive %s doesn ' t exist " % self . bootDrive )
2011-01-18 09:24:57 +00:00
else :
2013-01-23 17:28:19 +00:00
self . bootDrive = disk_names [ 0 ]
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
spec = udev_resolve_devspec ( self . bootDrive )
drive = storage . devicetree . getDeviceByName ( spec )
storage . bootloader . stage1_disk = drive
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
if self . leavebootorder :
flags . leavebootorder = True
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
class BTRFS ( commands . btrfs . F17_BTRFS ) :
def execute ( self , storage , ksdata , instClass ) :
for b in self . btrfsList :
b . execute ( storage , ksdata , instClass )
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
class BTRFSData ( commands . btrfs . F17_BTRFSData ) :
def execute ( self , storage , ksdata , instClass ) :
devicetree = storage . devicetree
storage . doAutoPart = False
members = [ ]
# Get a list of all the devices that make up this volume.
for member in self . devices :
# if using --onpart, use original device
member_name = ksdata . onPart . get ( member , member )
if member_name :
dev = devicetree . getDeviceByName ( member_name ) or lookupAlias ( devicetree , member )
if not dev :
dev = devicetree . resolveDevice ( member )
if dev and dev . format . type == " luks " :
try :
dev = devicetree . getChildren ( dev ) [ 0 ]
except IndexError :
dev = None
if not dev :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Tried to use undefined partition %s in BTRFS volume specification " % member )
members . append ( dev )
if self . subvol :
name = self . name
elif self . label :
name = self . label
else :
name = None
if len ( members ) == 0 and not self . preexist :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " BTRFS volume defined without any member devices. Either specify member devices or use --useexisting. " )
# allow creating btrfs vols/subvols without specifying mountpoint
if self . mountpoint in ( " none " , " None " ) :
self . mountpoint = " "
# Sanity check mountpoint
if self . mountpoint != " " and self . mountpoint [ 0 ] != ' / ' :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " The mount point \" %s \" is not valid. " % ( self . mountpoint , ) )
if self . preexist :
device = devicetree . getDeviceByName ( self . name )
if not device :
device = udev_resolve_devspec ( self . name )
if not device :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Specified nonexistent BTRFS volume %s in btrfs command " % self . name )
else :
# If a previous device has claimed this mount point, delete the
# old one.
try :
if self . mountpoint :
device = storage . mountpoints [ self . mountpoint ]
storage . destroyDevice ( device )
except KeyError :
pass
request = storage . newBTRFS ( name = name ,
subvol = self . subvol ,
mountpoint = self . mountpoint ,
metaDataLevel = self . metaDataLevel ,
dataLevel = self . dataLevel ,
parents = members )
storage . createDevice ( request )
class ClearPart ( commands . clearpart . F17_ClearPart ) :
2011-01-18 09:24:57 +00:00
def parse ( self , args ) :
2013-01-23 17:28:19 +00:00
retval = commands . clearpart . F17_ClearPart . parse ( self , args )
2011-01-18 09:24:57 +00:00
if self . type is None :
self . type = CLEARPART_TYPE_NONE
# Do any glob expansion now, since we need to have the real list of
# disks available before the execute methods run.
drives = [ ]
for spec in self . drives :
matched = deviceMatches ( spec )
if matched :
drives . extend ( matched )
else :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Specified nonexistent disk %s in clearpart command " % spec )
self . drives = drives
2013-01-23 17:28:19 +00:00
# Do any glob expansion now, since we need to have the real list of
# devices available before the execute methods run.
devices = [ ]
for spec in self . devices :
matched = deviceMatches ( spec )
if matched :
devices . extend ( matched )
else :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Specified nonexistent device %s in clearpart device list " % spec )
self . devices = devices
2011-01-18 09:24:57 +00:00
return retval
2013-01-23 17:28:19 +00:00
def execute ( self , storage , ksdata , instClass ) :
storage . config . clearPartType = self . type
storage . config . clearPartDisks = self . drives
storage . config . clearPartDevices = self . devices
2011-01-18 09:24:57 +00:00
if self . initAll :
2013-01-23 17:28:19 +00:00
storage . config . initializeDisks = self . initAll
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
storage . clearPartitions ( )
2011-01-18 09:24:57 +00:00
class Fcoe ( commands . fcoe . F13_Fcoe ) :
def parse ( self , args ) :
fc = commands . fcoe . F13_Fcoe . parse ( self , args )
if fc . nic not in isys . getDeviceProperties ( ) :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Specified nonexistent nic %s in fcoe command " % fc . nic )
2013-01-23 17:28:19 +00:00
storage . fcoe . fcoe ( ) . addSan ( nic = fc . nic , dcb = fc . dcb , auto_vlan = True )
2011-01-18 09:24:57 +00:00
return fc
2013-01-23 17:28:19 +00:00
class Firewall ( commands . firewall . F14_Firewall ) :
def execute ( self , storage , ksdata , instClass ) :
args = [ ]
# enabled is None if neither --enable or --disable is passed
# default to enabled if nothing has been set.
if self . enabled == False :
args + = [ " --disabled " ]
else :
args + = [ " --enabled " ]
if not " ssh " in self . services and not " 22:tcp " in self . ports :
args + = [ " --service=ssh " ]
for dev in self . trusts :
args + = [ " --trust= %s " % ( dev , ) ]
2011-01-18 09:24:57 +00:00
for port in self . ports :
2013-01-23 17:28:19 +00:00
args + = [ " --port= %s " % ( port , ) ]
for service in self . services :
args + = [ " --service= %s " % ( service , ) ]
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
cmd = " /usr/bin/firewall-offline-cmd "
if not os . path . exists ( ROOT_PATH + cmd ) :
msg = _ ( " %s is missing. Cannot setup firewall. " ) % ( cmd , )
raise KickstartError ( msg )
else :
iutil . execWithRedirect ( cmd , args ,
stdout = " /dev/tty5 " , stderr = " /dev/tty5 " ,
root = ROOT_PATH )
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
class Firstboot ( commands . firstboot . FC3_Firstboot ) :
def execute ( self , * args ) :
if not os . path . exists ( ROOT_PATH + " /lib/systemd/system/firstboot-graphical.service " ) :
return
action = " enable "
if self . firstboot == FIRSTBOOT_SKIP :
action = " disable "
elif self . firstboot == FIRSTBOOT_RECONFIG :
f = open ( ROOT_PATH + " /etc/reconfigSys " , " w+ " )
f . close ( )
iutil . execWithRedirect ( " systemctl " , [ action , " firstboot-graphical.service " ] ,
stdout = " /dev/tty5 " , stderr = " /dev/tty5 " ,
root = ROOT_PATH )
class Group ( commands . group . F12_Group ) :
def execute ( self , storage , ksdata , instClass , users ) :
algo = getPassAlgo ( ksdata . authconfig . authconfig )
for grp in self . groupList :
kwargs = grp . __dict__
kwargs . update ( { " root " : ROOT_PATH } )
if not users . createGroup ( grp . name , * * kwargs ) :
log . error ( " Group %s already exists, not creating. " % grp . name )
class IgnoreDisk ( commands . ignoredisk . RHEL6_IgnoreDisk ) :
2011-01-18 09:24:57 +00:00
def parse ( self , args ) :
2013-01-23 17:28:19 +00:00
retval = commands . ignoredisk . RHEL6_IgnoreDisk . parse ( self , args )
2011-01-18 09:24:57 +00:00
# See comment in ClearPart.parse
drives = [ ]
for spec in self . ignoredisk :
matched = deviceMatches ( spec )
if matched :
drives . extend ( matched )
else :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Specified nonexistent disk %s in ignoredisk command " % spec )
self . ignoredisk = drives
drives = [ ]
for spec in self . onlyuse :
matched = deviceMatches ( spec )
if matched :
drives . extend ( matched )
else :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Specified nonexistent disk %s in ignoredisk command " % spec )
self . onlyuse = drives
return retval
2013-01-23 17:28:19 +00:00
class Iscsi ( commands . iscsi . F17_Iscsi ) :
2011-01-18 09:24:57 +00:00
def parse ( self , args ) :
2013-01-23 17:28:19 +00:00
tg = commands . iscsi . F17_Iscsi . parse ( self , args )
if tg . iface :
active_ifaces = network . getActiveNetDevs ( )
if tg . iface not in active_ifaces :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " network interface %s required by iscsi %s target is not up " % ( tg . iface , tg . target ) )
mode = storage . iscsi . iscsi ( ) . mode
if mode == " none " :
if tg . iface :
storage . iscsi . iscsi ( ) . create_interfaces ( active_ifaces )
elif ( ( mode == " bind " and not tg . iface )
or ( mode == " default " and tg . iface ) ) :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " iscsi --iface must be specified (binding used) either for all targets or for none " )
2011-01-18 09:24:57 +00:00
try :
2013-01-23 17:28:19 +00:00
storage . iscsi . iscsi ( ) . addTarget ( tg . ipaddr , tg . port , tg . user ,
tg . password , tg . user_in ,
tg . password_in ,
target = tg . target ,
iface = tg . iface )
log . info ( " added iscsi target %s at %s via %s " % ( tg . target ,
tg . ipaddr ,
tg . iface ) )
except ( IOError , ValueError ) as e :
2011-01-18 09:24:57 +00:00
raise KickstartValueError , formatErrorMsg ( self . lineno ,
msg = str ( e ) )
2013-01-23 17:28:19 +00:00
2011-01-18 09:24:57 +00:00
return tg
class IscsiName ( commands . iscsiname . FC6_IscsiName ) :
def parse ( self , args ) :
retval = commands . iscsiname . FC6_IscsiName . parse ( self , args )
storage . iscsi . iscsi ( ) . initiator = self . iscsiname
return retval
class Lang ( commands . lang . FC3_Lang ) :
2013-01-23 17:28:19 +00:00
def execute ( self , * args , * * kwargs ) :
localization . write_language_configuration ( self , ROOT_PATH )
class LogVol ( commands . logvol . F18_LogVol ) :
def execute ( self , storage , ksdata , instClass ) :
for l in self . lvList :
l . execute ( storage , ksdata , instClass )
if self . lvList :
growLVM ( storage )
class LogVolData ( commands . logvol . F18_LogVolData ) :
def execute ( self , storage , ksdata , instClass ) :
2011-01-18 09:24:57 +00:00
devicetree = storage . devicetree
storage . doAutoPart = False
if self . mountpoint == " swap " :
type = " swap "
self . mountpoint = " "
2013-01-23 17:28:19 +00:00
if self . recommended or self . hibernation :
self . size = swap . swapSuggestion ( hibernation = self . hibernation )
self . grow = False
2011-01-18 09:24:57 +00:00
else :
if self . fstype != " " :
type = self . fstype
else :
type = storage . defaultFSType
# Sanity check mountpoint
if self . mountpoint != " " and self . mountpoint [ 0 ] != ' / ' :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " The mount point \" %s \" is not valid. " % ( self . mountpoint , ) )
# Check that the VG this LV is a member of has already been specified.
vg = devicetree . getDeviceByName ( self . vgname )
if not vg :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " No volume group exists with the name \" %s \" . Specify volume groups before logical volumes. " % self . vgname )
# If this specifies an existing request that we should not format,
# quit here after setting up enough information to mount it later.
if not self . format :
if not self . name :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " --noformat used without --name " )
dev = devicetree . getDeviceByName ( " %s - %s " % ( vg . name , self . name ) )
if not dev :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " No preexisting logical volume with the name \" %s \" was found. " % self . name )
2013-01-23 17:28:19 +00:00
if self . resize :
if self . size < dev . currentSize :
# shrink
try :
devicetree . registerAction ( ActionResizeFormat ( dev , self . size ) )
devicetree . registerAction ( ActionResizeDevice ( dev , self . size ) )
except ValueError :
raise KickstartValueError ( formatErrorMsg ( self . lineno ,
msg = " Invalid target size ( %d ) for device %s " % ( self . size , dev . name ) ) )
else :
# grow
try :
devicetree . registerAction ( ActionResizeDevice ( dev , self . size ) )
devicetree . registerAction ( ActionResizeFormat ( dev , self . size ) )
except ValueError :
raise KickstartValueError ( formatErrorMsg ( self . lineno ,
msg = " Invalid target size ( %d ) for device %s " % ( self . size , dev . name ) ) )
2011-01-18 09:24:57 +00:00
dev . format . mountpoint = self . mountpoint
dev . format . mountopts = self . fsopts
return
# Make sure this LV name is not already used in the requested VG.
if not self . preexist :
tmp = devicetree . getDeviceByName ( " %s - %s " % ( vg . name , self . name ) )
if tmp :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Logical volume name already used in volume group %s " % vg . name )
# Size specification checks
if not self . percent :
if not self . size :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Size required " )
elif not self . grow and self . size * 1024 < vg . peSize :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Logical volume size must be larger than the volume group physical extent size. " )
elif self . percent < = 0 or self . percent > 100 :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Percentage must be between 0 and 100 " )
# Now get a format to hold a lot of these extra values.
format = getFormat ( type ,
mountpoint = self . mountpoint ,
2013-01-23 17:28:19 +00:00
label = self . label ,
fsprofile = self . fsprofile ,
2011-01-18 09:24:57 +00:00
mountopts = self . fsopts )
2013-01-23 17:28:19 +00:00
if not format . type :
2011-01-18 09:24:57 +00:00
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " The \" %s \" filesystem type is not supported. " % type )
# If we were given a pre-existing LV to create a filesystem on, we need
# to verify it and its VG exists and then schedule a new format action
# to take place there. Also, we only support a subset of all the
# options on pre-existing LVs.
if self . preexist :
device = devicetree . getDeviceByName ( " %s - %s " % ( vg . name , self . name ) )
if not device :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Specified nonexistent LV %s in logvol command " % self . name )
removeExistingFormat ( device , storage )
2013-01-23 17:28:19 +00:00
if self . resize :
try :
devicetree . registerAction ( ActionResizeDevice ( device , self . size ) )
except ValueError :
raise KickstartValueError ( formatErrorMsg ( self . lineno ,
msg = " Invalid target size ( %d ) for device %s " % ( self . size , device . name ) ) )
2011-01-18 09:24:57 +00:00
devicetree . registerAction ( ActionCreateFormat ( device , format ) )
else :
# If a previous device has claimed this mount point, delete the
# old one.
try :
if self . mountpoint :
device = storage . mountpoints [ self . mountpoint ]
storage . destroyDevice ( device )
except KeyError :
pass
request = storage . newLV ( format = format ,
name = self . name ,
2013-01-23 17:28:19 +00:00
parents = [ vg ] ,
2011-01-18 09:24:57 +00:00
size = self . size ,
grow = self . grow ,
maxsize = self . maxSizeMB ,
percent = self . percent )
storage . createDevice ( request )
if self . encrypted :
if self . passphrase and not storage . encryptionPassphrase :
storage . encryptionPassphrase = self . passphrase
2013-01-23 17:28:19 +00:00
cert = getEscrowCertificate ( storage . escrowCertificates , self . escrowcert )
2011-01-18 09:24:57 +00:00
if self . preexist :
luksformat = format
device . format = getFormat ( " luks " , passphrase = self . passphrase , device = device . path ,
2013-01-23 17:28:19 +00:00
cipher = self . cipher ,
2011-01-18 09:24:57 +00:00
escrow_cert = cert ,
add_backup_passphrase = self . backuppassphrase )
luksdev = LUKSDevice ( " luks %d " % storage . nextID ,
format = luksformat ,
parents = device )
else :
luksformat = request . format
request . format = getFormat ( " luks " , passphrase = self . passphrase ,
2013-01-23 17:28:19 +00:00
cipher = self . cipher ,
2011-01-18 09:24:57 +00:00
escrow_cert = cert ,
add_backup_passphrase = self . backuppassphrase )
luksdev = LUKSDevice ( " luks %d " % storage . nextID ,
format = luksformat ,
parents = request )
storage . createDevice ( luksdev )
class Logging ( commands . logging . FC6_Logging ) :
2013-01-23 17:28:19 +00:00
def execute ( self , * args ) :
2011-01-18 09:24:57 +00:00
if logger . tty_loglevel == DEFAULT_TTY_LEVEL :
# not set from the command line
level = logLevelMap [ self . level ]
logger . tty_loglevel = level
setHandlersLevel ( log , level )
setHandlersLevel ( storage_log , level )
if logger . remote_syslog == None and len ( self . host ) > 0 :
# not set from the command line, ok to use kickstart
remote_server = self . host
if self . port :
remote_server = " %s : %s " % ( self . host , self . port )
logger . updateRemote ( remote_server )
2013-01-23 17:28:19 +00:00
class Network ( commands . network . F18_Network ) :
def execute ( self , storage , ksdata , instClass ) :
network . write_network_config ( storage , ksdata , instClass , ROOT_PATH )
2011-01-18 09:24:57 +00:00
class MultiPath ( commands . multipath . FC6_MultiPath ) :
def parse ( self , args ) :
raise NotImplementedError ( " The multipath kickstart command is not currently supported " )
class DmRaid ( commands . dmraid . FC6_DmRaid ) :
def parse ( self , args ) :
raise NotImplementedError ( " The dmraid kickstart command is not currently supported " )
2013-01-23 17:28:19 +00:00
class Partition ( commands . partition . F18_Partition ) :
def execute ( self , storage , ksdata , instClass ) :
for p in self . partitions :
p . execute ( storage , ksdata , instClass )
if self . partitions :
doPartitioning ( storage )
class PartitionData ( commands . partition . F18_PartData ) :
def execute ( self , storage , ksdata , instClass ) :
2011-01-18 09:24:57 +00:00
devicetree = storage . devicetree
kwargs = { }
storage . doAutoPart = False
if self . onbiosdisk != " " :
for ( disk , biosdisk ) in storage . eddDict . iteritems ( ) :
2013-01-23 17:28:19 +00:00
if " %x " % biosdisk == self . onbiosdisk :
2011-01-18 09:24:57 +00:00
self . disk = disk
break
2013-01-23 17:28:19 +00:00
if not self . disk :
2011-01-18 09:24:57 +00:00
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Specified BIOS disk %s cannot be determined " % self . onbiosdisk )
if self . mountpoint == " swap " :
type = " swap "
self . mountpoint = " "
2013-01-23 17:28:19 +00:00
if self . recommended or self . hibernation :
self . size = swap . swapSuggestion ( hibernation = self . hibernation )
self . grow = False
2011-01-18 09:24:57 +00:00
# if people want to specify no mountpoint for some reason, let them
# this is really needed for pSeries boot partitions :(
elif self . mountpoint == " None " :
self . mountpoint = " "
if self . fstype :
type = self . fstype
else :
type = storage . defaultFSType
elif self . mountpoint == ' appleboot ' :
2013-01-23 17:28:19 +00:00
type = " appleboot "
2011-01-18 09:24:57 +00:00
self . mountpoint = " "
elif self . mountpoint == ' prepboot ' :
2013-01-23 17:28:19 +00:00
type = " prepboot "
self . mountpoint = " "
elif self . mountpoint == ' biosboot ' :
type = " biosboot "
2011-01-18 09:24:57 +00:00
self . mountpoint = " "
elif self . mountpoint . startswith ( " raid. " ) :
type = " mdmember "
kwargs [ " name " ] = self . mountpoint
2013-01-23 17:28:19 +00:00
self . mountpoint = " "
2011-01-18 09:24:57 +00:00
if devicetree . getDeviceByName ( kwargs [ " name " ] ) :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " RAID partition defined multiple times " )
if self . onPart :
2013-01-23 17:28:19 +00:00
ksdata . onPart [ kwargs [ " name " ] ] = self . onPart
2011-01-18 09:24:57 +00:00
elif self . mountpoint . startswith ( " pv. " ) :
type = " lvmpv "
kwargs [ " name " ] = self . mountpoint
2013-01-23 17:28:19 +00:00
self . mountpoint = " "
2011-01-18 09:24:57 +00:00
if devicetree . getDeviceByName ( kwargs [ " name " ] ) :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " PV partition defined multiple times " )
if self . onPart :
2013-01-23 17:28:19 +00:00
ksdata . onPart [ kwargs [ " name " ] ] = self . onPart
elif self . mountpoint . startswith ( " btrfs. " ) :
type = " btrfs "
kwargs [ " name " ] = self . mountpoint
2011-01-18 09:24:57 +00:00
self . mountpoint = " "
2013-01-23 17:28:19 +00:00
if devicetree . getDeviceByName ( kwargs [ " name " ] ) :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " BTRFS partition defined multiple times " )
if self . onPart :
ksdata . onPart [ kwargs [ " name " ] ] = self . onPart
2011-01-18 09:24:57 +00:00
elif self . mountpoint == " /boot/efi " :
2013-01-23 17:28:19 +00:00
if iutil . isMactel ( ) :
type = " hfs+ "
else :
type = " EFI System Partition "
self . fsopts = " defaults,uid=0,gid=0,umask=0077,shortname=winnt "
2011-01-18 09:24:57 +00:00
else :
if self . fstype != " " :
type = self . fstype
elif self . mountpoint == " /boot " :
2013-01-23 17:28:19 +00:00
type = storage . defaultBootFSType
2011-01-18 09:24:57 +00:00
else :
type = storage . defaultFSType
# If this specified an existing request that we should not format,
# quit here after setting up enough information to mount it later.
if not self . format :
if not self . onPart :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " --noformat used without --onpart " )
dev = devicetree . getDeviceByName ( udev_resolve_devspec ( self . onPart ) )
if not dev :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " No preexisting partition with the name \" %s \" was found. " % self . onPart )
2013-01-23 17:28:19 +00:00
if self . resize :
if self . size < dev . currentSize :
# shrink
try :
devicetree . registerAction ( ActionResizeFormat ( dev , self . size ) )
devicetree . registerAction ( ActionResizeDevice ( dev , self . size ) )
except ValueError :
raise KickstartValueError ( formatErrorMsg ( self . lineno ,
msg = " Invalid target size ( %d ) for device %s " % ( self . size , dev . name ) ) )
else :
# grow
try :
devicetree . registerAction ( ActionResizeDevice ( dev , self . size ) )
devicetree . registerAction ( ActionResizeFormat ( dev , self . size ) )
except ValueError :
raise KickstartValueError ( formatErrorMsg ( self . lineno ,
msg = " Invalid target size ( %d ) for device %s " % ( self . size , dev . name ) ) )
2011-01-18 09:24:57 +00:00
dev . format . mountpoint = self . mountpoint
dev . format . mountopts = self . fsopts
return
# Now get a format to hold a lot of these extra values.
kwargs [ " format " ] = getFormat ( type ,
mountpoint = self . mountpoint ,
label = self . label ,
2013-01-23 17:28:19 +00:00
fsprofile = self . fsprofile ,
2011-01-18 09:24:57 +00:00
mountopts = self . fsopts )
2013-01-23 17:28:19 +00:00
if not kwargs [ " format " ] . type :
2011-01-18 09:24:57 +00:00
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " The \" %s \" filesystem type is not supported. " % type )
# If we were given a specific disk to create the partition on, verify
# that it exists first. If it doesn't exist, see if it exists with
# mapper/ on the front. If that doesn't exist either, it's an error.
if self . disk :
names = [ self . disk , " mapper/ " + self . disk ]
for n in names :
disk = devicetree . getDeviceByName ( udev_resolve_devspec ( n ) )
2013-01-23 17:28:19 +00:00
# if this is a multipath member promote it to the real mpath
if disk and disk . format . type == " multipath_member " :
mpath_device = storage . devicetree . getChildren ( disk ) [ 0 ]
storage_log . info ( " kickstart: part: promoting %s to %s "
% ( disk . name , mpath_device . name ) )
disk = mpath_device
2011-01-18 09:24:57 +00:00
if not disk :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Specified nonexistent disk %s in partition command " % n )
2013-01-23 17:28:19 +00:00
if not disk . partitionable :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Cannot install to read-only media %s . " % n )
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
should_clear = storage . shouldClear ( disk )
2011-01-18 09:24:57 +00:00
if disk and ( disk . partitioned or should_clear ) :
2013-01-23 17:28:19 +00:00
kwargs [ " parents " ] = [ disk ]
2011-01-18 09:24:57 +00:00
break
elif disk :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Specified unpartitioned disk %s in partition command " % self . disk )
2013-01-23 17:28:19 +00:00
if not kwargs [ " parents " ] :
2011-01-18 09:24:57 +00:00
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Specified nonexistent disk %s in partition command " % self . disk )
kwargs [ " grow " ] = self . grow
kwargs [ " size " ] = self . size
kwargs [ " maxsize " ] = self . maxSizeMB
kwargs [ " primary " ] = self . primOnly
# If we were given a pre-existing partition to create a filesystem on,
# we need to verify it exists and then schedule a new format action to
# take place there. Also, we only support a subset of all the options
# on pre-existing partitions.
if self . onPart :
device = devicetree . getDeviceByName ( udev_resolve_devspec ( self . onPart ) )
if not device :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Specified nonexistent partition %s in partition command " % self . onPart )
removeExistingFormat ( device , storage )
2013-01-23 17:28:19 +00:00
if self . resize :
try :
devicetree . registerAction ( ActionResizeDevice ( device , self . size ) )
except ValueError :
raise KickstartValueError ( formatErrorMsg ( self . lineno ,
msg = " Invalid target size ( %d ) for device %s " % ( self . size , device . name ) ) )
2011-01-18 09:24:57 +00:00
devicetree . registerAction ( ActionCreateFormat ( device , kwargs [ " format " ] ) )
else :
# If a previous device has claimed this mount point, delete the
# old one.
try :
if self . mountpoint :
device = storage . mountpoints [ self . mountpoint ]
storage . destroyDevice ( device )
except KeyError :
pass
request = storage . newPartition ( * * kwargs )
storage . createDevice ( request )
if self . encrypted :
if self . passphrase and not storage . encryptionPassphrase :
storage . encryptionPassphrase = self . passphrase
2013-01-23 17:28:19 +00:00
cert = getEscrowCertificate ( storage . escrowCertificates , self . escrowcert )
2011-01-18 09:24:57 +00:00
if self . onPart :
luksformat = format
device . format = getFormat ( " luks " , passphrase = self . passphrase , device = device . path ,
2013-01-23 17:28:19 +00:00
cipher = self . cipher ,
2011-01-18 09:24:57 +00:00
escrow_cert = cert ,
add_backup_passphrase = self . backuppassphrase )
luksdev = LUKSDevice ( " luks %d " % storage . nextID ,
format = luksformat ,
parents = device )
else :
luksformat = request . format
request . format = getFormat ( " luks " , passphrase = self . passphrase ,
2013-01-23 17:28:19 +00:00
cipher = self . cipher ,
2011-01-18 09:24:57 +00:00
escrow_cert = cert ,
add_backup_passphrase = self . backuppassphrase )
luksdev = LUKSDevice ( " luks %d " % storage . nextID ,
format = luksformat ,
parents = request )
storage . createDevice ( luksdev )
2013-01-23 17:28:19 +00:00
class Raid ( commands . raid . F18_Raid ) :
def execute ( self , storage , ksdata , instClass ) :
for r in self . raidList :
r . execute ( storage , ksdata , instClass )
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
class RaidData ( commands . raid . F18_RaidData ) :
def execute ( self , storage , ksdata , instClass ) :
2011-01-18 09:24:57 +00:00
raidmems = [ ]
devicename = " md %d " % self . device
devicetree = storage . devicetree
kwargs = { }
storage . doAutoPart = False
if self . mountpoint == " swap " :
type = " swap "
self . mountpoint = " "
elif self . mountpoint . startswith ( " pv. " ) :
type = " lvmpv "
kwargs [ " name " ] = self . mountpoint
2013-01-23 17:28:19 +00:00
ksdata . onPart [ kwargs [ " name " ] ] = devicename
2011-01-18 09:24:57 +00:00
if devicetree . getDeviceByName ( kwargs [ " name " ] ) :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " PV partition defined multiple times " )
2013-01-23 17:28:19 +00:00
self . mountpoint = " "
elif self . mountpoint . startswith ( " btrfs. " ) :
type = " btrfs "
kwargs [ " name " ] = self . mountpoint
ksdata . onPart [ kwargs [ " name " ] ] = devicename
if devicetree . getDeviceByName ( kwargs [ " name " ] ) :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " BTRFS partition defined multiple times " )
2011-01-18 09:24:57 +00:00
self . mountpoint = " "
else :
if self . fstype != " " :
type = self . fstype
2013-01-23 17:28:19 +00:00
elif self . mountpoint == " /boot " and \
" mdarray " in storage . bootloader . stage2_device_types :
type = storage . defaultBootFSType
2011-01-18 09:24:57 +00:00
else :
type = storage . defaultFSType
# Sanity check mountpoint
if self . mountpoint != " " and self . mountpoint [ 0 ] != ' / ' :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " The mount point is not valid. " )
# If this specifies an existing request that we should not format,
# quit here after setting up enough information to mount it later.
if not self . format :
if not devicename :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " --noformat used without --device " )
dev = devicetree . getDeviceByName ( devicename )
if not dev :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " No preexisting RAID device with the name \" %s \" was found. " % devicename )
dev . format . mountpoint = self . mountpoint
dev . format . mountopts = self . fsopts
return
# Get a list of all the RAID members.
for member in self . members :
# if member is using --onpart, use original device
2013-01-23 17:28:19 +00:00
mem = ksdata . onPart . get ( member , member )
dev = devicetree . getDeviceByName ( mem ) or lookupAlias ( devicetree , mem )
2011-01-18 09:24:57 +00:00
if dev and dev . format . type == " luks " :
try :
dev = devicetree . getChildren ( dev ) [ 0 ]
except IndexError :
dev = None
if not dev :
2013-01-23 17:28:19 +00:00
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Tried to use undefined partition %s in RAID specification " % mem )
2011-01-18 09:24:57 +00:00
raidmems . append ( dev )
# Now get a format to hold a lot of these extra values.
kwargs [ " format " ] = getFormat ( type ,
2013-01-23 17:28:19 +00:00
label = self . label ,
fsprofile = self . fsprofile ,
2011-01-18 09:24:57 +00:00
mountpoint = self . mountpoint ,
mountopts = self . fsopts )
2013-01-23 17:28:19 +00:00
if not kwargs [ " format " ] . type :
2011-01-18 09:24:57 +00:00
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " The \" %s \" filesystem type is not supported. " % type )
kwargs [ " name " ] = devicename
kwargs [ " level " ] = self . level
kwargs [ " parents " ] = raidmems
2013-01-23 17:28:19 +00:00
kwargs [ " memberDevices " ] = len ( raidmems ) - self . spares
kwargs [ " totalDevices " ] = len ( raidmems )
2011-01-18 09:24:57 +00:00
# If we were given a pre-existing RAID to create a filesystem on,
# we need to verify it exists and then schedule a new format action
# to take place there. Also, we only support a subset of all the
# options on pre-existing RAIDs.
if self . preexist :
device = devicetree . getDeviceByName ( devicename )
if not device :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Specifeid nonexistent RAID %s in raid command " % devicename )
removeExistingFormat ( device , storage )
devicetree . registerAction ( ActionCreateFormat ( device , kwargs [ " format " ] ) )
else :
2013-01-23 17:28:19 +00:00
if devicename and devicename in [ a . name for a in storage . mdarrays ] :
raise KickstartValueError ( formatErrorMsg ( self . lineno , msg = " The Software RAID array name \" %s \" is already in use. " % devicename ) )
2011-01-18 09:24:57 +00:00
# If a previous device has claimed this mount point, delete the
# old one.
try :
if self . mountpoint :
device = storage . mountpoints [ self . mountpoint ]
storage . destroyDevice ( device )
except KeyError :
pass
try :
request = storage . newMDArray ( * * kwargs )
2013-01-23 17:28:19 +00:00
except ValueError as e :
2011-01-18 09:24:57 +00:00
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = str ( e ) )
storage . createDevice ( request )
if self . encrypted :
if self . passphrase and not storage . encryptionPassphrase :
storage . encryptionPassphrase = self . passphrase
2013-01-23 17:28:19 +00:00
cert = getEscrowCertificate ( storage . escrowCertificates , self . escrowcert )
2011-01-18 09:24:57 +00:00
if self . preexist :
luksformat = format
device . format = getFormat ( " luks " , passphrase = self . passphrase , device = device . path ,
2013-01-23 17:28:19 +00:00
cipher = self . cipher ,
2011-01-18 09:24:57 +00:00
escrow_cert = cert ,
add_backup_passphrase = self . backuppassphrase )
luksdev = LUKSDevice ( " luks %d " % storage . nextID ,
format = luksformat ,
parents = device )
else :
luksformat = request . format
request . format = getFormat ( " luks " , passphrase = self . passphrase ,
2013-01-23 17:28:19 +00:00
cipher = self . cipher ,
2011-01-18 09:24:57 +00:00
escrow_cert = cert ,
add_backup_passphrase = self . backuppassphrase )
luksdev = LUKSDevice ( " luks %d " % storage . nextID ,
format = luksformat ,
parents = request )
storage . createDevice ( luksdev )
2013-01-23 17:28:19 +00:00
class RootPw ( commands . rootpw . F18_RootPw ) :
2013-02-12 01:30:33 +00:00
def __init__ ( self , writePriority = 100 , * args , * * kwargs ) :
if ' lock ' not in kwargs :
kwargs [ ' lock ' ] = True
super ( RootPw , self ) . __init__ ( writePriority = writePriority , * args , * * kwargs )
2013-01-23 17:28:19 +00:00
def execute ( self , storage , ksdata , instClass , users ) :
algo = getPassAlgo ( ksdata . authconfig . authconfig )
users . setRootPassword ( self . password , self . isCrypted , self . lock , algo )
2011-01-18 09:24:57 +00:00
class SELinux ( commands . selinux . FC3_SELinux ) :
2013-01-23 17:28:19 +00:00
def execute ( self , * args ) :
selinux_states = { SELINUX_DISABLED : " disabled " ,
SELINUX_ENFORCING : " enforcing " ,
SELINUX_PERMISSIVE : " permissive " }
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
if self . selinux not in selinux_states :
log . error ( " unknown selinux state: %s " % ( self . selinux , ) )
return
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
try :
selinux_cfg = SimpleConfigFile ( ROOT_PATH + " /etc/selinux/config " )
selinux_cfg . read ( )
selinux_cfg . set ( ( " SELINUX " , selinux_states [ self . selinux ] ) )
selinux_cfg . write ( )
except IOError as msg :
log . error ( " Error setting selinux mode: %s " % ( msg , ) )
class Services ( commands . services . FC6_Services ) :
def execute ( self , storage , ksdata , instClass ) :
disabled = map ( lambda s : s + " .service " , self . disabled )
enabled = map ( lambda s : s + " .service " , self . enabled )
if disabled :
iutil . execWithRedirect ( " systemctl " , [ " disable " ] + disabled ,
stdout = " /dev/tty5 " , stderr = " /dev/tty5 " ,
root = ROOT_PATH )
if enabled :
iutil . execWithRedirect ( " systemctl " , [ " enable " ] + enabled ,
stdout = " /dev/tty5 " , stderr = " /dev/tty5 " ,
root = ROOT_PATH )
class Timezone ( commands . timezone . F18_Timezone ) :
def __init__ ( self , * args ) :
commands . timezone . F18_Timezone . __init__ ( self , * args )
#TODO: Do we need to set it to False in case of dual-boot?
#default to UTC HW clock in Anaconda
self . isUtc = True
def execute ( self , * args ) :
# write out timezone configuration
if not timezone . is_valid_timezone ( self . timezone ) :
# this should never happen, but for pity's sake
log . warning ( " Timezone %s set in kickstart is not valid, falling " \
" back to default (America/New_York). " % ( self . timezone , ) )
self . timezone = " America/New_York "
timezone . write_timezone_config ( self , ROOT_PATH )
# write out NTP configuration (if set)
if not self . nontp and self . ntpservers :
chronyd_conf_path = os . path . normpath ( ROOT_PATH + ntp . NTP_CONFIG_FILE )
try :
ntp . save_servers_to_config ( self . ntpservers ,
conf_file_path = chronyd_conf_path )
except ntp . NTPconfigError as ntperr :
log . warning ( " Failed to save NTP configuration: %s " % ntperr )
class User ( commands . user . F12_User ) :
def execute ( self , storage , ksdata , instClass , users ) :
algo = getPassAlgo ( ksdata . authconfig . authconfig )
for usr in self . userList :
kwargs = usr . __dict__
kwargs . update ( { " algo " : algo , " root " : ROOT_PATH } )
if not users . createUser ( usr . name , * * kwargs ) :
log . error ( " User %s already exists, not creating. " % usr . name )
class VolGroup ( commands . volgroup . FC16_VolGroup ) :
def execute ( self , storage , ksdata , instClass ) :
for v in self . vgList :
v . execute ( storage , ksdata , instClass )
class VolGroupData ( commands . volgroup . FC16_VolGroupData ) :
def execute ( self , storage , ksdata , instClass ) :
2011-01-18 09:24:57 +00:00
pvs = [ ]
devicetree = storage . devicetree
storage . doAutoPart = False
# Get a list of all the physical volume devices that make up this VG.
for pv in self . physvols :
# if pv is using --onpart, use original device
2013-01-23 17:28:19 +00:00
pv = ksdata . onPart . get ( pv , pv )
dev = devicetree . getDeviceByName ( pv ) or lookupAlias ( devicetree , pv )
2011-01-18 09:24:57 +00:00
if dev and dev . format . type == " luks " :
try :
dev = devicetree . getChildren ( dev ) [ 0 ]
except IndexError :
dev = None
if not dev :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Tried to use undefined partition %s in Volume Group specification " % pv )
pvs . append ( dev )
if len ( pvs ) == 0 and not self . preexist :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Volume group defined without any physical volumes. Either specify physical volumes or use --useexisting. " )
if self . pesize not in getPossiblePhysicalExtents ( floor = 1024 ) :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " Volume group specified invalid pesize " )
# If --noformat or --useexisting was given, there's really nothing to do.
if not self . format or self . preexist :
if not self . vgname :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " --noformat or --useexisting used without giving a name " )
dev = devicetree . getDeviceByName ( self . vgname )
if not dev :
raise KickstartValueError , formatErrorMsg ( self . lineno , msg = " No preexisting VG with the name \" %s \" was found. " % self . vgname )
2013-01-23 17:28:19 +00:00
elif self . vgname in [ vg . name for vg in storage . vgs ] :
raise KickstartValueError ( formatErrorMsg ( self . lineno , msg = " The volume group name \" %s \" is already in use. " % self . vgname ) )
2011-01-18 09:24:57 +00:00
else :
2013-01-23 17:28:19 +00:00
request = storage . newVG ( parents = pvs ,
2011-01-18 09:24:57 +00:00
name = self . vgname ,
peSize = self . pesize / 1024.0 )
storage . createDevice ( request )
2013-01-23 17:28:19 +00:00
if self . reserved_space :
request . reserved_space = self . reserved_space
elif self . reserved_percent :
request . reserved_percent = self . reserved_percent
class XConfig ( commands . xconfig . F14_XConfig ) :
def execute ( self , * args ) :
desktop = Desktop ( )
2011-01-18 09:24:57 +00:00
if self . startX :
2013-01-23 17:28:19 +00:00
desktop . setDefaultRunLevel ( 5 )
2011-01-18 09:24:57 +00:00
if self . defaultdesktop :
2013-01-23 17:28:19 +00:00
desktop . setDefaultDesktop ( self . defaultdesktop )
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
# now write it out
desktop . write ( )
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
class ZFCP ( commands . zfcp . F14_ZFCP ) :
2011-01-18 09:24:57 +00:00
def parse ( self , args ) :
2013-01-23 17:28:19 +00:00
fcp = commands . zfcp . F14_ZFCP . parse ( self , args )
2011-01-18 09:24:57 +00:00
try :
storage . zfcp . ZFCP ( ) . addFCP ( fcp . devnum , fcp . wwpn , fcp . fcplun )
2013-01-23 17:28:19 +00:00
except ValueError as e :
2011-01-18 09:24:57 +00:00
log . warning ( str ( e ) )
return fcp
2013-01-23 17:28:19 +00:00
class Keyboard ( commands . keyboard . F18_Keyboard ) :
def execute ( self , * args ) :
keyboard . write_keyboard_config ( self , ROOT_PATH )
def dracutSetupArgs ( self , * args ) :
return keyboard . dracut_setup_args ( self )
2011-01-18 09:24:57 +00:00
###
### HANDLERS
###
# This is just the latest entry from pykickstart.handlers.control with all the
# classes we're overriding in place of the defaults.
commandMap = {
" auth " : Authconfig ,
" authconfig " : Authconfig ,
" autopart " : AutoPart ,
2013-01-23 17:28:19 +00:00
" btrfs " : BTRFS ,
2011-01-18 09:24:57 +00:00
" bootloader " : Bootloader ,
" clearpart " : ClearPart ,
" dmraid " : DmRaid ,
" fcoe " : Fcoe ,
" firewall " : Firewall ,
2013-01-23 17:28:19 +00:00
" firstboot " : Firstboot ,
" group " : Group ,
2011-01-18 09:24:57 +00:00
" ignoredisk " : IgnoreDisk ,
" iscsi " : Iscsi ,
" iscsiname " : IscsiName ,
" keyboard " : Keyboard ,
" lang " : Lang ,
" logging " : Logging ,
2013-01-23 17:28:19 +00:00
" logvol " : LogVol ,
2011-01-18 09:24:57 +00:00
" multipath " : MultiPath ,
2013-01-23 17:28:19 +00:00
" network " : Network ,
" part " : Partition ,
" partition " : Partition ,
" raid " : Raid ,
2011-01-18 09:24:57 +00:00
" rootpw " : RootPw ,
" selinux " : SELinux ,
2013-01-23 17:28:19 +00:00
" services " : Services ,
2011-01-18 09:24:57 +00:00
" timezone " : Timezone ,
2013-01-23 17:28:19 +00:00
" user " : User ,
" volgroup " : VolGroup ,
2011-01-18 09:24:57 +00:00
" xconfig " : XConfig ,
" zfcp " : ZFCP ,
}
dataMap = {
2013-01-23 17:28:19 +00:00
" BTRFSData " : BTRFSData ,
2011-01-18 09:24:57 +00:00
" LogVolData " : LogVolData ,
" PartData " : PartitionData ,
" RaidData " : RaidData ,
" VolGroupData " : VolGroupData ,
}
superclass = returnClassForVersion ( )
class AnacondaKSHandler ( superclass ) :
2013-01-23 17:28:19 +00:00
def __init__ ( self ) :
2011-01-18 09:24:57 +00:00
superclass . __init__ ( self , commandUpdates = commandMap , dataUpdates = dataMap )
self . onPart = { }
class AnacondaPreParser ( KickstartParser ) :
# A subclass of KickstartParser that only looks for %pre scripts and
# sets them up to be run. All other scripts and commands are ignored.
def __init__ ( self , handler , followIncludes = True , errorsAreFatal = True ,
missingIncludeIsFatal = True ) :
KickstartParser . __init__ ( self , handler , missingIncludeIsFatal = False )
def handleCommand ( self , lineno , args ) :
pass
2013-01-23 17:28:19 +00:00
def setupSections ( self ) :
self . registerSection ( PreScriptSection ( self . handler , dataObj = AnacondaKSScript ) )
self . registerSection ( NullSection ( self . handler , sectionOpen = " % post " ) )
self . registerSection ( NullSection ( self . handler , sectionOpen = " % traceback " ) )
self . registerSection ( NullSection ( self . handler , sectionOpen = " % packages " ) )
2011-01-18 09:24:57 +00:00
class AnacondaKSParser ( KickstartParser ) :
def __init__ ( self , handler , followIncludes = True , errorsAreFatal = True ,
2013-01-23 17:28:19 +00:00
missingIncludeIsFatal = True , scriptClass = AnacondaKSScript ) :
self . scriptClass = scriptClass
2011-01-18 09:24:57 +00:00
KickstartParser . __init__ ( self , handler )
def handleCommand ( self , lineno , args ) :
if not self . handler :
return
2013-01-23 17:28:19 +00:00
return KickstartParser . handleCommand ( self , lineno , args )
def setupSections ( self ) :
self . registerSection ( PreScriptSection ( self . handler , dataObj = self . scriptClass ) )
self . registerSection ( PostScriptSection ( self . handler , dataObj = self . scriptClass ) )
self . registerSection ( TracebackScriptSection ( self . handler , dataObj = self . scriptClass ) )
self . registerSection ( PackageSection ( self . handler ) )
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
def preScriptPass ( f ) :
2011-01-18 09:24:57 +00:00
# The first pass through kickstart file processing - look for %pre scripts
# and run them. This must come in a separate pass in case a script
# generates an included file that has commands for later.
2013-01-23 17:28:19 +00:00
ksparser = AnacondaPreParser ( AnacondaKSHandler ( ) )
2011-01-18 09:24:57 +00:00
try :
2013-01-23 17:28:19 +00:00
ksparser . readKickstart ( f )
except KickstartError as e :
errorHandler . cb ( KickstartError ( ) , e )
sys . exit ( 1 )
2011-01-18 09:24:57 +00:00
# run %pre scripts
2013-01-23 17:28:19 +00:00
runPreScripts ( ksparser . handler . scripts )
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
def parseKickstart ( f ) :
# preprocessing the kickstart file has already been handled in initramfs.
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
handler = AnacondaKSHandler ( )
2011-01-18 09:24:57 +00:00
ksparser = AnacondaKSParser ( handler )
# We need this so all the /dev/disk/* stuff is set up before parsing.
udev_trigger ( subsystem = " block " , action = " change " )
# So that drives onlined by these can be used in the ks file
storage . iscsi . iscsi ( ) . startup ( )
storage . fcoe . fcoe ( ) . startup ( )
storage . zfcp . ZFCP ( ) . startup ( )
# Note we do NOT call dasd.startup() here, that does not online drives, but
# only checks if they need formatting, which requires zerombr to be known
2013-01-23 17:28:19 +00:00
detect_multipaths ( )
2011-01-18 09:24:57 +00:00
try :
2013-01-23 17:28:19 +00:00
ksparser . readKickstart ( f )
except KickstartError as e :
errorHandler . cb ( KickstartError ( ) , e )
sys . exit ( 1 )
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
global packagesSeen
packagesSeen = ksparser . getSection ( " % packages " ) . timesSeen > 0
2011-01-18 09:24:57 +00:00
return handler
2013-01-23 17:28:19 +00:00
def appendPostScripts ( ksdata ) :
scripts = " "
2011-01-18 09:24:57 +00:00
2013-01-23 17:28:19 +00:00
# Read in all the post script snippets to a single big string.
for fn in glob . glob ( " /usr/share/anaconda/post-scripts/*ks " ) :
f = open ( fn , " r " )
scripts + = f . read ( )
f . close ( )
# Then parse the snippets against the existing ksdata. We can do this
# because pykickstart allows multiple parses to save their data into a
# single data object. Errors parsing the scripts are a bug in anaconda,
# so just raise an exception.
ksparser = AnacondaKSParser ( ksdata , scriptClass = AnacondaInternalScript )
ksparser . readKickstartFromString ( scripts , reset = False )
def runPostScripts ( scripts ) :
postScripts = filter ( lambda s : s . type == KS_SCRIPT_POST , scripts )
2011-01-18 09:24:57 +00:00
if len ( postScripts ) == 0 :
return
# Remove environment variables that cause problems for %post scripts.
for var in [ " LIBUSER_CONF " ] :
if os . environ . has_key ( var ) :
del ( os . environ [ var ] )
log . info ( " Running kickstart %% post script(s) " )
2013-01-23 17:28:19 +00:00
map ( lambda s : s . run ( ROOT_PATH ) , postScripts )
2011-01-18 09:24:57 +00:00
log . info ( " All kickstart %% post script(s) have been run " )
2013-01-23 17:28:19 +00:00
def runPreScripts ( scripts ) :
2011-01-18 09:24:57 +00:00
preScripts = filter ( lambda s : s . type == KS_SCRIPT_PRE , scripts )
if len ( preScripts ) == 0 :
return
log . info ( " Running kickstart %% pre script(s) " )
2013-01-23 17:28:19 +00:00
stdoutLog . info ( _ ( " Running pre-installation scripts " ) )
map ( lambda s : s . run ( " / " ) , preScripts )
2011-01-18 09:24:57 +00:00
log . info ( " All kickstart %% pre script(s) have been run " )
2013-01-23 17:28:19 +00:00
def runTracebackScripts ( scripts ) :
2011-01-18 09:24:57 +00:00
log . info ( " Running kickstart %% traceback script(s) " )
2013-01-23 17:28:19 +00:00
for script in filter ( lambda s : s . type == KS_SCRIPT_TRACEBACK , scripts ) :
script . run ( " / " )
2011-01-18 09:24:57 +00:00
log . info ( " All kickstart %% traceback script(s) have been run " )
2013-01-23 17:28:19 +00:00
def doKickstartStorage ( storage , ksdata , instClass ) :
""" Setup storage state from the kickstart data """
ksdata . clearpart . execute ( storage , ksdata , instClass )
if not [ d for d in storage . disks if not d . format . hidden ] :
2011-01-18 09:24:57 +00:00
return
2013-01-23 17:28:19 +00:00
ksdata . bootloader . execute ( storage , ksdata , instClass )
ksdata . autopart . execute ( storage , ksdata , instClass )
ksdata . partition . execute ( storage , ksdata , instClass )
ksdata . raid . execute ( storage , ksdata , instClass )
ksdata . volgroup . execute ( storage , ksdata , instClass )
ksdata . logvol . execute ( storage , ksdata , instClass )
ksdata . btrfs . execute ( storage , ksdata , instClass )
storage . setUpBootLoader ( )
2011-01-18 09:24:57 +00:00