2006-12-15 21:05:01 +00:00
#
# firstboot_kdump.py - kdump configuration page for firstboot
# Copyright 2006 Red Hat, Inc.
# Author: Jarod Wilson <jwilson@redhat.com>
# Contributors:
2009-06-23 18:36:27 +00:00
# Neil Horman <nhorman@redhat.com>
# Dave Lehman <dlehman@redhat.com>
2006-12-15 21:05:01 +00:00
#
#
# 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, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import sys
sys . path . append ( ' /usr/share/system-config-kdump/ ' )
from gtk import *
import string
import os
import os . path
import time
import gtk
import gobject
import commands
2009-06-23 18:36:27 +00:00
from firstboot . config import *
from firstboot . constants import *
from firstboot . functions import *
from firstboot . module import *
2010-06-13 19:20:48 +00:00
import gettext
2012-08-09 02:22:48 +00:00
_ = lambda x : gettext . ldgettext ( " kexec-tools " , x )
2010-06-13 19:20:48 +00:00
N_ = lambda x : x
2006-12-15 21:05:01 +00:00
2009-06-23 18:36:27 +00:00
class moduleClass ( Module ) :
def __init__ ( self ) :
Module . __init__ ( self )
self . priority = 100
self . sidebarTitle = N_ ( " Kdump " )
self . title = N_ ( " Kdump " )
2009-11-23 16:17:42 +00:00
self . reboot = False
2009-06-23 18:36:27 +00:00
# runPriority determines the order in which this module runs in firstboot
runPriority = 70
moduleName = _ ( " Kdump " )
windowName = moduleName
2009-11-23 16:17:42 +00:00
reboot = False
2009-06-23 18:36:27 +00:00
# possible bootloaders we'll need to adjust
2012-08-09 02:22:50 +00:00
# todo: f18 grub2 for efi
2009-06-23 18:36:27 +00:00
# bootloader : (config file, kdump offset)
2010-06-13 19:20:48 +00:00
bootloaders = { " grub " : ( [ " /boot/grub/grub.conf " , " /boot/efi/EFI/redhat/grub.conf " ] , [ 16 , 256 ] ) ,
2012-08-09 02:22:50 +00:00
" grub2 " : ( [ " /boot/grub2/grub.cfg " ] , [ 16 , 256 ] ) ,
2012-08-09 02:22:50 +00:00
" yaboot " : ( [ " /boot/etc/yaboot.conf " ] , [ 32 ] ) }
2009-06-23 18:36:27 +00:00
bootloader = None
offset = 0
# list of architectures without kdump support
unsupportedArches = [ " ppc " , " s390 " , " s390x " , " i386 " , " i586 " ]
# list of platforms that have a separate kernel-kdump
kernelKdumpArches = [ " ppc64 " ]
kernelKdumpInstalled = False
2009-11-23 16:17:42 +00:00
def needsReboot ( self ) :
return self . reboot
2009-06-23 18:36:27 +00:00
# toggle sensitivity of kdump config bits
def showHide ( self , status ) :
self . totalMem . set_sensitive ( status )
self . kdumpMem . set_sensitive ( status )
self . systemUsableMem . set_sensitive ( status )
self . labelTotal . set_sensitive ( status )
self . labelKdump . set_sensitive ( status )
self . labelSys . set_sensitive ( status )
self . kdumpEnabled = status
2012-08-09 02:22:49 +00:00
self . AdvWindow . set_sensitive ( status )
2009-06-23 18:36:27 +00:00
def on_enableKdumpCheck_toggled ( self , * args ) :
showHideStatus = self . enableKdumpCheck . get_active ( )
self . showHide ( showHideStatus )
def updateAvail ( self , widget , spin ) :
self . remMem = self . availMem - spin . get_value_as_int ( )
self . systemUsableMem . set_text ( " %s " % self . remMem )
def getBootloader ( self ) :
for ( name , ( conf , offset ) ) in self . bootloaders . items ( ) :
2010-06-13 19:20:48 +00:00
i = 0
for c in conf :
if os . access ( c , os . W_OK ) :
self . bootloader = name
self . offset = i
return self . bootloader
i + = 1
self . offset = None
self . bootloader = None
return None
2009-06-23 18:36:27 +00:00
def createScreen ( self , doDebug = None ) :
self . doDebug = doDebug
if doDebug :
print " initializing kdump module "
# What kernel are we running?
self . runningKernel = os . popen ( " /bin/uname -r " ) . read ( ) . strip ( )
# What arch are we running on?
self . arch = os . popen ( " /bin/uname -m " ) . read ( ) . strip ( )
# Check for a xen kernel, kdump doesn't work w/xen just yet...
self . xenKernel = self . runningKernel . find ( " xen " )
# Fedora or RHEL?
releaseFile = ' /etc/redhat-release '
self . distro = ' rhel '
lines = open ( releaseFile ) . readlines ( )
for line in lines :
if line . find ( " Fedora " ) != - 1 :
self . distro = ' fedora '
kernelKdumpArchesFC = [ " i686 " , " x86_64 " ]
self . kernelKdumpArches . extend ( kernelKdumpArchesFC )
break
# If we need kernel-kdump, check to see if its already installed
if self . arch in self . kernelKdumpArches :
self . kernelKdump = " /boot/vmlinux- %s kdump " % self . runningKernel
if os . access ( self . kernelKdump , os . R_OK ) :
self . kernelKdumpInstalled = True
# Ascertain how much memory is in the system
memInfo = open ( " /proc/meminfo " ) . readlines ( )
self . availMem = 0
for line in memInfo :
if line . startswith ( " MemTotal: " ) :
self . availMem = int ( line . split ( ) [ 1 ] ) / 1024
break
# Fix up memory calculations if kdump is already on
cmdLine = open ( " /proc/cmdline " ) . read ( )
self . kdumpOffset = 0
self . origCrashKernel = " "
2009-11-23 16:17:42 +00:00
self . kdumpEnabled = False
2012-08-09 02:22:48 +00:00
chkConfigStatus = commands . getoutput ( ' /bin/systemctl is-enabled kdump.service ' )
if chkConfigStatus . find ( " enabled " ) > - 1 :
2009-06-23 18:36:27 +00:00
self . kdumpEnabled = True
self . kdumpMemInitial = 0
2012-08-09 02:22:49 +00:00
kexec_crash_size = open ( " /sys/kernel/kexec_crash_size " ) . read ( )
self . kdumpMem = int ( kexec_crash_size ) / ( 1024 * 1024 )
if self . kdumpMem != 0 :
2009-06-23 18:36:27 +00:00
crashString = filter ( lambda t : t . startswith ( " crashkernel= " ) ,
2006-12-15 21:05:01 +00:00
cmdLine . split ( ) ) [ 0 ] . split ( " = " ) [ 1 ]
2009-06-23 18:36:27 +00:00
if self . doDebug :
print " crashString is %s " % crashString
2009-11-23 16:17:42 +00:00
if crashString . find ( " @ " ) != - 1 :
( self . kdumpMem , self . kdumpOffset ) = [ int ( m [ : - 1 ] ) for m in crashString . split ( " @ " ) ]
else :
self . kdumpOffset = 0
2009-06-23 18:36:27 +00:00
self . availMem + = self . kdumpMem
2009-11-23 16:17:42 +00:00
self . origCrashKernel = " %d M " % ( self . kdumpMem )
2009-06-23 18:36:27 +00:00
self . kdumpMemInitial = self . kdumpMem
2010-06-13 19:20:48 +00:00
self . kdumpEnabled = True
2009-06-23 18:36:27 +00:00
else :
self . kdumpEnabled = False
2012-08-09 02:22:49 +00:00
2009-06-23 18:36:27 +00:00
self . initialState = self . kdumpEnabled
# Do some sanity-checking and try to present only sane options.
#
# Defaults
lowerBound = 128
minUsable = 256
step = 64
self . enoughMem = True
if self . arch == ' ia64 ' :
# ia64 usually needs at *least* 256M, page-aligned... :(
lowerBound = 256
minUsable = 512
step = 256
elif self . arch == ' ppc64 ' :
# ppc64 often fails w/128M lately, and we want at least 1G
# of RAM for normal use, due to 64k page size... :\
lowerBound = 256
minUsable = 1024
upperBound = ( self . availMem - minUsable ) - ( self . availMem % step )
if upperBound < lowerBound :
self . enoughMem = False
# Set spinner to lowerBound unless already set on kernel command line
if self . kdumpMem == 0 :
self . kdumpMem = lowerBound
else :
# round down to a multiple of step value
self . kdumpMem = self . kdumpMem - ( self . kdumpMem % step )
# kdump enable/disable checkbox
2012-08-09 02:22:49 +00:00
self . enableKdumpCheck = gtk . CheckButton ( _ ( " _Enable kdump? " ) )
2009-06-23 18:36:27 +00:00
self . enableKdumpCheck . set_alignment ( xalign = 0 , yalign = 0 )
# detected total amount of system memory
self . totalMem = gtk . Label ( _ ( " %s " % self . availMem ) )
self . labelTotal = gtk . Label ( _ ( " _Total System Memory (MB): " ) )
self . labelTotal . set_use_underline ( True )
self . labelTotal . set_mnemonic_widget ( self . totalMem )
self . labelTotal . set_alignment ( 0.0 , 0.5 )
self . labelTotal . set_width_chars ( 32 )
# how much ram to reserve for kdump
self . memSpin = gtk . Adjustment ( self . kdumpMem , lowerBound , upperBound , step , step , 64 )
self . kdumpMem = gtk . SpinButton ( self . memSpin , 0 , 0 )
self . kdumpMem . set_update_policy ( gtk . UPDATE_IF_VALID )
self . kdumpMem . set_numeric ( True )
self . memSpin . connect ( " value_changed " , self . updateAvail , self . kdumpMem )
self . labelKdump = gtk . Label ( _ ( " _Kdump Memory (MB): " ) )
self . labelKdump . set_use_underline ( True )
self . labelKdump . set_mnemonic_widget ( self . kdumpMem )
self . labelKdump . set_alignment ( 0.0 , 0.5 )
# remaining usable system memory
self . resMem = eval ( string . strip ( self . kdumpMem . get_text ( ) ) )
self . remMem = self . availMem - self . resMem
self . systemUsableMem = gtk . Label ( _ ( " %s " % self . remMem ) )
self . labelSys = gtk . Label ( _ ( " _Usable System Memory (MB): " ) )
self . labelSys . set_use_underline ( True )
self . labelSys . set_mnemonic_widget ( self . systemUsableMem )
self . labelSys . set_alignment ( 0.0 , 0.5 )
2012-08-09 02:22:49 +00:00
# Add an advanced kdump config text widget
inputbuf = open ( " /etc/kdump.conf " , " r " )
self . AdvConfig = gtk . TextView ( )
AdvBuf = gtk . TextBuffer ( )
AdvBuf . set_text ( inputbuf . read ( ) )
inputbuf . close ( )
self . AdvConfig . set_buffer ( AdvBuf )
self . AdvWindow = gtk . ScrolledWindow ( )
self . AdvWindow . set_shadow_type ( gtk . SHADOW_IN )
self . AdvWindow . set_policy ( gtk . POLICY_AUTOMATIC , gtk . POLICY_AUTOMATIC )
self . AdvWindow . set_size_request ( 500 , 300 )
self . AdvWindow . add ( self . AdvConfig )
self . AdvConfLabel = gtk . Label ( _ ( " \n Advanced kdump configuration " ) )
self . AdvConfLabel . set_alignment ( 0.0 , 0.5 )
2009-06-23 18:36:27 +00:00
self . vbox = gtk . VBox ( )
self . vbox . set_size_request ( 400 , 200 )
# title_pix = loadPixbuf("workstation.png")
internalVBox = gtk . VBox ( )
internalVBox . set_border_width ( 10 )
internalVBox . set_spacing ( 10 )
label = gtk . Label ( _ ( " Kdump is a kernel crash dumping mechanism. In the event of a "
" system crash, kdump will capture information from your system "
" that can be invaluable in determining the cause of the crash. "
" Note that kdump does require reserving a portion of system "
" memory that will be unavailable for other uses. " ) )
label . set_line_wrap ( True )
label . set_alignment ( 0.0 , 0.5 )
label . set_size_request ( 500 , - 1 )
internalVBox . pack_start ( label , False , True )
2012-08-09 02:22:49 +00:00
table = gtk . Table ( 2 , 100 )
2009-06-23 18:36:27 +00:00
table . attach ( self . enableKdumpCheck , 0 , 2 , 0 , 1 , gtk . FILL , gtk . FILL , 5 , 5 )
table . attach ( self . labelTotal , 0 , 1 , 1 , 2 , gtk . FILL )
table . attach ( self . totalMem , 1 , 2 , 1 , 2 , gtk . SHRINK , gtk . FILL , 5 , 5 )
table . attach ( self . labelKdump , 0 , 1 , 2 , 3 , gtk . FILL )
table . attach ( self . kdumpMem , 1 , 2 , 2 , 3 , gtk . SHRINK , gtk . FILL , 5 , 5 )
table . attach ( self . labelSys , 0 , 1 , 3 , 4 , gtk . FILL )
table . attach ( self . systemUsableMem , 1 , 2 , 3 , 4 , gtk . SHRINK , gtk . FILL , 5 , 5 )
2012-08-09 02:22:49 +00:00
table . attach ( self . AdvConfLabel , 0 , 1 , 5 , 6 , gtk . FILL )
table . attach ( self . AdvWindow , 0 , 2 , 6 , 100 , gtk . FILL , gtk . FILL , 5 , 5 )
2009-06-23 18:36:27 +00:00
# disable until user clicks check box, if not already enabled
if self . initialState is False :
self . showHide ( False )
else :
self . enableKdumpCheck . set_active ( True )
internalVBox . pack_start ( table , True , 15 )
# toggle sensitivity of Mem items
self . enableKdumpCheck . connect ( " toggled " , self . on_enableKdumpCheck_toggled )
self . vbox . pack_start ( internalVBox , False , 15 )
def grabFocus ( self ) :
self . enableKdumpCheck . grab_focus ( )
def apply ( self , * args ) :
if self . kdumpEnabled :
totalSysMem = self . totalMem . get_text ( )
totalSysMem = eval ( string . strip ( totalSysMem ) )
reservedMem = self . kdumpMem . get_value_as_int ( )
remainingMem = totalSysMem - reservedMem
else :
reservedMem = self . kdumpMemInitial
if self . doDebug :
print " Running kernel %s on %s architecture " % ( self . runningKernel , self . arch )
if self . enableKdumpCheck . get_active ( ) :
print " System Mem: %s MB Kdump Mem: %s MB Avail Mem: %s MB " % ( totalSysMem , reservedMem , remainingMem )
else :
print " Kdump will be disabled "
2012-08-09 02:22:49 +00:00
# Before we do other checks we should save the users config
AdvBuf = self . AdvConfig . get_buffer ( )
start , end = AdvBuf . get_bounds ( )
outputbuf = open ( " /etc/kdump.conf " , " rw+ " )
outputbuf . write ( AdvBuf . get_text ( start , end ) )
outputbuf . close ( )
2012-08-09 02:22:49 +00:00
# Regardless of what else happens we need to be sure to disalbe kdump if its disabled here, or
# else it will fail during startup
if ( self . enableKdumpCheck . get_active ( ) == False ) :
os . system ( " /bin/systemctl disable kdump.service " )
2009-06-23 18:36:27 +00:00
# If the user simply doesn't have enough memory for kdump to be viable/supportable, tell 'em
if self . enoughMem is False and self . kdumpEnabled :
self . showErrorMessage ( _ ( " Sorry, your system does not have enough memory for kdump to be viable! " ) )
self . enableKdumpCheck . set_active ( False )
self . showHide ( False )
return RESULT_FAILURE
# Alert user that we're not going to turn on kdump if they're running a xen kernel
elif self . xenKernel != - 1 and self . kdumpEnabled :
self . showErrorMessage ( _ ( " Sorry, Xen kernels do not support kdump at this time! " ) )
self . enableKdumpCheck . set_active ( False )
self . showHide ( False )
return RESULT_FAILURE
# If there's no kdump support on this arch, let the user know and don't configure
elif self . arch in self . unsupportedArches :
self . showErrorMessage ( _ ( " Sorry, the %s architecture does not support kdump at this time! " % self . arch ) )
self . enableKdumpCheck . set_active ( False )
self . showHide ( False )
return RESULT_FAILURE
# If running on an arch w/a separate kernel-kdump (i.e., non-relocatable kernel), check to
# see that its installed, otherwise, alert the user they need to install it, and give them
# the chance to abort configuration.
if self . arch in self . kernelKdumpArches and self . kernelKdumpInstalled is False :
kernelKdumpNote = " \n \n Note that the %s architecture does not feature a relocatable kernel at this time, and thus requires a separate kernel-kdump package to be installed for kdump to function. This can be installed via ' yum install kernel-kdump ' at your convenience. \n \n " % self . arch
else :
kernelKdumpNote = " "
# Don't alert if nothing has changed
if self . initialState != self . kdumpEnabled or reservedMem != self . kdumpMemInitial :
dlg = gtk . MessageDialog ( None , 0 , gtk . MESSAGE_INFO ,
gtk . BUTTONS_YES_NO ,
_ ( " Changing Kdump settings requires rebooting the "
" system to reallocate memory accordingly. %s Would you "
" like to continue with this change and reboot the "
" system after firstboot is complete? " % kernelKdumpNote ) )
dlg . set_position ( gtk . WIN_POS_CENTER )
dlg . show_all ( )
rc = dlg . run ( )
dlg . destroy ( )
2012-08-09 02:22:50 +00:00
if rc != gtk . RESPONSE_YES :
2009-11-23 16:17:42 +00:00
self . reboot = False
2009-06-23 18:36:27 +00:00
return RESULT_SUCCESS
else :
2009-11-23 16:17:42 +00:00
self . reboot = True
2009-06-23 18:36:27 +00:00
# Find bootloader if it exists, and update accordingly
if self . getBootloader ( ) == None :
self . showErrorMessage ( _ ( " Error! No bootloader config file found, aborting configuration! " ) )
self . enableKdumpCheck . set_active ( False )
self . showHide ( False )
return RESULT_FAILURE
# Are we adding or removing the crashkernel param?
if self . kdumpEnabled :
2009-11-23 16:17:42 +00:00
grubbyCmd = " /sbin/grubby -- %s --update-kernel=/boot/vmlinuz- %s --args=crashkernel= %i M " \
% ( self . bootloader , self . runningKernel , reservedMem )
2012-08-09 02:22:48 +00:00
chkconfigStatus = " enable "
2009-06-23 18:36:27 +00:00
else :
grubbyCmd = " /sbin/grubby -- %s --update-kernel=/boot/vmlinuz- %s --remove-args=crashkernel= %s " \
% ( self . bootloader , self . runningKernel , self . origCrashKernel )
2012-08-09 02:22:48 +00:00
chkconfigStatus = " disable "
2009-06-23 18:36:27 +00:00
if self . doDebug :
print " Using %s bootloader with %i M offset " % ( self . bootloader , self . offset )
print " Grubby command would be: \n %s " % grubbyCmd
2012-08-09 02:22:49 +00:00
print " chkconfig status is %s " % chkconfigStatus
2009-06-23 18:36:27 +00:00
else :
os . system ( grubbyCmd )
2012-08-09 02:22:48 +00:00
os . system ( " /bin/systemctl %s kdump.service " % ( chkconfigStatus ) )
2009-06-23 18:36:27 +00:00
if self . bootloader == ' yaboot ' :
os . system ( ' /sbin/ybin ' )
else :
2009-11-23 16:17:42 +00:00
self . reboot = False
2009-06-23 18:36:27 +00:00
return RESULT_SUCCESS
def showErrorMessage ( self , text ) :
dlg = gtk . MessageDialog ( None , 0 , gtk . MESSAGE_ERROR , gtk . BUTTONS_OK , text )
dlg . set_position ( gtk . WIN_POS_CENTER )
dlg . set_modal ( True )
rc = dlg . run ( )
dlg . destroy ( )
return None
def initializeUI ( self ) :
pass