Some improvements in do_bootloader in fuel_agent
1) Added copying grub stage 1.5 files into /boot/grub. 2) Added fstab related stuff Change-Id: Id540f73d30b51b80d40661e2d59f8382f7a4c901 Implements: blueprint image-based-provisioning
This commit is contained in:
parent
246d096441
commit
cb5d2f5e8e
@ -207,6 +207,12 @@ class Manager(object):
|
|||||||
LOG.debug('Launching image processing chain')
|
LOG.debug('Launching image processing chain')
|
||||||
processing.process()
|
processing.process()
|
||||||
|
|
||||||
|
LOG.debug('Extending image file systems')
|
||||||
|
if image.format in ('ext2', 'ext3', 'ext4', 'xfs'):
|
||||||
|
LOG.debug('Extending %s %s' %
|
||||||
|
(image.format, image.target_device))
|
||||||
|
fu.extend_fs(image.format, image.target_device)
|
||||||
|
|
||||||
def mount_target(self, chroot):
|
def mount_target(self, chroot):
|
||||||
LOG.debug('Mounting target file systems')
|
LOG.debug('Mounting target file systems')
|
||||||
# Here we are going to mount all file systems in partition scheme.
|
# Here we are going to mount all file systems in partition scheme.
|
||||||
@ -223,26 +229,40 @@ class Manager(object):
|
|||||||
fu.mount_bind(chroot, '/sys')
|
fu.mount_bind(chroot, '/sys')
|
||||||
fu.mount_bind(chroot, '/dev')
|
fu.mount_bind(chroot, '/dev')
|
||||||
fu.mount_bind(chroot, '/proc')
|
fu.mount_bind(chroot, '/proc')
|
||||||
|
mtab = utils.execute(
|
||||||
|
'chroot', chroot, 'grep', '-v', 'rootfs', '/proc/mounts')[0]
|
||||||
|
with open(chroot + '/etc/mtab', 'wb') as f:
|
||||||
|
f.write(mtab)
|
||||||
|
|
||||||
def umount_target(self, chroot):
|
def umount_target(self, chroot):
|
||||||
LOG.debug('Umounting target file systems')
|
LOG.debug('Umounting target file systems')
|
||||||
key = lambda x: len(x.mount.rstrip('/').split('/'))
|
|
||||||
for fs in sorted(self.partition_scheme.fss, key=key, reverse=True):
|
|
||||||
fu.umount_fs(fs.device)
|
|
||||||
fu.umount_fs(chroot + '/proc')
|
fu.umount_fs(chroot + '/proc')
|
||||||
fu.umount_fs(chroot + '/dev')
|
fu.umount_fs(chroot + '/dev')
|
||||||
fu.umount_fs(chroot + '/sys')
|
fu.umount_fs(chroot + '/sys')
|
||||||
|
key = lambda x: len(x.mount.rstrip('/').split('/'))
|
||||||
|
for fs in sorted(self.partition_scheme.fss, key=key, reverse=True):
|
||||||
|
if fs.mount == 'swap':
|
||||||
|
continue
|
||||||
|
fu.umount_fs(fs.device)
|
||||||
|
|
||||||
def do_bootloader(self):
|
def do_bootloader(self):
|
||||||
LOG.debug('--- Installing bootloader (do_bootloader) ---')
|
LOG.debug('--- Installing bootloader (do_bootloader) ---')
|
||||||
chroot = '/tmp/target'
|
chroot = '/tmp/target'
|
||||||
self.mount_target(chroot)
|
self.mount_target(chroot)
|
||||||
|
|
||||||
grub_version = gu.grub_version_guess(chroot=chroot)
|
mount2uuid = {}
|
||||||
|
for fs in self.partition_scheme.fss:
|
||||||
|
mount2uuid[fs.mount], _ = utils.execute(
|
||||||
|
'blkid', '-o', 'value', '-s', 'UUID', fs.device,
|
||||||
|
check_exit_code=[0])
|
||||||
|
|
||||||
|
grub_version = gu.guess_grub_version(chroot=chroot)
|
||||||
boot_device = self.partition_scheme.boot_device(grub_version)
|
boot_device = self.partition_scheme.boot_device(grub_version)
|
||||||
install_devices = [d.name for d in self.partition_scheme.parteds
|
install_devices = [d.name for d in self.partition_scheme.parteds
|
||||||
if d.install_bootloader]
|
if d.install_bootloader]
|
||||||
|
|
||||||
kernel_params = self.partition_scheme.kernel_params
|
kernel_params = self.partition_scheme.kernel_params
|
||||||
|
kernel_params += ' root=UUID=%s ' % mount2uuid['/']
|
||||||
|
|
||||||
if grub_version == 1:
|
if grub_version == 1:
|
||||||
gu.grub1_cfg(kernel_params=kernel_params, chroot=chroot)
|
gu.grub1_cfg(kernel_params=kernel_params, chroot=chroot)
|
||||||
@ -251,6 +271,16 @@ class Manager(object):
|
|||||||
gu.grub2_cfg(kernel_params=kernel_params, chroot=chroot)
|
gu.grub2_cfg(kernel_params=kernel_params, chroot=chroot)
|
||||||
gu.grub2_install(install_devices, chroot=chroot)
|
gu.grub2_install(install_devices, chroot=chroot)
|
||||||
|
|
||||||
|
with open(chroot + '/etc/fstab', 'wb') as f:
|
||||||
|
for fs in self.partition_scheme.fss:
|
||||||
|
# TODO(kozhukalov): Think of improving the logic so as to
|
||||||
|
# insert a meaningful fsck order value which is last zero
|
||||||
|
# at fstab line. Currently we set it into 0 which means
|
||||||
|
# a corresponding file system will never be checked. We assume
|
||||||
|
# puppet or other configuration tool will care of it.
|
||||||
|
f.write('UUID=%s %s %s defaults 0 0\n' %
|
||||||
|
(mount2uuid[fs.mount], fs.mount, fs.type))
|
||||||
|
|
||||||
self.umount_target(chroot)
|
self.umount_target(chroot)
|
||||||
|
|
||||||
def do_reboot(self):
|
def do_reboot(self):
|
||||||
|
@ -91,7 +91,18 @@ class TestFSUtils(test_base.BaseTestCase):
|
|||||||
'mount', '--bind', '/fake', '/target/fake2', check_exit_code=[0])
|
'mount', '--bind', '/fake', '/target/fake2', check_exit_code=[0])
|
||||||
|
|
||||||
@mock.patch.object(utils, 'execute')
|
@mock.patch.object(utils, 'execute')
|
||||||
def test_umount_fs(self, mock_exec):
|
def test_umount_fs_ok(self, mock_exec):
|
||||||
fu.umount_fs('/fake')
|
fu.umount_fs('/fake')
|
||||||
mock_exec.assert_called_once_with(
|
mock_exec.assert_called_once_with(
|
||||||
'umount', '/fake', check_exit_code=[0])
|
'umount', '/fake', check_exit_code=[0])
|
||||||
|
|
||||||
|
@mock.patch.object(utils, 'execute')
|
||||||
|
def test_umount_fs_error(self, mock_exec):
|
||||||
|
mock_exec.side_effect = [
|
||||||
|
errors.ProcessExecutionError('message'), ('', '')]
|
||||||
|
fu.umount_fs('/fake')
|
||||||
|
expected_calls = [
|
||||||
|
mock.call('umount', '/fake', check_exit_code=[0]),
|
||||||
|
mock.call('umount', '-l', '/fake', check_exit_code=[0])
|
||||||
|
]
|
||||||
|
self.assertEqual(expected_calls, mock_exec.call_args_list)
|
||||||
|
@ -219,8 +219,9 @@ class TestGrubUtils(test_base.BaseTestCase):
|
|||||||
mock_listdir.return_value = ['1', '2', '3']
|
mock_listdir.return_value = ['1', '2', '3']
|
||||||
self.assertRaises(errors.GrubUtilsError, gu.guess_initrd, '/target')
|
self.assertRaises(errors.GrubUtilsError, gu.guess_initrd, '/target')
|
||||||
|
|
||||||
|
@mock.patch.object(gu, 'grub1_stage1')
|
||||||
@mock.patch.object(gu, 'grub1_mbr')
|
@mock.patch.object(gu, 'grub1_mbr')
|
||||||
def test_grub1_install(self, mock_mbr):
|
def test_grub1_install(self, mock_mbr, mock_stage1):
|
||||||
install_devices = ['/dev/foo', '/dev/bar']
|
install_devices = ['/dev/foo', '/dev/bar']
|
||||||
expected_calls_mbr = []
|
expected_calls_mbr = []
|
||||||
for install_device in install_devices:
|
for install_device in install_devices:
|
||||||
@ -228,6 +229,7 @@ class TestGrubUtils(test_base.BaseTestCase):
|
|||||||
mock.call(install_device, '/dev/foo', '0', chroot='/target'))
|
mock.call(install_device, '/dev/foo', '0', chroot='/target'))
|
||||||
gu.grub1_install(install_devices, '/dev/foo1', '/target')
|
gu.grub1_install(install_devices, '/dev/foo1', '/target')
|
||||||
self.assertEqual(expected_calls_mbr, mock_mbr.call_args_list)
|
self.assertEqual(expected_calls_mbr, mock_mbr.call_args_list)
|
||||||
|
mock_stage1.assert_called_once_with(chroot='/target')
|
||||||
# should raise exception if boot_device (second argument)
|
# should raise exception if boot_device (second argument)
|
||||||
# is not a partition but a whole disk
|
# is not a partition but a whole disk
|
||||||
self.assertRaises(errors.GrubUtilsError, gu.grub1_install,
|
self.assertRaises(errors.GrubUtilsError, gu.grub1_install,
|
||||||
@ -239,6 +241,7 @@ class TestGrubUtils(test_base.BaseTestCase):
|
|||||||
def test_grub1_mbr_install_differs_boot(self, mock_exec,
|
def test_grub1_mbr_install_differs_boot(self, mock_exec,
|
||||||
mock_chmod, mock_guess):
|
mock_chmod, mock_guess):
|
||||||
mock_guess.return_value = '/sbin/grub'
|
mock_guess.return_value = '/sbin/grub'
|
||||||
|
mock_exec.return_value = ('stdout', 'stderr')
|
||||||
|
|
||||||
# install_device != boot_disk
|
# install_device != boot_disk
|
||||||
batch = 'device (hd0) /dev/foo\n'
|
batch = 'device (hd0) /dev/foo\n'
|
||||||
@ -274,6 +277,7 @@ class TestGrubUtils(test_base.BaseTestCase):
|
|||||||
def test_grub1_mbr_install_same_as_boot(self, mock_exec,
|
def test_grub1_mbr_install_same_as_boot(self, mock_exec,
|
||||||
mock_chmod, mock_guess):
|
mock_chmod, mock_guess):
|
||||||
mock_guess.return_value = '/sbin/grub'
|
mock_guess.return_value = '/sbin/grub'
|
||||||
|
mock_exec.return_value = ('stdout', 'stderr')
|
||||||
|
|
||||||
# install_device == boot_disk
|
# install_device == boot_disk
|
||||||
batch = 'device (hd0) /dev/foo\n'
|
batch = 'device (hd0) /dev/foo\n'
|
||||||
|
@ -13,8 +13,11 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from fuel_agent import errors
|
from fuel_agent import errors
|
||||||
|
from fuel_agent.openstack.common import log as logging
|
||||||
from fuel_agent.utils import utils
|
from fuel_agent.utils import utils
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def make_fs(fs_type, fs_options, fs_label, dev):
|
def make_fs(fs_type, fs_options, fs_label, dev):
|
||||||
# NOTE(agordeev): notice the different flag to force the fs creating
|
# NOTE(agordeev): notice the different flag to force the fs creating
|
||||||
@ -56,4 +59,11 @@ def mount_bind(chroot, path, path2=None):
|
|||||||
|
|
||||||
|
|
||||||
def umount_fs(fs_mount):
|
def umount_fs(fs_mount):
|
||||||
|
try:
|
||||||
|
LOG.debug('Trying to umount {0}'.format(fs_mount))
|
||||||
utils.execute('umount', fs_mount, check_exit_code=[0])
|
utils.execute('umount', fs_mount, check_exit_code=[0])
|
||||||
|
except errors.ProcessExecutionError as e:
|
||||||
|
LOG.warning('Error while umounting {0} '
|
||||||
|
'exc={1}'.format(fs_mount, e.message))
|
||||||
|
LOG.debug('Trying lazy umounting {0}'.format(fs_mount))
|
||||||
|
utils.execute('umount', '-l', fs_mount, check_exit_code=[0])
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import shutil
|
||||||
|
|
||||||
from fuel_agent import errors
|
from fuel_agent import errors
|
||||||
from fuel_agent.openstack.common import log as logging
|
from fuel_agent.openstack.common import log as logging
|
||||||
@ -70,6 +71,15 @@ def guess_grub_install(chroot=''):
|
|||||||
raise errors.GrubUtilsError('grub-install not found')
|
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
|
||||||
|
|
||||||
|
|
||||||
def guess_kernel(chroot=''):
|
def guess_kernel(chroot=''):
|
||||||
for filename in sorted(os.listdir(chroot + '/boot'), reverse=True):
|
for filename in sorted(os.listdir(chroot + '/boot'), reverse=True):
|
||||||
# We assume kernel name is always starts with vmlinuz.
|
# We assume kernel name is always starts with vmlinuz.
|
||||||
@ -98,7 +108,7 @@ def grub1_install(install_devices, boot_device, chroot=''):
|
|||||||
'boot device must be a partition')
|
'boot device must be a partition')
|
||||||
boot_disk = match.group(1)
|
boot_disk = match.group(1)
|
||||||
boot_part = str(int(match.group(3)) - 1)
|
boot_part = str(int(match.group(3)) - 1)
|
||||||
|
grub1_stage1(chroot=chroot)
|
||||||
for install_device in install_devices:
|
for install_device in install_devices:
|
||||||
grub1_mbr(install_device, boot_disk, boot_part, chroot=chroot)
|
grub1_mbr(install_device, boot_disk, boot_part, chroot=chroot)
|
||||||
|
|
||||||
@ -139,7 +149,23 @@ def grub1_mbr(install_device, boot_disk, boot_part, chroot=''):
|
|||||||
cmd = ['/tmp/grub.sh']
|
cmd = ['/tmp/grub.sh']
|
||||||
if chroot:
|
if chroot:
|
||||||
cmd[:0] = ['chroot', chroot]
|
cmd[:0] = ['chroot', chroot]
|
||||||
utils.execute(*cmd, run_as_root=True, check_exit_code=[0])
|
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,
|
def grub1_cfg(kernel=None, initrd=None,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user