Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions coriolis/osmorphing/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -738,9 +738,41 @@ def _set_grub2_cmdline(self, config_obj, options, clobber=False):
self.set_grub_value(
"GRUB_CMDLINE_LINUX", kernel_cmd, config_obj, replace=replace)

def _get_grub_default_conf(self):
grub_conf = "/etc/default/grub"
if self._test_path_chroot(grub_conf):
return grub_conf
return None

def _set_grub_os_prober_setting(self, grub_conf, value):
"""Set or remove GRUB_DISABLE_OS_PROBER in /etc/default/grub."""
if value is None:
self._exec_cmd_chroot(
"sed -i '/^GRUB_DISABLE_OS_PROBER=/d' %s" % grub_conf)
return
config_obj = self._get_grub_config_obj(grub_conf)
replace = "GRUB_DISABLE_OS_PROBER" in config_obj["contents"]
self.set_grub_value(
"GRUB_DISABLE_OS_PROBER", value, config_obj, replace=replace)
self._apply_grub2_config(config_obj, execute_update_grub=False)

def _execute_update_grub(self):
update_cmd = self.get_update_grub2_command()
self._exec_cmd_chroot(update_cmd)
"""Regenerate guest GRUB config.

Temporarily disable os-prober to prevent discovery of host boot
entries.
"""
grub_conf = self._get_grub_default_conf()
original_value = None
if grub_conf:
original_value = self._read_grub_config(grub_conf).get(
"GRUB_DISABLE_OS_PROBER")
self._set_grub_os_prober_setting(grub_conf, "true")
try:
self._exec_cmd_chroot(self.get_update_grub2_command())
finally:
if grub_conf:
self._set_grub_os_prober_setting(grub_conf, original_value)

def _schedule_grub2_update(self):
"""Flags that the GRUB2 config needs to be regenerated.
Expand Down
155 changes: 153 additions & 2 deletions coriolis/tests/osmorphing/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1145,19 +1145,170 @@ def test__set_grub2_cmdline_no_options_to_add(self, mock_set_grub_value):
clobber=False)
mock_set_grub_value.assert_not_called()

@mock.patch.object(
base.BaseLinuxOSMorphingTools, '_get_grub_default_conf',
return_value=None,
)
@mock.patch.object(base.BaseLinuxOSMorphingTools, '_exec_cmd_chroot')
@mock.patch.object(
base.BaseLinuxOSMorphingTools, 'get_update_grub2_command'
)
def test__execute_update_grub(self, mock_get_update_grub2_command,
mock_exec_cmd_chroot):
def test__execute_update_grub(
self,
mock_get_update_grub2_command,
mock_exec_cmd_chroot,
_mock_get_grub_default_conf):
self.os_morphing_tools._execute_update_grub()

mock_get_update_grub2_command.assert_called_once_with()
mock_exec_cmd_chroot.assert_called_once_with(
mock_get_update_grub2_command.return_value
)

@mock.patch.object(base.BaseLinuxOSMorphingTools, '_test_path_chroot')
def test__get_grub_default_conf_exists(self, mock_test_path_chroot):
mock_test_path_chroot.return_value = True

result = self.os_morphing_tools._get_grub_default_conf()

mock_test_path_chroot.assert_called_once_with('/etc/default/grub')
self.assertEqual(result, '/etc/default/grub')

@mock.patch.object(base.BaseLinuxOSMorphingTools, '_test_path_chroot')
def test__get_grub_default_conf_missing(self, mock_test_path_chroot):
mock_test_path_chroot.return_value = False

result = self.os_morphing_tools._get_grub_default_conf()

mock_test_path_chroot.assert_called_once_with('/etc/default/grub')
self.assertIsNone(result)

@mock.patch.object(base.BaseLinuxOSMorphingTools, '_exec_cmd_chroot')
def test__set_grub_os_prober_setting_remove(
self, mock_exec_cmd_chroot):
grub_conf = '/etc/default/grub'

self.os_morphing_tools._set_grub_os_prober_setting(grub_conf, None)

mock_exec_cmd_chroot.assert_called_once_with(
"sed -i '/^GRUB_DISABLE_OS_PROBER=/d' %s" % grub_conf)

@mock.patch.object(base.BaseLinuxOSMorphingTools, '_apply_grub2_config')
@mock.patch.object(base.BaseLinuxOSMorphingTools, 'set_grub_value')
@mock.patch.object(base.BaseLinuxOSMorphingTools, '_get_grub_config_obj')
def test__set_grub_os_prober_setting_append(
self, mock_get_grub_config_obj, mock_set_grub_value,
mock_apply_grub2_config):
grub_conf = '/etc/default/grub'
config_obj = {
'location': mock.sentinel.location,
'source': grub_conf,
'contents': {},
}
mock_get_grub_config_obj.return_value = config_obj

self.os_morphing_tools._set_grub_os_prober_setting(
grub_conf, 'true')

mock_get_grub_config_obj.assert_called_once_with(grub_conf)
mock_set_grub_value.assert_called_once_with(
'GRUB_DISABLE_OS_PROBER', 'true', config_obj, replace=False)
mock_apply_grub2_config.assert_called_once_with(
config_obj, execute_update_grub=False)

@mock.patch.object(base.BaseLinuxOSMorphingTools, '_apply_grub2_config')
@mock.patch.object(base.BaseLinuxOSMorphingTools, 'set_grub_value')
@mock.patch.object(base.BaseLinuxOSMorphingTools, '_get_grub_config_obj')
def test__set_grub_os_prober_setting_replace(
self, mock_get_grub_config_obj, mock_set_grub_value,
mock_apply_grub2_config):
grub_conf = '/etc/default/grub'
config_obj = {
'location': mock.sentinel.location,
'source': grub_conf,
'contents': {'GRUB_DISABLE_OS_PROBER': 'false'},
}
mock_get_grub_config_obj.return_value = config_obj

self.os_morphing_tools._set_grub_os_prober_setting(
grub_conf, 'true')

mock_get_grub_config_obj.assert_called_once_with(grub_conf)
mock_set_grub_value.assert_called_once_with(
'GRUB_DISABLE_OS_PROBER', 'true', config_obj, replace=True)
mock_apply_grub2_config.assert_called_once_with(
config_obj, execute_update_grub=False)

@ddt.data(
({}, None),
({'GRUB_DISABLE_OS_PROBER': 'false'}, 'false'),
({'GRUB_DISABLE_OS_PROBER': 'true'}, 'true'),
)
@ddt.unpack
@mock.patch.object(
base.BaseLinuxOSMorphingTools, '_set_grub_os_prober_setting')
@mock.patch.object(base.BaseLinuxOSMorphingTools, '_exec_cmd_chroot')
@mock.patch.object(
base.BaseLinuxOSMorphingTools, 'get_update_grub2_command')
@mock.patch.object(base.BaseLinuxOSMorphingTools, '_read_grub_config')
@mock.patch.object(
base.BaseLinuxOSMorphingTools, '_get_grub_default_conf',
return_value='/etc/default/grub',
)
def test__execute_update_grub_toggles_os_prober(
self,
grub_contents,
expected_restore_value,
_mock_get_grub_default_conf,
mock_read_grub_config,
mock_get_update_grub2_command,
mock_exec_cmd_chroot,
mock_set_grub_os_prober_setting):
mock_read_grub_config.return_value = grub_contents

self.os_morphing_tools._execute_update_grub()

mock_read_grub_config.assert_called_once_with('/etc/default/grub')
mock_set_grub_os_prober_setting.assert_has_calls([
mock.call('/etc/default/grub', 'true'),
mock.call('/etc/default/grub', expected_restore_value),
])
mock_get_update_grub2_command.assert_called_once_with()
mock_exec_cmd_chroot.assert_called_once_with(
mock_get_update_grub2_command.return_value)

@mock.patch.object(
base.BaseLinuxOSMorphingTools, '_set_grub_os_prober_setting')
@mock.patch.object(base.BaseLinuxOSMorphingTools, '_exec_cmd_chroot')
@mock.patch.object(
base.BaseLinuxOSMorphingTools, 'get_update_grub2_command')
@mock.patch.object(base.BaseLinuxOSMorphingTools, '_read_grub_config')
@mock.patch.object(
base.BaseLinuxOSMorphingTools, '_get_grub_default_conf',
return_value='/etc/default/grub',
)
def test__execute_update_grub_restores_os_prober_on_failure(
self,
_mock_get_grub_default_conf,
mock_read_grub_config,
mock_get_update_grub2_command,
mock_exec_cmd_chroot,
mock_set_grub_os_prober_setting):
mock_read_grub_config.return_value = {
'GRUB_DISABLE_OS_PROBER': 'false',
}
mock_exec_cmd_chroot.side_effect = CoriolisTestException()

self.assertRaises(
CoriolisTestException,
self.os_morphing_tools._execute_update_grub)

mock_set_grub_os_prober_setting.assert_has_calls([
mock.call('/etc/default/grub', 'true'),
mock.call('/etc/default/grub', 'false'),
])
mock_get_update_grub2_command.assert_called_once_with()

@mock.patch.object(base.BaseLinuxOSMorphingTools, '_execute_update_grub')
def test__schedule_grub2_update(self, mock_execute_update_grub):
self.assertFalse(self.os_morphing_tools._grub2_update_scheduled)
Expand Down
Loading