
Some methods were declared with the default parameters specified as CONF.<foo> values. Those values will be evaluated only once during module build time. So, the values speficied in config file won't be passed into those methods as config file values will be available only after config file gets parsed in run-time. Change-Id: Ic8e24be4fdc0ce165d8142d47405373acaf4a803 Closes-Bug: #1479307
250 lines
9.1 KiB
Python
250 lines
9.1 KiB
Python
# Copyright 2014 Mirantis, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import os
|
|
import re
|
|
import shutil
|
|
|
|
from fuel_agent import errors
|
|
from fuel_agent.openstack.common import log as logging
|
|
from fuel_agent.utils import utils
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
def guess_grub2_conf(chroot=''):
|
|
for filename in ('/boot/grub/grub.cfg', '/boot/grub2/grub.cfg'):
|
|
if os.path.isdir(os.path.dirname(chroot + filename)):
|
|
return filename
|
|
raise errors.GrubUtilsError('grub2 config file not found')
|
|
|
|
|
|
def guess_grub2_default(chroot=''):
|
|
for filename in ('/etc/default/grub', '/etc/sysconfig/grub'):
|
|
if os.path.isfile(chroot + filename):
|
|
return filename
|
|
raise errors.GrubUtilsError('grub2 defaul config file not found')
|
|
|
|
|
|
def guess_grub2_mkconfig(chroot=''):
|
|
for grub_mkconfig in \
|
|
('/sbin/grub-mkconfig', '/sbin/grub2-mkconfig',
|
|
'/usr/sbin/grub-mkconfig', '/usr/sbin/grub2-mkconfig'):
|
|
if os.path.isfile(chroot + grub_mkconfig):
|
|
return grub_mkconfig
|
|
raise errors.GrubUtilsError('grub2 mkconfig binary not found')
|
|
|
|
|
|
def guess_grub_version(chroot=''):
|
|
grub_install = guess_grub_install(chroot=chroot)
|
|
LOG.debug('Trying to run %s --version' % grub_install)
|
|
cmd = [grub_install, '--version']
|
|
if chroot:
|
|
cmd[:0] = ['chroot', chroot]
|
|
result = utils.execute(*cmd)
|
|
version = 1 if result[0].find('0.97') > 0 else 2
|
|
LOG.debug('Looks like grub version is %s' % version)
|
|
return version
|
|
|
|
|
|
def guess_grub(chroot=''):
|
|
for grub in ('/sbin/grub', '/usr/sbin/grub'):
|
|
LOG.debug('Looking for grub: trying %s' % grub)
|
|
if os.path.isfile(chroot + grub):
|
|
LOG.debug('grub found: %s' % grub)
|
|
return grub
|
|
raise errors.GrubUtilsError('grub not found')
|
|
|
|
|
|
def guess_grub_install(chroot=''):
|
|
for grub_install in ('/sbin/grub-install', '/sbin/grub2-install',
|
|
'/usr/sbin/grub-install', '/usr/sbin/grub2-install'):
|
|
LOG.debug('Looking for grub-install: trying %s' % grub_install)
|
|
if os.path.isfile(chroot + grub_install):
|
|
LOG.debug('grub-install found: %s' % grub_install)
|
|
return grub_install
|
|
raise errors.GrubUtilsError('grub-install not found')
|
|
|
|
|
|
def guess_grub1_datadir(chroot='', arch='x86_64'):
|
|
LOG.debug('Looking for grub data directory')
|
|
for d in os.listdir(chroot + '/usr/share/grub'):
|
|
if arch in d:
|
|
LOG.debug('Looks like grub data directory '
|
|
'is /usr/share/grub/%s' % d)
|
|
return '/usr/share/grub/' + d
|
|
raise errors.GrubUtilsError(
|
|
'grub data directory not found for arch %s' % arch)
|
|
|
|
|
|
def guess_kernel(chroot='', regexp=None):
|
|
"""Tries to guess kernel by regexp
|
|
|
|
:param chroot: Path to chroot
|
|
:param regexp: (String) Regular expression (must have python syntax).
|
|
Default is r'^vmlinuz.*'
|
|
"""
|
|
kernel = utils.guess_filename(
|
|
path=os.path.join(chroot, 'boot'),
|
|
regexp=(regexp or r'^vmlinuz.*'))
|
|
|
|
if kernel:
|
|
return kernel
|
|
|
|
raise errors.GrubUtilsError('Error while trying to find kernel: '
|
|
'regexp=%s' % regexp)
|
|
|
|
|
|
def guess_initrd(chroot='', regexp=None):
|
|
"""Tries to guess initrd by regexp
|
|
|
|
:param chroot: Path to chroot
|
|
:param regexp: (String) Regular expression (must have python syntax).
|
|
Default is r'^(initrd|initramfs).*'
|
|
"""
|
|
initrd = utils.guess_filename(
|
|
path=os.path.join(chroot, 'boot'),
|
|
regexp=(regexp or r'^(initrd|initramfs).*'))
|
|
|
|
if initrd:
|
|
return initrd
|
|
|
|
raise errors.GrubUtilsError('Error while trying to find initrd: '
|
|
'regexp=%s' % regexp)
|
|
|
|
|
|
def grub1_install(install_devices, boot_device, chroot=''):
|
|
match = re.search(r'(.+?)(p?)(\d*)$', boot_device)
|
|
# Checking whether boot device is a partition
|
|
# !!! It must be a partition not a whole disk. !!!
|
|
if not match.group(3):
|
|
raise errors.GrubUtilsError(
|
|
'Error while installing legacy grub: '
|
|
'boot device must be a partition')
|
|
boot_disk = match.group(1)
|
|
boot_part = str(int(match.group(3)) - 1)
|
|
grub1_stage1(chroot=chroot)
|
|
for install_device in install_devices:
|
|
grub1_mbr(install_device, boot_disk, boot_part, chroot=chroot)
|
|
|
|
|
|
def grub1_mbr(install_device, boot_disk, boot_part, chroot=''):
|
|
# The device on which we are going to install
|
|
# stage1 needs to be mapped as hd0, otherwise system won't be able to boot.
|
|
batch = 'device (hd0) {0}\n'.format(install_device)
|
|
# That is much easier to use grub-install, but unfortunately
|
|
# it is not able to install bootloader on huge disks.
|
|
# Instead we set drive geometry manually to avoid grub register
|
|
# overlapping. We set it so as to make grub
|
|
# thinking that disk size is equal to 1G.
|
|
# 130 cylinders * (16065 * 512 = 8225280 bytes) = 1G
|
|
# We also assume that boot partition is in the beginning
|
|
# of disk between 0 and 1G.
|
|
batch += 'geometry (hd0) 130 255 63\n'
|
|
if boot_disk != install_device:
|
|
batch += 'device (hd1) {0}\n'.format(boot_disk)
|
|
batch += 'geometry (hd1) 130 255 63\n'
|
|
batch += 'root (hd1,{0})\n'.format(boot_part)
|
|
else:
|
|
batch += 'root (hd0,{0})\n'.format(boot_part)
|
|
batch += 'setup (hd0)\n'
|
|
batch += 'quit\n'
|
|
|
|
with open(chroot + '/tmp/grub.batch', 'wb') as f:
|
|
LOG.debug('Grub batch content: \n%s' % batch)
|
|
f.write(batch)
|
|
|
|
script = 'cat /tmp/grub.batch | {0} --no-floppy --batch'.format(
|
|
guess_grub(chroot=chroot))
|
|
with open(chroot + '/tmp/grub.sh', 'wb') as f:
|
|
LOG.debug('Grub script content: \n%s' % script)
|
|
f.write(script)
|
|
|
|
os.chmod(chroot + '/tmp/grub.sh', 0o755)
|
|
cmd = ['/tmp/grub.sh']
|
|
if chroot:
|
|
cmd[:0] = ['chroot', chroot]
|
|
stdout, stderr = utils.execute(*cmd, run_as_root=True, check_exit_code=[0])
|
|
LOG.debug('Grub script stdout: \n%s' % stdout)
|
|
LOG.debug('Grub script stderr: \n%s' % stderr)
|
|
|
|
|
|
def grub1_stage1(chroot=''):
|
|
LOG.debug('Installing grub stage1 files')
|
|
for f in os.listdir(chroot + '/boot/grub'):
|
|
if f in ('stage1', 'stage2') or 'stage1_5' in f:
|
|
LOG.debug('Removing: %s' % chroot + os.path.join('/boot/grub', f))
|
|
os.remove(chroot + os.path.join('/boot/grub', f))
|
|
grub1_datadir = guess_grub1_datadir(chroot=chroot)
|
|
for f in os.listdir(chroot + grub1_datadir):
|
|
if f in ('stage1', 'stage2') or 'stage1_5' in f:
|
|
LOG.debug('Copying %s from %s to /boot/grub' % (f, grub1_datadir))
|
|
shutil.copy(chroot + os.path.join(grub1_datadir, f),
|
|
chroot + os.path.join('/boot/grub', f))
|
|
|
|
|
|
def grub1_cfg(kernel=None, initrd=None,
|
|
kernel_params='', chroot='', grub_timeout=5):
|
|
|
|
if not kernel:
|
|
kernel = guess_kernel(chroot=chroot)
|
|
if not initrd:
|
|
initrd = guess_initrd(chroot=chroot)
|
|
|
|
config = """
|
|
default=0
|
|
timeout={grub_timeout}
|
|
title Default ({kernel})
|
|
kernel /{kernel} {kernel_params}
|
|
initrd /{initrd}
|
|
""".format(kernel=kernel, initrd=initrd,
|
|
kernel_params=kernel_params,
|
|
grub_timeout=grub_timeout)
|
|
with open(chroot + '/boot/grub/grub.conf', 'wb') as f:
|
|
f.write(config)
|
|
|
|
|
|
def grub2_install(install_devices, chroot=''):
|
|
grub_install = guess_grub_install(chroot=chroot)
|
|
for install_device in install_devices:
|
|
cmd = [grub_install, install_device]
|
|
if chroot:
|
|
cmd[:0] = ['chroot', chroot]
|
|
utils.execute(*cmd, run_as_root=True, check_exit_code=[0])
|
|
|
|
|
|
def grub2_cfg(kernel_params='', chroot='', grub_timeout=5):
|
|
grub_defaults = chroot + guess_grub2_default(chroot=chroot)
|
|
rekerparams = re.compile(r'^.*GRUB_CMDLINE_LINUX=.*')
|
|
retimeout = re.compile(r'^.*GRUB_HIDDEN_TIMEOUT=.*')
|
|
new_content = ''
|
|
with open(grub_defaults) as f:
|
|
for line in f:
|
|
line = rekerparams.sub(
|
|
'GRUB_CMDLINE_LINUX="{kernel_params}"'.
|
|
format(kernel_params=kernel_params), line)
|
|
line = retimeout.sub('GRUB_HIDDEN_TIMEOUT={grub_timeout}'.
|
|
format(grub_timeout=grub_timeout), line)
|
|
new_content += line
|
|
# NOTE(agordeev): explicitly add record fail timeout, in order to
|
|
# prevent user confirmation appearing if unexpected reboot occured.
|
|
new_content += '\nGRUB_RECORDFAIL_TIMEOUT={grub_timeout}\n'.\
|
|
format(grub_timeout=grub_timeout)
|
|
with open(grub_defaults, 'wb') as f:
|
|
f.write(new_content)
|
|
cmd = [guess_grub2_mkconfig(chroot), '-o', guess_grub2_conf(chroot)]
|
|
if chroot:
|
|
cmd[:0] = ['chroot', chroot]
|
|
utils.execute(*cmd, run_as_root=True)
|