curtin-dev team mailing list archive
-
curtin-dev team
-
Mailing list archive
-
Message #00156
[Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
Ryan Harper has proposed merging ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master.
Commit message:
Replace grub-shell-helper with install_grub command
The install_grub command implemented in shell code inside
helpers/common lacked unittests. We've had some recent and
ongoing changes in this space which need greater unittest
coverage. Add a new command line option and update
curthooks to utilize it.
Also:
- Move util.get_architecture into distro class
Requested reviews:
curtin developers (curtin-dev)
For more details, see:
https://code.launchpad.net/~raharper/curtin/+git/curtin/+merge/382931
--
Your team curtin developers is requested to review the proposed merge of ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master.
diff --git a/curtin/commands/apt_config.py b/curtin/commands/apt_config.py
index f012ae0..e7d84c0 100644
--- a/curtin/commands/apt_config.py
+++ b/curtin/commands/apt_config.py
@@ -46,7 +46,7 @@ def get_default_mirrors(arch=None):
architecture, for more see:
https://wiki.ubuntu.com/UbuntuDevelopment/PackageArchive#Ports"""
if arch is None:
- arch = util.get_architecture()
+ arch = distro.get_architecture()
if arch in PRIMARY_ARCHES:
return PRIMARY_ARCH_MIRRORS.copy()
if arch in PORTS_ARCHES:
@@ -61,7 +61,7 @@ def handle_apt(cfg, target=None):
standalone command.
"""
release = distro.lsb_release(target=target)['codename']
- arch = util.get_architecture(target)
+ arch = distro.get_architecture(target)
mirrors = find_apt_mirror_info(cfg, arch)
LOG.debug("Apt Mirror info: %s", mirrors)
@@ -188,7 +188,7 @@ def mirrorurl_to_apt_fileprefix(mirror):
def rename_apt_lists(new_mirrors, target=None):
"""rename_apt_lists - rename apt lists to preserve old cache data"""
- default_mirrors = get_default_mirrors(util.get_architecture(target))
+ default_mirrors = get_default_mirrors(distro.get_architecture(target))
pre = paths.target_path(target, APT_LISTS)
for (name, omirror) in default_mirrors.items():
@@ -285,7 +285,7 @@ def generate_sources_list(cfg, release, mirrors, target=None):
create a source.list file based on a custom or default template
by replacing mirrors and release in the template
"""
- default_mirrors = get_default_mirrors(util.get_architecture(target))
+ default_mirrors = get_default_mirrors(distro.get_architecture(target))
aptsrc = "/etc/apt/sources.list"
params = {'RELEASE': release}
for k in mirrors:
@@ -512,7 +512,7 @@ def find_apt_mirror_info(cfg, arch=None):
"""
if arch is None:
- arch = util.get_architecture()
+ arch = distro.get_architecture()
LOG.debug("got arch for mirror selection: %s", arch)
pmirror = get_mirror(cfg, "primary", arch)
LOG.debug("got primary mirror: %s", pmirror)
diff --git a/curtin/commands/curthooks.py b/curtin/commands/curthooks.py
index 4afe00c..f705711 100644
--- a/curtin/commands/curthooks.py
+++ b/curtin/commands/curthooks.py
@@ -26,6 +26,7 @@ from curtin.distro import DISTROS
from curtin.net import deps as ndeps
from curtin.reporter import events
from curtin.commands import apply_net, apt_config
+from curtin.commands.install_grub import install_grub
from curtin.url_helper import get_maas_version
from . import populate_one_subcmd
@@ -307,7 +308,7 @@ def chzdev_prepare_for_import(chzdev_conf):
def get_flash_kernel_pkgs(arch=None, uefi=None):
if arch is None:
- arch = util.get_architecture()
+ arch = distro.get_architecture()
if uefi is None:
uefi = util.is_uefi_bootable()
if uefi:
@@ -682,28 +683,6 @@ def setup_grub(cfg, target, osfamily=DISTROS.debian):
else:
instdevs = list(blockdevs)
- env = os.environ.copy()
-
- replace_default = grubcfg.get('replace_linux_default', True)
- if str(replace_default).lower() in ("0", "false"):
- env['REPLACE_GRUB_LINUX_DEFAULT'] = "0"
- else:
- env['REPLACE_GRUB_LINUX_DEFAULT'] = "1"
-
- probe_os = grubcfg.get('probe_additional_os', False)
- if probe_os not in (False, True):
- raise ValueError("Unexpected value %s for 'probe_additional_os'. "
- "Value must be boolean" % probe_os)
- env['DISABLE_OS_PROBER'] = "0" if probe_os else "1"
-
- # if terminal is present in config, but unset, then don't
- grub_terminal = grubcfg.get('terminal', 'console')
- if not isinstance(grub_terminal, str):
- raise ValueError("Unexpected value %s for 'terminal'. "
- "Value must be a string" % grub_terminal)
- if not grub_terminal.lower() == "unmodified":
- env['GRUB_TERMINAL'] = grub_terminal
-
if instdevs:
instdevs = [block.get_dev_name_entry(i)[1] for i in instdevs]
if osfamily == DISTROS.debian:
@@ -711,38 +690,15 @@ def setup_grub(cfg, target, osfamily=DISTROS.debian):
else:
instdevs = ["none"]
- if uefi_bootable and grubcfg.get('update_nvram', True):
+ update_nvram = grubcfg.get('update_nvram', True)
+ if uefi_bootable and update_nvram:
uefi_remove_old_loaders(grubcfg, target)
LOG.debug("installing grub to %s [replace_default=%s]",
- instdevs, replace_default)
+ instdevs, grubcfg.get('replace_default'))
+ install_grub(instdevs, target, uefi=uefi_bootable, grubcfg=grubcfg)
- with util.ChrootableTarget(target):
- args = ['install-grub']
- if uefi_bootable:
- args.append("--uefi")
- LOG.debug("grubcfg: %s", grubcfg)
- if grubcfg.get('update_nvram', True):
- LOG.debug("GRUB UEFI enabling NVRAM updates")
- args.append("--update-nvram")
- else:
- LOG.debug("NOT enabling UEFI nvram updates")
- LOG.debug("Target system may not boot")
- if len(instdevs) > 1:
- instdevs = [instdevs[0]]
- LOG.debug("Selecting primary EFI boot device %s for install",
- instdevs[0])
-
- args.append('--os-family=%s' % osfamily)
- args.append(target)
-
- # capture stdout and stderr joined.
- join_stdout_err = ['sh', '-c', 'exec "$0" "$@" 2>&1']
- out, _err = util.subp(
- join_stdout_err + args + instdevs, env=env, capture=True)
- LOG.debug("%s\n%s\n", args + instdevs, out)
-
- if uefi_bootable and grubcfg.get('update_nvram', True):
+ if uefi_bootable and update_nvram:
uefi_remove_duplicate_entries(grubcfg, target)
uefi_reorder_loaders(grubcfg, target)
@@ -1207,7 +1163,7 @@ def install_missing_packages(cfg, target, osfamily=DISTROS.debian):
# signed version.
uefi_pkgs.extend(['grub2-efi-x64', 'shim-x64'])
elif osfamily == DISTROS.debian:
- arch = util.get_architecture()
+ arch = distro.get_architecture()
if arch == 'i386':
arch = 'ia32'
uefi_pkgs.append('grub-efi-%s' % arch)
diff --git a/curtin/commands/install_grub.py b/curtin/commands/install_grub.py
new file mode 100644
index 0000000..de36b0c
--- /dev/null
+++ b/curtin/commands/install_grub.py
@@ -0,0 +1,353 @@
+import os
+import re
+import shutil
+import sys
+
+from curtin import block
+from curtin import config
+from curtin import distro
+from curtin import util
+from curtin.log import LOG
+from curtin.paths import target_path
+from curtin.reporter import events
+from . import populate_one_subcmd
+
+CMD_ARGUMENTS = (
+ ((('-t', '--target'),
+ {'help': 'operate on target. default is env[TARGET_MOUNT_POINT]',
+ 'action': 'store', 'metavar': 'TARGET', 'default': None}),
+ (('-c', '--config'),
+ {'help': 'operate on config. default is env[CONFIG]',
+ 'action': 'store', 'metavar': 'CONFIG', 'default': None}),
+ )
+)
+
+GRUB_MULTI_INSTALL = '/usr/lib/grub/grub-multi-install'
+
+
+def get_grub_package(target_arch, uefi, rhel_ver=None):
+ if 'ppc64' in target_arch:
+ return ('grub-ieee1275', 'powerpc-ieee1275')
+ if uefi:
+ if target_arch == 'amd64':
+ grub_name = 'grub-efi-%s' % target_arch
+ grub_target = "x86_64-efi"
+ elif target_arch == 'x86_64':
+ # centos 7+, no centos6 support
+ # grub2-efi-x64 installs a signed grub bootloader while
+ # curtin uses grub2-efi-x64-modules to generate grubx64.efi.
+ # Either works just check that one of them is installed.
+ grub_name = "grub2-efi-x64"
+ grub_target = "x86_64-efi"
+ elif target_arch == 'arm64':
+ grub_name = 'grub-efi-%s' % target_arch
+ grub_target = "arm64-efi"
+ elif target_arch == 'i386':
+ grub_name = 'grub-efi-ia32'
+ grub_target = 'i386-efi'
+ else:
+ raise ValueError('Unsupported UEFI arch: %s' % target_arch)
+ else:
+ grub_target = 'i386-pc'
+ if target_arch in ['i386', 'amd64']:
+ grub_name = 'grub-pc'
+ elif target_arch == 'x86_64':
+ if rhel_ver == '6':
+ grub_name = 'grub'
+ elif rhel_ver in ['7', '8']:
+ grub_name = 'grub2-pc'
+ else:
+ raise ValueError('Unsupported RHEL version: %s', rhel_ver)
+ else:
+ raise ValueError('Unsupported arch: %s' % target_arch)
+
+ return (grub_name, grub_target)
+
+
+def get_grub_config_file(distroinfo):
+ if distroinfo.family == distro.DISTROS.redhat:
+ return '/etc/default/grub'
+ # ubuntu writes to /etc/default/grub.d/50-curtin-settings.cfg
+ # to avoid tripping prompts on upgrade LP: #564853
+ return '/etc/default/grub.d/50-curtin-settings.cfg'
+
+
+def prepare_grub_dir(target, grub_cfg):
+ util.ensure_dir(target_path(target, grub_cfg))
+
+ # LP: #1179940 . The 50-cloudig-settings.cfg file is written by the cloud
+ # images build and defines/override some settings. Disable it.
+ ci_cfg = target_path(target,
+ os.path.join(
+ os.path.dirname(grub_cfg),
+ "50-cloudimg-settings.cfg"))
+
+ if os.path.exists(ci_cfg):
+ LOG.debug('grub: moved %s out of the way', ci_cfg)
+ shutil.move(ci_cfg, ci_cfg + '.disabled')
+
+
+def get_carryover_params(distroinfo):
+ # return a string to append to installed systems boot parameters
+ # it may include a '--' after a '---'
+ # see LP: 1402042 for some history here.
+ # this is similar to 'user-params' from d-i
+ cmdline = util.load_file('/proc/cmdline')
+ preferred_sep = '---' # KERNEL_CMDLINE_COPY_TO_INSTALL_SEP
+ legacy_sep = '--'
+
+ def wrap(sep):
+ return ' ' + sep + ' '
+
+ if wrap(preferred_sep) in cmdline:
+ lead, extra = cmdline.split(wrap(preferred_sep))
+ elif wrap(legacy_sep) in cmdline:
+ lead, extra = cmdline.split(wrap(legacy_sep))
+ else:
+ extra = ""
+ lead = cmdline
+
+ carry_extra = []
+ if extra:
+ for tok in extra.split():
+ if re.match(r'(BOOTIF=.*|initrd=.*|BOOT_IMAGE=.*)', tok):
+ continue
+ carry_extra.append(tok)
+
+ carry_lead = []
+ for tok in lead.split():
+ if tok in carry_extra:
+ continue
+ if tok.startswith('console='):
+ carry_lead.append(tok)
+
+ # always append rd.auto=1 for redhat family
+ if distroinfo.family == distro.DISTROS.redhat:
+ carry_extra.append('rd.auto=1')
+
+ return carry_lead + carry_extra
+
+
+def replace_grub_cmdline_linux_default(target, grubconf, new_args):
+ newline = 'GRUB_CMDLINE_LINUX_DEFAULT="%s"' % " ".join(new_args)
+ target_grubconf = target_path(target, grubconf)
+ content = ""
+ if os.path.exists(target_grubconf):
+ content = util.load_file(target_grubconf)
+ existing = re.search(
+ r'GRUB_CMDLINE_LINUX_DEFAULT=.*', content, re.MULTILINE)
+ if existing:
+ omode = 'w+'
+ updated_content = content[:existing.start()]
+ updated_content += newline
+ updated_content += content[existing.end():]
+ else:
+ omode = 'a+'
+ updated_content = newline + '\n'
+
+ util.write_file(target_grubconf, updated_content, omode=omode)
+ LOG.debug('updated %s to set: %s', grubconf, newline)
+
+
+def write_grub_config(target, grubcfg, grub_conf, new_params):
+ replace_default = grubcfg.get('replace_linux_default', True)
+ if replace_default:
+ replace_grub_cmdline_linux_default(target, grub_conf, new_params)
+
+ probe_os = grubcfg.get('probe_additional_os', False)
+ if probe_os not in (False, True):
+ raise ValueError("Unexpected value %s for 'probe_additional_os'. "
+ "Value must be boolean" % probe_os)
+ probe_content = [
+ '# Curtin disable grub os prober that might find other OS installs.',
+ 'GRUB_DISABLE_OS_PROBER="%s"' % ('false' if probe_os else 'true'),
+ '']
+ util.write_file(target_path(target, grub_conf),
+ "\n".join(probe_content), omode='a+')
+
+ # if terminal is present in config, but unset, then don't
+ grub_terminal = grubcfg.get('terminal', 'console')
+ if not isinstance(grub_terminal, str):
+ raise ValueError("Unexpected value %s for 'terminal'. "
+ "Value must be a string" % grub_terminal)
+ if not grub_terminal.lower() == "unmodified":
+ terminal_content = [
+ '# Curtin configured GRUB_TERMINAL value',
+ 'GRUB_TERMINAL="%s"' % grub_terminal]
+ util.write_file(target_path(target, grub_conf),
+ "\n".join(terminal_content), omode='a+')
+
+
+def find_efi_loader(target, bootid):
+ efi_path = '/boot/efi/EFI'
+ possible_loaders = [
+ os.path.join(efi_path, bootid, 'shimx64.efi'),
+ os.path.join(efi_path, 'BOOT', 'BOOTX64.EFI'),
+ os.path.join(efi_path, bootid, 'grubx64.efi'),
+ ]
+ for loader in possible_loaders:
+ tloader = target_path(target, path=loader)
+ if os.path.exists(tloader):
+ LOG.debug('find_efi_loader: found %s', loader)
+ return loader
+ return None
+
+
+def get_efi_disk_part(devices):
+ for disk in devices:
+ (parent, partnum) = block.get_blockdev_for_partition(disk)
+ if partnum:
+ return (parent, partnum)
+
+ return (None, None)
+
+
+def get_grub_install_command(uefi, distroinfo):
+ grub_install_cmd = 'grub-install'
+ if distroinfo.family == distro.DISTROS.debian:
+ # prefer grub-multi-install if present
+ if uefi and os.path.exists(GRUB_MULTI_INSTALL):
+ grub_install_cmd = GRUB_MULTI_INSTALL
+ elif distroinfo.family == distro.DISTROS.redhat:
+ grub_install_cmd = 'grub2-install'
+
+ return grub_install_cmd
+
+
+def gen_uefi_install_commands(grub_name, grub_target, grub_cmd, update_nvram,
+ distroinfo, devices, target):
+ install_cmds = [['efibootmgr', '-v']]
+ post_cmds = []
+ bootid = distroinfo.variant
+ efidir = '/boot/efi'
+ if distroinfo.family == distro.DISTROS.debian:
+ install_cmds.append(['dpkg-reconfigure', grub_name])
+ install_cmds.append(['update-grub'])
+ elif distroinfo.family == distro.DISTROS.redhat:
+ loader = find_efi_loader(target, bootid)
+ if loader and update_nvram:
+ grub_cmd = None # don't install just add entry
+ efi_disk, efi_part_num = get_efi_disk_part(devices)
+ install_cmds.append(['efibootmgr', '--create', '--write-signature',
+ '--label', bootid, '--disk', efi_disk,
+ '--part', efi_part_num, '--loader', loader])
+ post_cmds.append(['grub2-mkconfig', '-o',
+ '/boot/efi/EFI/%s/grub.cfg' % bootid])
+ else:
+ post_cmds.append(['grub2-mkconfig', '-o', '/boot/grub2/grub.cfg'])
+ else:
+ raise ValueError("Unsupported os family for grub "
+ "install: %s" % distroinfo.family)
+
+ if grub_cmd == GRUB_MULTI_INSTALL:
+ # grub-multi-install is called with no arguments
+ install_cmds.append([grub_cmd])
+ elif grub_cmd:
+ install_cmds.append(
+ [grub_cmd, '--target=%s' % grub_target,
+ '--efi-directory=%s' % efidir, '--bootloader-id=%s' % bootid,
+ '--recheck'] + ([] if update_nvram else ['--no-nvram']))
+
+ # check efi boot menu before and after
+ post_cmds.append(['efibootmgr', '-v'])
+
+ return (install_cmds, post_cmds)
+
+
+def gen_install_commands(grub_name, grub_cmd, distroinfo, devices,
+ rhel_ver=None):
+ install_cmds = []
+ post_cmds = []
+ if distroinfo.family == distro.DISTROS.debian:
+ install_cmds.append(['dpkg-reconfigure', grub_name])
+ install_cmds.append(['update-grub'])
+ elif distroinfo.family == distro.DISTROS.redhat:
+ if rhel_ver in ["7", "8"]:
+ post_cmds.append(
+ ['grub2-mkconfig', '-o', '/boot/grub2/grub.cfg'])
+ else:
+ raise ValueError('Unsupported "rhel_ver" value: %s' % rhel_ver)
+ else:
+ raise ValueError("Unsupported os family for grub "
+ "install: %s" % distroinfo.family)
+ for dev in devices:
+ install_cmds.append([grub_cmd, dev])
+
+ return (install_cmds, post_cmds)
+
+
+def install_grub(devices, target, uefi=None, grubcfg=None):
+ """Install grub to devices inside target chroot.
+
+ :param: devices: List of block device paths to install grub upon.
+ :param: target: A string specifying the path to the chroot mountpoint.
+ :param: uefi: A boolean set to True if system is UEFI bootable otherwise
+ False.
+ :param: grubcfg: An config dict with grub config options.
+ """
+
+ if not devices:
+ raise ValueError("Invalid parameter 'devices': %s" % devices)
+
+ if not target:
+ raise ValueError("Invalid parameter 'target': %s" % target)
+
+ LOG.debug("install_grub: target=%s devices=%s", target, devices)
+ update_nvram = config.value_as_boolean(grubcfg.get('update_nvram', True))
+ distroinfo = distro.get_distroinfo(target=target)
+ target_arch = distro.get_architecture(target=target)
+ rhel_ver = (distro.rpm_get_dist_id(target)
+ if distroinfo.family == distro.DISTROS.redhat else None)
+
+ if target_arch == "s390x":
+ raise RuntimeError("Grub is not valid for s390x")
+ # verify_target_device_mount(target)
+ grub_name, grub_target = get_grub_package(target_arch, rhel_ver)
+ grub_conf = get_grub_config_file(distroinfo)
+ new_params = get_carryover_params(distroinfo)
+ prepare_grub_dir(target, grub_conf)
+ write_grub_config(target, grubcfg, grub_conf, new_params)
+ grub_cmd = get_grub_install_command(uefi, distroinfo)
+ print(grub_cmd)
+ if uefi:
+ install_cmds, post_cmds = gen_uefi_install_commands(
+ grub_name, grub_target, grub_cmd, update_nvram, distroinfo,
+ devices, target)
+ else:
+ install_cmds, post_cmds = gen_install_commands(
+ grub_name, grub_cmd, distroinfo, devices, rhel_ver)
+
+ LOG.debug('Grub install cmds:\n%s', str(install_cmds + post_cmds))
+ with util.ChrootableTarget(target):
+ for cmd in install_cmds + post_cmds:
+ util.subp(cmd, capture=True)
+
+
+def install_grub_main(args):
+ state = util.load_command_environment()
+
+ if args.target is not None:
+ target = args.target
+ else:
+ target = state['target']
+
+ if target is None:
+ sys.stderr.write("Unable to find target. "
+ "Use --target or set TARGET_MOUNT_POINT\n")
+ sys.exit(2)
+
+ cfg = config.load_command_config(args, state)
+ stack_prefix = state.get('report_stack_prefix', '')
+ uefi = util.is_uefi_bootable()
+ grubcfg = cfg.get('grub')
+ with events.ReportEventStack(
+ name=stack_prefix, reporting_enabled=True, level="INFO",
+ description="Installing grub to target devices"):
+ install_grub(args.devices, target, uefi=uefi, grubcfg=grubcfg)
+ sys.exit(0)
+
+
+def POPULATE_SUBCMD(parser):
+ populate_one_subcmd(parser, CMD_ARGUMENTS, install_grub_main)
+
+# vi: ts=4 expandtab syntax=python
diff --git a/curtin/deps/__init__.py b/curtin/deps/__init__.py
index 714ef18..a9f38d1 100644
--- a/curtin/deps/__init__.py
+++ b/curtin/deps/__init__.py
@@ -5,13 +5,16 @@ import sys
from curtin.util import (
ProcessExecutionError,
- get_architecture,
is_uefi_bootable,
subp,
which,
)
-from curtin.distro import install_packages, lsb_release
+from curtin.distro import (
+ get_architecture,
+ install_packages,
+ lsb_release,
+ )
REQUIRED_IMPORTS = [
# import string to execute, python2 package, python3 package
diff --git a/curtin/distro.py b/curtin/distro.py
index 1f62e7a..c503cc6 100644
--- a/curtin/distro.py
+++ b/curtin/distro.py
@@ -429,6 +429,7 @@ def has_pkg_available(pkg, target=None, osfamily=None):
def get_installed_packages(target=None):
+ out = None
if which('dpkg-query', target=target):
(out, _) = subp(['dpkg-query', '--list'], target=target, capture=True)
elif which('rpm', target=target):
@@ -549,4 +550,27 @@ def fstab_header():
#
# <file system> <mount point> <type> <options> <dump> <pass>""")
+
+def dpkg_get_architecture(target=None):
+ out, _ = subp(['dpkg', '--print-architecture'], capture=True,
+ target=target)
+ return out.strip()
+
+
+def rpm_get_architecture(target=None):
+ out, _ = subp(['rpm', '-E', '%_arch'], capture=True, target=target)
+ return out.strip()
+
+
+def get_architecture(target=None, osfamily=None):
+ if not osfamily:
+ osfamily = get_osfamily(target=target)
+
+ if osfamily == DISTROS.debian:
+ return dpkg_get_architecture(target=target)
+
+ if osfamily == DISTROS.redhat:
+ return rpm_get_architecture(target=target)
+
+
# vi: ts=4 expandtab syntax=python
diff --git a/curtin/util.py b/curtin/util.py
index fa4f3f3..4c42e6b 100644
--- a/curtin/util.py
+++ b/curtin/util.py
@@ -790,12 +790,6 @@ def get_paths(curtin_exe=None, lib=None, helpers=None):
return({'curtin_exe': curtin_exe, 'lib': mydir, 'helpers': helpers})
-def get_architecture(target=None):
- out, _ = subp(['dpkg', '--print-architecture'], capture=True,
- target=target)
- return out.strip()
-
-
def find_newer(src, files):
mtime = os.stat(src).st_mtime
return [f for f in files if
diff --git a/tests/unittests/test_apt_custom_sources_list.py b/tests/unittests/test_apt_custom_sources_list.py
index bf004b1..dafc478 100644
--- a/tests/unittests/test_apt_custom_sources_list.py
+++ b/tests/unittests/test_apt_custom_sources_list.py
@@ -100,11 +100,12 @@ class TestAptSourceConfigSourceList(CiTestCase):
def _apt_source_list(self, cfg, expected):
"_apt_source_list - Test rendering from template (generic)"
- arch = util.get_architecture()
+ arch = distro.get_architecture()
# would fail inside the unittest context
bpath = "curtin.commands.apt_config."
upath = bpath + "util."
- self.add_patch(upath + "get_architecture", "mockga", return_value=arch)
+ dpath = bpath + 'distro.'
+ self.add_patch(dpath + "get_architecture", "mockga", return_value=arch)
self.add_patch(upath + "write_file", "mockwrite")
self.add_patch(bpath + "os.rename", "mockrename")
self.add_patch(upath + "load_file", "mockload_file",
@@ -143,9 +144,9 @@ class TestAptSourceConfigSourceList(CiTestCase):
cfg = yaml.safe_load(YAML_TEXT_CUSTOM_SL)
target = self.new_root
- arch = util.get_architecture()
+ arch = distro.get_architecture()
# would fail inside the unittest context
- with mock.patch.object(util, 'get_architecture', return_value=arch):
+ with mock.patch.object(distro, 'get_architecture', return_value=arch):
with mock.patch.object(distro, 'lsb_release',
return_value={'codename': 'fakerel'}):
apt_config.handle_apt(cfg, target)
@@ -155,7 +156,7 @@ class TestAptSourceConfigSourceList(CiTestCase):
util.load_file(paths.target_path(target, "/etc/apt/sources.list")))
@mock.patch("curtin.distro.lsb_release")
- @mock.patch("curtin.util.get_architecture", return_value="amd64")
+ @mock.patch("curtin.distro.get_architecture", return_value="amd64")
def test_trusty_source_lists(self, m_get_arch, m_lsb_release):
"""Support mirror equivalency with and without trailing /.
diff --git a/tests/unittests/test_apt_source.py b/tests/unittests/test_apt_source.py
index 6ae5579..74ad7e1 100644
--- a/tests/unittests/test_apt_source.py
+++ b/tests/unittests/test_apt_source.py
@@ -90,7 +90,7 @@ class TestAptSourceConfig(CiTestCase):
"""
params = {}
params['RELEASE'] = distro.lsb_release()['codename']
- arch = util.get_architecture()
+ arch = distro.get_architecture()
params['MIRROR'] = apt_config.get_default_mirrors(arch)["PRIMARY"]
return params
@@ -457,7 +457,7 @@ class TestAptSourceConfig(CiTestCase):
self.assertFalse(os.path.isfile(self.aptlistfile2))
self.assertFalse(os.path.isfile(self.aptlistfile3))
- @mock.patch("curtin.commands.apt_config.util.get_architecture")
+ @mock.patch("curtin.commands.apt_config.distro.get_architecture")
def test_mir_apt_list_rename(self, m_get_architecture):
"""test_mir_apt_list_rename - Test find mirror and apt list renaming"""
pre = "/var/lib/apt/lists"
@@ -495,7 +495,7 @@ class TestAptSourceConfig(CiTestCase):
mockren.assert_any_call(fromfn, tofn)
- @mock.patch("curtin.commands.apt_config.util.get_architecture")
+ @mock.patch("curtin.commands.apt_config.distro.get_architecture")
def test_mir_apt_list_rename_non_slash(self, m_get_architecture):
target = os.path.join(self.tmp, "rename_non_slash")
apt_lists_d = os.path.join(target, "./" + apt_config.APT_LISTS)
@@ -577,7 +577,7 @@ class TestAptSourceConfig(CiTestCase):
def test_mirror_default(self):
"""test_mirror_default - Test without defining a mirror"""
- arch = util.get_architecture()
+ arch = distro.get_architecture()
default_mirrors = apt_config.get_default_mirrors(arch)
pmir = default_mirrors["PRIMARY"]
smir = default_mirrors["SECURITY"]
@@ -628,7 +628,7 @@ class TestAptSourceConfig(CiTestCase):
self.assertEqual(mirrors['SECURITY'],
smir)
- @mock.patch("curtin.commands.apt_config.util.get_architecture")
+ @mock.patch("curtin.commands.apt_config.distro.get_architecture")
def test_get_default_mirrors_non_intel_no_arch(self, m_get_architecture):
arch = 'ppc64el'
m_get_architecture.return_value = arch
@@ -645,7 +645,7 @@ class TestAptSourceConfig(CiTestCase):
def test_mirror_arches_sysdefault(self):
"""test_mirror_arches - Test arches falling back to sys default"""
- arch = util.get_architecture()
+ arch = distro.get_architecture()
default_mirrors = apt_config.get_default_mirrors(arch)
pmir = default_mirrors["PRIMARY"]
smir = default_mirrors["SECURITY"]
diff --git a/tests/unittests/test_commands_install_grub.py b/tests/unittests/test_commands_install_grub.py
new file mode 100644
index 0000000..1c86539
--- /dev/null
+++ b/tests/unittests/test_commands_install_grub.py
@@ -0,0 +1,956 @@
+# This file is part of curtin. See LICENSE file for copyright and license info.
+
+from curtin import distro
+from curtin import util
+from curtin.commands import install_grub
+from .helpers import CiTestCase
+
+import mock
+import os
+
+
+class TestGetGrubPackage(CiTestCase):
+
+ def test_ppc64_arch(self):
+ target_arch = 'ppc64le'
+ uefi = False
+ rhel_ver = None
+ self.assertEqual(
+ ('grub-ieee1275', 'powerpc-ieee1275'),
+ install_grub.get_grub_package(target_arch, uefi, rhel_ver))
+
+ def test_uefi_debian_amd64(self):
+ target_arch = 'amd64'
+ uefi = True
+ rhel_ver = None
+ self.assertEqual(
+ ('grub-efi-amd64', 'x86_64-efi'),
+ install_grub.get_grub_package(target_arch, uefi, rhel_ver))
+
+ def test_uefi_rhel7_amd64(self):
+ target_arch = 'x86_64'
+ uefi = True
+ rhel_ver = '7'
+ self.assertEqual(
+ ('grub2-efi-x64', 'x86_64-efi'),
+ install_grub.get_grub_package(target_arch, uefi, rhel_ver))
+
+ def test_uefi_rhel8_amd64(self):
+ target_arch = 'x86_64'
+ uefi = True
+ rhel_ver = '8'
+ self.assertEqual(
+ ('grub2-efi-x64', 'x86_64-efi'),
+ install_grub.get_grub_package(target_arch, uefi, rhel_ver))
+
+ def test_uefi_debian_arm64(self):
+ target_arch = 'arm64'
+ uefi = True
+ rhel_ver = None
+ self.assertEqual(
+ ('grub-efi-arm64', 'arm64-efi'),
+ install_grub.get_grub_package(target_arch, uefi, rhel_ver))
+
+ def test_uefi_debian_i386(self):
+ target_arch = 'i386'
+ uefi = True
+ rhel_ver = None
+ self.assertEqual(
+ ('grub-efi-ia32', 'i386-efi'),
+ install_grub.get_grub_package(target_arch, uefi, rhel_ver))
+
+ def test_debian_amd64(self):
+ target_arch = 'amd64'
+ uefi = False
+ rhel_ver = None
+ self.assertEqual(
+ ('grub-pc', 'i386-pc'),
+ install_grub.get_grub_package(target_arch, uefi, rhel_ver))
+
+ def test_rhel6_amd64(self):
+ target_arch = 'x86_64'
+ uefi = False
+ rhel_ver = '6'
+ self.assertEqual(
+ ('grub', 'i386-pc'),
+ install_grub.get_grub_package(target_arch, uefi, rhel_ver))
+
+ def test_rhel7_amd64(self):
+ target_arch = 'x86_64'
+ uefi = False
+ rhel_ver = '7'
+ self.assertEqual(
+ ('grub2-pc', 'i386-pc'),
+ install_grub.get_grub_package(target_arch, uefi, rhel_ver))
+
+ def test_rhel8_amd64(self):
+ target_arch = 'x86_64'
+ uefi = False
+ rhel_ver = '8'
+ self.assertEqual(
+ ('grub2-pc', 'i386-pc'),
+ install_grub.get_grub_package(target_arch, uefi, rhel_ver))
+
+ def test_debian_i386(self):
+ target_arch = 'i386'
+ uefi = False
+ rhel_ver = None
+ self.assertEqual(
+ ('grub-pc', 'i386-pc'),
+ install_grub.get_grub_package(target_arch, uefi, rhel_ver))
+
+ def test_invalid_rhel_version(self):
+ with self.assertRaises(ValueError):
+ install_grub.get_grub_package('x86_64', uefi=False, rhel_ver='5')
+
+ def test_invalid_arch(self):
+ with self.assertRaises(ValueError):
+ install_grub.get_grub_package(self.random_string(),
+ uefi=False, rhel_ver=None)
+
+ def test_invalid_arch_uefi(self):
+ with self.assertRaises(ValueError):
+ install_grub.get_grub_package(self.random_string(),
+ uefi=True, rhel_ver=None)
+
+
+class TestGetGrubConfigFile(CiTestCase):
+
+ @mock.patch('curtin.commands.install_grub.distro.os_release')
+ def test_grub_config_redhat(self, mock_os_release):
+ mock_os_release.return_value = {'ID': 'redhat'}
+ distroinfo = install_grub.distro.get_distroinfo()
+ self.assertEqual(
+ '/etc/default/grub',
+ install_grub.get_grub_config_file(distroinfo))
+
+ @mock.patch('curtin.commands.install_grub.distro.os_release')
+ def test_grub_config_debian(self, mock_os_release):
+ mock_os_release.return_value = {'ID': 'ubuntu'}
+ distroinfo = install_grub.distro.get_distroinfo()
+ self.assertEqual(
+ '/etc/default/grub.d/50-curtin-settings.cfg',
+ install_grub.get_grub_config_file(distroinfo))
+
+
+class TestPrepareGrubDir(CiTestCase):
+
+ def setUp(self):
+ super(TestPrepareGrubDir, self).setUp()
+ self.target = self.tmp_dir()
+ self.add_patch('curtin.commands.install_grub.util.ensure_dir',
+ 'm_ensure_dir')
+ self.add_patch('curtin.commands.install_grub.shutil.move', 'm_move')
+ self.add_patch('curtin.commands.install_grub.os.path.exists', 'm_path')
+
+ def test_prepare_grub_dir(self):
+ grub_conf = 'etc/default/grub.d/%s' % self.random_string()
+ target_grub_conf = os.path.join(self.target, grub_conf)
+ ci_conf = os.path.join(
+ os.path.dirname(target_grub_conf), '50-cloudimg-settings.cfg')
+ self.m_path.return_value = True
+ install_grub.prepare_grub_dir(self.target, grub_conf)
+ self.m_ensure_dir.assert_called_with(target_grub_conf)
+ self.m_move.assert_called_with(ci_conf, ci_conf + '.disabled')
+
+ def test_prepare_grub_dir_no_ci_cfg(self):
+ grub_conf = 'etc/default/grub.d/%s' % self.random_string()
+ target_grub_conf = os.path.join(self.target, grub_conf)
+ self.m_path.return_value = False
+ install_grub.prepare_grub_dir(self.target, grub_conf)
+ self.m_ensure_dir.assert_called_with(target_grub_conf)
+ self.assertEqual(0, self.m_move.call_count)
+
+
+class TestGetCarryoverParams(CiTestCase):
+
+ def setUp(self):
+ super(TestGetCarryoverParams, self).setUp()
+ self.add_patch('curtin.commands.install_grub.util.load_file',
+ 'm_load_file')
+ self.add_patch('curtin.commands.install_grub.distro.os_release',
+ 'm_os_release')
+ self.m_os_release.return_value = {'ID': 'ubuntu'}
+
+ def test_no_carry_params(self):
+ distroinfo = install_grub.distro.get_distroinfo()
+ cmdline = "root=ZFS=rpool/ROOT/ubuntu_bo2om9 ro quiet splash"
+ self.m_load_file.return_value = cmdline
+ self.assertEqual([], install_grub.get_carryover_params(distroinfo))
+
+ def test_legacy_seporator(self):
+ distroinfo = install_grub.distro.get_distroinfo()
+ sep = '--'
+ expected_carry_params = ['foo=bar', 'debug=1']
+ cmdline = "root=/dev/xvda1 ro quiet splash %s %s" % (
+ sep, " ".join(expected_carry_params))
+ self.m_load_file.return_value = cmdline
+ self.assertEqual(expected_carry_params,
+ install_grub.get_carryover_params(distroinfo))
+
+ def test_preferred_seporator(self):
+ distroinfo = install_grub.distro.get_distroinfo()
+ sep = '---'
+ expected_carry_params = ['foo=bar', 'debug=1']
+ cmdline = "root=/dev/xvda1 ro quiet splash %s %s" % (
+ sep, " ".join(expected_carry_params))
+ self.m_load_file.return_value = cmdline
+ self.assertEqual(expected_carry_params,
+ install_grub.get_carryover_params(distroinfo))
+
+ def test_drop_bootif_initrd_boot_image_from_extra(self):
+ distroinfo = install_grub.distro.get_distroinfo()
+ sep = '---'
+ expected_carry_params = ['foo=bar', 'debug=1']
+ filtered = ["BOOTIF=eth0", "initrd=initrd-2.3", "BOOT_IMAGE=/xv1"]
+ cmdline = "root=/dev/xvda1 ro quiet splash %s %s" % (
+ sep, " ".join(filtered + expected_carry_params))
+ self.m_load_file.return_value = cmdline
+ self.assertEqual(expected_carry_params,
+ install_grub.get_carryover_params(distroinfo))
+
+ def test_keep_console_always(self):
+ distroinfo = install_grub.distro.get_distroinfo()
+ sep = '---'
+ console = "console=ttyS1,115200"
+ cmdline = "root=/dev/xvda1 ro quiet splash %s %s" % (console, sep)
+ self.m_load_file.return_value = cmdline
+ self.assertEqual([console],
+ install_grub.get_carryover_params(distroinfo))
+
+ def test_keep_console_only_once(self):
+ distroinfo = install_grub.distro.get_distroinfo()
+ sep = '---'
+ console = "console=ttyS1,115200"
+ cmdline = "root=/dev/xvda1 ro quiet splash %s %s %s" % (
+ console, sep, console)
+ self.m_load_file.return_value = cmdline
+ self.assertEqual([console],
+ install_grub.get_carryover_params(distroinfo))
+
+ def test_always_set_rh_params(self):
+ self.m_os_release.return_value = {'ID': 'redhat'}
+ distroinfo = install_grub.distro.get_distroinfo()
+ cmdline = "root=ZFS=rpool/ROOT/ubuntu_bo2om9 ro quiet splash"
+ self.m_load_file.return_value = cmdline
+ self.assertEqual(['rd.auto=1'],
+ install_grub.get_carryover_params(distroinfo))
+
+
+class TestReplaceGrubCmdlineLinuxDefault(CiTestCase):
+
+ def setUp(self):
+ super(TestReplaceGrubCmdlineLinuxDefault, self).setUp()
+ self.target = self.tmp_dir()
+ self.grubconf = "grub"
+ self.target_grubconf = os.path.join(self.target, self.grubconf)
+
+ @mock.patch('curtin.commands.install_grub.util.write_file')
+ @mock.patch('curtin.commands.install_grub.util.load_file')
+ def test_append_line_if_not_found(self, m_load_file, m_write_file):
+ existing = [
+ "# If you change this file, run 'update-grub' after to update",
+ "# /boot/grub/grub.cfg",
+ ]
+ m_load_file.return_value = "\n".join(existing)
+ new_args = ["foo=bar", "wark=1"]
+ newline = 'GRUB_CMDLINE_LINUX_DEFAULT="%s"' % " ".join(new_args)
+ expected = newline + "\n"
+
+ install_grub.replace_grub_cmdline_linux_default(
+ self.target, self.grubconf, new_args)
+
+ m_write_file.assert_called_with(
+ self.target_grubconf, expected, omode="a+")
+
+ def test_append_line_if_not_found_verify_content(self):
+ existing = [
+ "# If you change this file, run 'update-grub' after to update",
+ "# /boot/grub/grub.cfg",
+ ]
+ with open(self.target_grubconf, "w") as fh:
+ fh.write("\n".join(existing))
+
+ new_args = ["foo=bar", "wark=1"]
+ newline = 'GRUB_CMDLINE_LINUX_DEFAULT="%s"' % " ".join(new_args)
+ expected = "\n".join(existing) + newline + "\n"
+
+ install_grub.replace_grub_cmdline_linux_default(
+ self.target, self.grubconf, new_args)
+
+ with open(self.target_grubconf) as fh:
+ found = fh.read()
+ self.assertEqual(expected, found)
+
+ @mock.patch('curtin.commands.install_grub.os.path.exists')
+ @mock.patch('curtin.commands.install_grub.util.write_file')
+ @mock.patch('curtin.commands.install_grub.util.load_file')
+ def test_replace_line_when_found(self, m_load_file, m_write_file,
+ m_exists):
+ existing = [
+ "# Line1",
+ "# Line2",
+ 'GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"',
+ "# Line4",
+ "# Line5",
+ ]
+ m_exists.return_value = True
+ m_load_file.return_value = "\n".join(existing)
+ new_args = ["foo=bar", "wark=1"]
+ newline = 'GRUB_CMDLINE_LINUX_DEFAULT="%s"' % " ".join(new_args)
+ expected = ("\n".join(existing[0:2]) + "\n" +
+ newline + "\n" +
+ "\n".join(existing[3:]))
+
+ install_grub.replace_grub_cmdline_linux_default(
+ self.target, self.grubconf, new_args)
+
+ m_write_file.assert_called_with(
+ self.target_grubconf, expected, omode="w+")
+
+ def test_replace_line_when_found_verify_content(self):
+ existing = [
+ "# Line1",
+ "# Line2",
+ 'GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"',
+ "# Line4",
+ "# Line5",
+ ]
+ with open(self.target_grubconf, "w") as fh:
+ fh.write("\n".join(existing))
+
+ new_args = ["foo=bar", "wark=1"]
+ newline = 'GRUB_CMDLINE_LINUX_DEFAULT="%s"' % " ".join(new_args)
+ expected = ("\n".join(existing[0:2]) + "\n" +
+ newline + "\n" +
+ "\n".join(existing[3:]))
+
+ install_grub.replace_grub_cmdline_linux_default(
+ self.target, self.grubconf, new_args)
+
+ with open(self.target_grubconf) as fh:
+ found = fh.read()
+ self.assertEqual(expected, found)
+
+
+class TestWriteGrubConfig(CiTestCase):
+
+ def setUp(self):
+ super(TestWriteGrubConfig, self).setUp()
+ self.target = self.tmp_dir()
+ self.grubconf = "grub"
+ self.target_grubconf = os.path.join(self.target, self.grubconf)
+
+ def test_write_grub_config_defaults(self):
+ grubcfg = {}
+ new_params = ['foo=bar', 'wark=1']
+ expected = "\n".join([
+ 'GRUB_CMDLINE_LINUX_DEFAULT="foo=bar wark=1"',
+ ("# Curtin disable grub os prober that might find "
+ "other OS installs."),
+ 'GRUB_DISABLE_OS_PROBER="true"',
+ '# Curtin configured GRUB_TERMINAL value',
+ 'GRUB_TERMINAL="console"'])
+
+ install_grub.write_grub_config(
+ self.target, grubcfg, self.grubconf, new_params)
+
+ with open(self.target_grubconf) as fh:
+ found = fh.read()
+ self.assertEqual(expected, found)
+
+ def test_write_grub_config_no_replace(self):
+ grubcfg = {'replace_linux_default': False}
+ new_params = ['foo=bar', 'wark=1']
+ expected = "\n".join([
+ ("# Curtin disable grub os prober that might find "
+ "other OS installs."),
+ 'GRUB_DISABLE_OS_PROBER="true"',
+ '# Curtin configured GRUB_TERMINAL value',
+ 'GRUB_TERMINAL="console"'])
+
+ install_grub.write_grub_config(
+ self.target, grubcfg, self.grubconf, new_params)
+
+ with open(self.target_grubconf) as fh:
+ found = fh.read()
+ self.assertEqual(expected, found)
+
+ def test_write_grub_config_enable_probe(self):
+ grubcfg = {'probe_additional_os': True}
+ new_params = ['foo=bar', 'wark=1']
+ expected = "\n".join([
+ 'GRUB_CMDLINE_LINUX_DEFAULT="foo=bar wark=1"',
+ ("# Curtin disable grub os prober that might find "
+ "other OS installs."),
+ 'GRUB_DISABLE_OS_PROBER="false"',
+ '# Curtin configured GRUB_TERMINAL value',
+ 'GRUB_TERMINAL="console"'])
+
+ install_grub.write_grub_config(
+ self.target, grubcfg, self.grubconf, new_params)
+
+ with open(self.target_grubconf) as fh:
+ found = fh.read()
+ self.assertEqual(expected, found)
+
+ def test_write_grub_config_invalid_probe(self):
+ grubcfg = {'probe_additional_os': '3'}
+ new_params = ['foo=bar', 'wark=1']
+ with self.assertRaises(ValueError):
+ install_grub.write_grub_config(
+ self.target, grubcfg, self.grubconf, new_params)
+
+ def test_write_grub_config_specify_terminal(self):
+ grubcfg = {'terminal': 'serial'}
+ new_params = ['foo=bar', 'wark=1']
+ expected = "\n".join([
+ 'GRUB_CMDLINE_LINUX_DEFAULT="foo=bar wark=1"',
+ ("# Curtin disable grub os prober that might find "
+ "other OS installs."),
+ 'GRUB_DISABLE_OS_PROBER="true"',
+ '# Curtin configured GRUB_TERMINAL value',
+ 'GRUB_TERMINAL="serial"'])
+
+ install_grub.write_grub_config(
+ self.target, grubcfg, self.grubconf, new_params)
+
+ with open(self.target_grubconf) as fh:
+ found = fh.read()
+ self.assertEqual(expected, found)
+
+ def test_write_grub_config_terminal_unmodified(self):
+ grubcfg = {'terminal': 'unmodified'}
+ new_params = ['foo=bar', 'wark=1']
+ expected = "\n".join([
+ 'GRUB_CMDLINE_LINUX_DEFAULT="foo=bar wark=1"',
+ ("# Curtin disable grub os prober that might find "
+ "other OS installs."),
+ 'GRUB_DISABLE_OS_PROBER="true"', ''])
+
+ install_grub.write_grub_config(
+ self.target, grubcfg, self.grubconf, new_params)
+
+ with open(self.target_grubconf) as fh:
+ found = fh.read()
+ self.assertEqual(expected, found)
+
+ def test_write_grub_config_invalid_terminal(self):
+ grubcfg = {'terminal': ['color-tv']}
+ new_params = ['foo=bar', 'wark=1']
+ with self.assertRaises(ValueError):
+ install_grub.write_grub_config(
+ self.target, grubcfg, self.grubconf, new_params)
+
+
+class TestFindEfiLoader(CiTestCase):
+
+ def setUp(self):
+ super(TestFindEfiLoader, self).setUp()
+ self.target = self.tmp_dir()
+ self.efi_path = 'boot/efi/EFI'
+ self.target_efi_path = os.path.join(self.target, self.efi_path)
+ self.bootid = self.random_string()
+
+ def _possible_loaders(self):
+ return [
+ os.path.join(self.efi_path, self.bootid, 'shimx64.efi'),
+ os.path.join(self.efi_path, 'BOOT', 'BOOTX64.EFI'),
+ os.path.join(self.efi_path, self.bootid, 'grubx64.efi'),
+ ]
+
+ def test_return_none_with_no_loaders(self):
+ self.assertIsNone(
+ install_grub.find_efi_loader(self.target, self.bootid))
+
+ def test_prefer_shim_loader(self):
+ # touch loaders in target filesystem
+ loaders = self._possible_loaders()
+ for loader in loaders:
+ tloader = os.path.join(self.target, loader)
+ util.ensure_dir(os.path.dirname(tloader))
+ with open(tloader, 'w+') as fh:
+ fh.write('\n')
+
+ found = install_grub.find_efi_loader(self.target, self.bootid)
+ self.assertTrue(found.endswith(
+ os.path.join(self.efi_path, self.bootid, 'shimx64.efi')))
+
+ def test_prefer_existing_bootx_loader_with_no_shim(self):
+ # touch all loaders in target filesystem
+ loaders = self._possible_loaders()[1:]
+ for loader in loaders:
+ tloader = os.path.join(self.target, loader)
+ util.ensure_dir(os.path.dirname(tloader))
+ with open(tloader, 'w+') as fh:
+ fh.write('\n')
+
+ found = install_grub.find_efi_loader(self.target, self.bootid)
+ self.assertTrue(found.endswith(
+ os.path.join(self.efi_path, 'BOOT', 'BOOTX64.EFI')))
+
+ def test_prefer_existing_grub_loader_with_no_other_loader(self):
+ # touch all loaders in target filesystem
+ loaders = self._possible_loaders()[2:]
+ for loader in loaders:
+ tloader = os.path.join(self.target, loader)
+ util.ensure_dir(os.path.dirname(tloader))
+ with open(tloader, 'w+') as fh:
+ fh.write('\n')
+
+ found = install_grub.find_efi_loader(self.target, self.bootid)
+ print(found)
+ self.assertTrue(found.endswith(
+ os.path.join(self.efi_path, self.bootid, 'grubx64.efi')))
+
+
+class TestGetGrubInstallCommand(CiTestCase):
+
+ def setUp(self):
+ super(TestGetGrubInstallCommand, self).setUp()
+ self.add_patch('curtin.commands.install_grub.distro.os_release',
+ 'm_os_release')
+ self.add_patch('curtin.commands.install_grub.os.path.exists',
+ 'm_exists')
+ self.m_os_release.return_value = {'ID': 'ubuntu'}
+ self.m_exists.return_value = False
+ self.target = self.tmp_dir()
+
+ def test_grub_install_command_ubuntu_no_uefi(self):
+ uefi = False
+ distroinfo = install_grub.distro.get_distroinfo()
+ self.assertEqual(
+ 'grub-install',
+ install_grub.get_grub_install_command(uefi, distroinfo))
+
+ def test_grub_install_command_ubuntu_with_uefi(self):
+ self.m_exists.return_value = True
+ uefi = True
+ distroinfo = install_grub.distro.get_distroinfo()
+ self.assertEqual(
+ install_grub.GRUB_MULTI_INSTALL,
+ install_grub.get_grub_install_command(uefi, distroinfo))
+
+ def test_grub_install_command_ubuntu_with_uefi_no_multi(self):
+ uefi = True
+ distroinfo = install_grub.distro.get_distroinfo()
+ self.assertEqual(
+ 'grub-install',
+ install_grub.get_grub_install_command(uefi, distroinfo))
+
+ def test_grub_install_command_redhat_no_uefi(self):
+ uefi = False
+ self.m_os_release.return_value = {'ID': 'redhat'}
+ distroinfo = install_grub.distro.get_distroinfo()
+ self.assertEqual(
+ 'grub2-install',
+ install_grub.get_grub_install_command(uefi, distroinfo))
+
+
+class TestGetEfiDiskPart(CiTestCase):
+
+ def setUp(self):
+ super(TestGetEfiDiskPart, self).setUp()
+ self.add_patch(
+ 'curtin.commands.install_grub.block.get_blockdev_for_partition',
+ 'm_blkpart')
+
+ def test_returns_first_result_with_partition(self):
+ self.m_blkpart.side_effect = iter([
+ ('/dev/disk-a', None),
+ ('/dev/disk-b', '1'),
+ ('/dev/disk-c', None),
+ ])
+ devices = ['/dev/disk-a', '/dev/disk-b', '/dev/disc-c']
+ self.assertEqual(('/dev/disk-b', '1'),
+ install_grub.get_efi_disk_part(devices))
+
+ def test_returns_none_tuple_if_no_partitions(self):
+ self.m_blkpart.side_effect = iter([
+ ('/dev/disk-a', None),
+ ('/dev/disk-b', None),
+ ('/dev/disk-c', None),
+ ])
+ devices = ['/dev/disk-a', '/dev/disk-b', '/dev/disc-c']
+ self.assertEqual((None, None),
+ install_grub.get_efi_disk_part(devices))
+
+
+class TestGenUefiInstallCommands(CiTestCase):
+
+ def setUp(self):
+ super(TestGenUefiInstallCommands, self).setUp()
+ self.add_patch(
+ 'curtin.commands.install_grub.get_efi_disk_part',
+ 'm_get_disk_part')
+ self.add_patch('curtin.commands.install_grub.distro.os_release',
+ 'm_os_release')
+ self.m_os_release.return_value = {'ID': 'ubuntu'}
+ self.target = self.tmp_dir()
+
+ def test_unsupported_distro_family_raises_valueerror(self):
+ self.m_os_release.return_value = {'ID': 'arch'}
+ distroinfo = install_grub.distro.get_distroinfo()
+ grub_name = 'grub-efi-amd64'
+ grub_target = 'x86_64-efi'
+ grub_cmd = 'grub-install'
+ update_nvram = True
+ devices = ['/dev/disk-a-part1']
+ disk = '/dev/disk-a'
+ part = '1'
+ self.m_get_disk_part.return_value = (disk, part)
+
+ with self.assertRaises(ValueError):
+ install_grub.gen_uefi_install_commands(
+ grub_name, grub_target, grub_cmd, update_nvram, distroinfo,
+ devices, self.target)
+
+ def test_ubuntu_install(self):
+ distroinfo = install_grub.distro.get_distroinfo()
+ grub_name = 'grub-efi-amd64'
+ grub_target = 'x86_64-efi'
+ grub_cmd = 'grub-install'
+ update_nvram = True
+ devices = ['/dev/disk-a-part1']
+ disk = '/dev/disk-a'
+ part = '1'
+ self.m_get_disk_part.return_value = (disk, part)
+
+ expected_install = [
+ ['efibootmgr', '-v'],
+ ['dpkg-reconfigure', grub_name],
+ ['update-grub'],
+ [grub_cmd, '--target=%s' % grub_target,
+ '--efi-directory=/boot/efi',
+ '--bootloader-id=%s' % distroinfo.variant, '--recheck'],
+ ]
+ expected_post = [['efibootmgr', '-v']]
+ self.assertEqual(
+ (expected_install, expected_post),
+ install_grub.gen_uefi_install_commands(
+ grub_name, grub_target, grub_cmd, update_nvram,
+ distroinfo, devices, self.target))
+
+ def test_ubuntu_install_multiple_esp(self):
+ distroinfo = install_grub.distro.get_distroinfo()
+ grub_name = 'grub-efi-amd64'
+ grub_cmd = install_grub.GRUB_MULTI_INSTALL
+ grub_target = 'x86_64-efi'
+ update_nvram = True
+ devices = ['/dev/disk-a-part1']
+ disk = '/dev/disk-a'
+ part = '1'
+ self.m_get_disk_part.return_value = (disk, part)
+
+ expected_install = [
+ ['efibootmgr', '-v'],
+ ['dpkg-reconfigure', grub_name],
+ ['update-grub'],
+ [install_grub.GRUB_MULTI_INSTALL],
+ ]
+ expected_post = [['efibootmgr', '-v']]
+ self.assertEqual(
+ (expected_install, expected_post),
+ install_grub.gen_uefi_install_commands(
+ grub_name, grub_target, grub_cmd, update_nvram, distroinfo,
+ devices, self.target))
+
+ def test_redhat_install(self):
+ self.m_os_release.return_value = {'ID': 'redhat'}
+ distroinfo = install_grub.distro.get_distroinfo()
+ grub_name = 'grub2-efi-x64'
+ grub_target = 'x86_64-efi'
+ grub_cmd = 'grub2-install'
+ update_nvram = True
+ devices = ['/dev/disk-a-part1']
+ disk = '/dev/disk-a'
+ part = '1'
+ self.m_get_disk_part.return_value = (disk, part)
+
+ expected_install = [
+ ['efibootmgr', '-v'],
+ [grub_cmd, '--target=%s' % grub_target,
+ '--efi-directory=/boot/efi',
+ '--bootloader-id=%s' % distroinfo.variant, '--recheck'],
+ ]
+ expected_post = [
+ ['grub2-mkconfig', '-o', '/boot/grub2/grub.cfg'],
+ ['efibootmgr', '-v']
+ ]
+ self.assertEqual(
+ (expected_install, expected_post),
+ install_grub.gen_uefi_install_commands(
+ grub_name, grub_target, grub_cmd, update_nvram, distroinfo,
+ devices, self.target))
+
+ def test_redhat_install_existing(self):
+ # simulate existing bootloaders already installed in target system
+ # by touching the files grub would have installed, including shim
+ def _enable_loaders(bootid):
+ efi_path = 'boot/efi/EFI'
+ target_efi_path = os.path.join(self.target, efi_path)
+ loaders = [
+ os.path.join(target_efi_path, bootid, 'shimx64.efi'),
+ os.path.join(target_efi_path, 'BOOT', 'BOOTX64.EFI'),
+ os.path.join(target_efi_path, bootid, 'grubx64.efi'),
+ ]
+ for loader in loaders:
+ util.ensure_dir(os.path.dirname(loader))
+ with open(loader, 'w+') as fh:
+ fh.write('\n')
+
+ self.m_os_release.return_value = {'ID': 'redhat'}
+ distroinfo = install_grub.distro.get_distroinfo()
+ bootid = distroinfo.variant
+ _enable_loaders(bootid)
+ grub_name = 'grub2-efi-x64'
+ grub_target = 'x86_64-efi'
+ grub_cmd = 'grub2-install'
+ update_nvram = True
+ devices = ['/dev/disk-a-part1']
+ disk = '/dev/disk-a'
+ part = '1'
+ self.m_get_disk_part.return_value = (disk, part)
+
+ expected_loader = '/boot/efi/EFI/%s/shimx64.efi' % bootid
+ expected_install = [
+ ['efibootmgr', '-v'],
+ ['efibootmgr', '--create', '--write-signature',
+ '--label', bootid, '--disk', disk, '--part', part,
+ '--loader', expected_loader],
+ ]
+ expected_post = [
+ ['grub2-mkconfig', '-o', '/boot/efi/EFI/%s/grub.cfg' % bootid],
+ ['efibootmgr', '-v']
+ ]
+
+ self.assertEqual(
+ (expected_install, expected_post),
+ install_grub.gen_uefi_install_commands(
+ grub_name, grub_target, grub_cmd, update_nvram, distroinfo,
+ devices, self.target))
+
+
+class TestGenInstallCommands(CiTestCase):
+
+ def setUp(self):
+ super(TestGenInstallCommands, self).setUp()
+ self.add_patch('curtin.commands.install_grub.distro.os_release',
+ 'm_os_release')
+ self.m_os_release.return_value = {'ID': 'ubuntu'}
+
+ def test_unsupported_install(self):
+ self.m_os_release.return_value = {'ID': 'gentoo'}
+ distroinfo = install_grub.distro.get_distroinfo()
+ devices = ['/dev/disk-a-part1', '/dev/disk-b-part1']
+ rhel_ver = None
+ grub_name = 'grub-pc'
+ grub_cmd = 'grub-install'
+ with self.assertRaises(ValueError):
+ install_grub.gen_install_commands(
+ grub_name, grub_cmd, distroinfo, devices, rhel_ver)
+
+ def test_ubuntu_install(self):
+ distroinfo = install_grub.distro.get_distroinfo()
+ devices = ['/dev/disk-a-part1', '/dev/disk-b-part1']
+ rhel_ver = None
+ grub_name = 'grub-pc'
+ grub_cmd = 'grub-install'
+ expected_install = [
+ ['dpkg-reconfigure', grub_name],
+ ['update-grub']
+ ] + [[grub_cmd, dev] for dev in devices]
+ expected_post = []
+ self.assertEqual(
+ (expected_install, expected_post),
+ install_grub.gen_install_commands(
+ grub_name, grub_cmd, distroinfo, devices, rhel_ver))
+
+ def test_redhat_6_install_unsupported(self):
+ self.m_os_release.return_value = {'ID': 'redhat'}
+ distroinfo = install_grub.distro.get_distroinfo()
+ devices = ['/dev/disk-a-part1', '/dev/disk-b-part1']
+ rhel_ver = '6'
+ grub_name = 'grub-pc'
+ grub_cmd = 'grub-install'
+ with self.assertRaises(ValueError):
+ install_grub.gen_install_commands(
+ grub_name, grub_cmd, distroinfo, devices, rhel_ver)
+
+ def test_redhatp_7_or_8_install(self):
+ self.m_os_release.return_value = {'ID': 'redhat'}
+ distroinfo = install_grub.distro.get_distroinfo()
+ devices = ['/dev/disk-a-part1', '/dev/disk-b-part1']
+ rhel_ver = '7'
+ grub_name = 'grub-pc'
+ grub_cmd = 'grub2-install'
+ expected_install = [[grub_cmd, dev] for dev in devices]
+ expected_post = [
+ ['grub2-mkconfig', '-o', '/boot/grub2/grub.cfg']
+ ]
+ self.assertEqual(
+ (expected_install, expected_post),
+ install_grub.gen_install_commands(
+ grub_name, grub_cmd, distroinfo, devices, rhel_ver))
+
+
+@mock.patch.object(util.ChrootableTarget, "__enter__", new=lambda a: a)
+class TestInstallGrub(CiTestCase):
+
+ def setUp(self):
+ super(TestInstallGrub, self).setUp()
+ base = 'curtin.commands.install_grub.'
+ self.add_patch(base + 'distro.get_distroinfo',
+ 'm_distro_get_distroinfo')
+ self.add_patch(base + 'distro.get_architecture',
+ 'm_distro_get_architecture')
+ self.add_patch(base + 'distro.rpm_get_dist_id',
+ 'm_distro_rpm_get_dist_id')
+ self.add_patch(base + 'get_grub_package', 'm_get_grub_package')
+ self.add_patch(base + 'get_grub_config_file', 'm_get_grub_config_file')
+ self.add_patch(base + 'get_carryover_params', 'm_get_carryover_params')
+ self.add_patch(base + 'prepare_grub_dir', 'm_prepare_grub_dir')
+ self.add_patch(base + 'write_grub_config', 'm_write_grub_config')
+ self.add_patch(base + 'get_grub_install_command',
+ 'm_get_grub_install_command')
+ self.add_patch(base + 'gen_uefi_install_commands',
+ 'm_gen_uefi_install_commands')
+ self.add_patch(base + 'gen_install_commands', 'm_gen_install_commands')
+ self.add_patch(base + 'util.subp', 'm_subp')
+
+ self.distroinfo = distro.DistroInfo('myubuntu', 'mydebian')
+ self.m_distro_get_distroinfo.return_value = self.distroinfo
+ self.m_distro_rpm_get_dist_id.return_value = '7'
+ self.m_distro_get_architecture.return_value = 'amd64'
+ self.target = self.tmp_dir()
+
+ def test_grub_install_raise_exception_on_no_devices(self):
+ devices = []
+ with self.assertRaises(ValueError):
+ install_grub.install_grub(devices, self.target, False, {})
+
+ def test_grub_install_raise_exception_on_no_target(self):
+ devices = ['foobar']
+ with self.assertRaises(ValueError):
+ install_grub.install_grub(devices, None, False, {})
+
+ def test_grub_install_raise_exception_on_s390x(self):
+ self.m_distro_get_architecture.return_value = 's390x'
+ devices = ['foobar']
+ with self.assertRaises(RuntimeError):
+ install_grub.install_grub(devices, self.target, False, {})
+
+ def test_grub_install_ubuntu(self):
+ devices = ['/dev/disk-a-part1']
+ uefi = False
+ grubcfg = {}
+ grub_conf = self.tmp_path('grubconf')
+ new_params = []
+ self.m_get_grub_package.return_value = ('grub-pc', 'i386-pc')
+ self.m_get_grub_config_file.return_value = grub_conf
+ self.m_get_carryover_params.return_value = new_params
+ self.m_get_grub_install_command.return_value = 'grub-install'
+ self.m_gen_install_commands.return_value = (
+ [['/bin/true']], [['/bin/false']])
+
+ install_grub.install_grub(devices, self.target, uefi, grubcfg)
+
+ self.m_distro_get_distroinfo.assert_called_with(target=self.target)
+ self.m_distro_get_architecture.assert_called_with(target=self.target)
+ self.assertEqual(0, self.m_distro_rpm_get_dist_id.call_count)
+ self.m_get_grub_package.assert_called_with('amd64', None)
+ self.m_get_grub_config_file.assert_called_with(self.distroinfo)
+ self.m_get_carryover_params.assert_called_with(self.distroinfo)
+ self.m_prepare_grub_dir.assert_called_with(self.target, grub_conf)
+ self.m_write_grub_config.assert_called_with(self.target, grubcfg,
+ grub_conf, new_params)
+ self.m_get_grub_install_command.assert_called_with(
+ uefi, self.distroinfo)
+ self.m_gen_install_commands.assert_called_with(
+ 'grub-pc', 'grub-install', self.distroinfo, devices, None)
+
+ self.m_subp.assert_has_calls([
+ mock.call(['/bin/true'], capture=True),
+ mock.call(['/bin/false'], capture=True),
+ ])
+
+ def test_uefi_grub_install_ubuntu(self):
+ devices = ['/dev/disk-a-part1']
+ uefi = True
+ update_nvram = True
+ grubcfg = {'update_nvram': update_nvram}
+ grub_conf = self.tmp_path('grubconf')
+ new_params = []
+ grub_name = 'grub-efi-amd64'
+ grub_target = 'x86_64-efi'
+ grub_cmd = 'grub-install'
+ self.m_get_grub_package.return_value = (grub_name, grub_target)
+ self.m_get_grub_config_file.return_value = grub_conf
+ self.m_get_carryover_params.return_value = new_params
+ self.m_get_grub_install_command.return_value = grub_cmd
+ self.m_gen_uefi_install_commands.return_value = (
+ [['/bin/true']], [['/bin/false']])
+
+ install_grub.install_grub(devices, self.target, uefi, grubcfg)
+
+ self.m_distro_get_distroinfo.assert_called_with(target=self.target)
+ self.m_distro_get_architecture.assert_called_with(target=self.target)
+ self.assertEqual(0, self.m_distro_rpm_get_dist_id.call_count)
+ self.m_get_grub_package.assert_called_with('amd64', None)
+ self.m_get_grub_config_file.assert_called_with(self.distroinfo)
+ self.m_get_carryover_params.assert_called_with(self.distroinfo)
+ self.m_prepare_grub_dir.assert_called_with(self.target, grub_conf)
+ self.m_write_grub_config.assert_called_with(self.target, grubcfg,
+ grub_conf, new_params)
+ self.m_get_grub_install_command.assert_called_with(
+ uefi, self.distroinfo)
+ self.m_gen_uefi_install_commands.assert_called_with(
+ grub_name, grub_target, grub_cmd, update_nvram, self.distroinfo,
+ devices, self.target)
+
+ self.m_subp.assert_has_calls([
+ mock.call(['/bin/true'], capture=True),
+ mock.call(['/bin/false'], capture=True),
+ ])
+
+ def test_uefi_grub_install_ubuntu_multiple_esp(self):
+ devices = ['/dev/disk-a-part1']
+ uefi = True
+ update_nvram = True
+ grubcfg = {'update_nvram': update_nvram}
+ grub_conf = self.tmp_path('grubconf')
+ new_params = []
+ grub_name = 'grub-efi-amd64'
+ grub_target = 'x86_64-efi'
+ grub_cmd = install_grub.GRUB_MULTI_INSTALL
+ self.m_get_grub_package.return_value = (grub_name, grub_target)
+ self.m_get_grub_config_file.return_value = grub_conf
+ self.m_get_carryover_params.return_value = new_params
+ self.m_get_grub_install_command.return_value = grub_cmd
+ self.m_gen_uefi_install_commands.return_value = (
+ [['/bin/true']], [['/bin/false']])
+
+ install_grub.install_grub(devices, self.target, uefi, grubcfg)
+
+ self.m_distro_get_distroinfo.assert_called_with(target=self.target)
+ self.m_distro_get_architecture.assert_called_with(target=self.target)
+ self.assertEqual(0, self.m_distro_rpm_get_dist_id.call_count)
+ self.m_get_grub_package.assert_called_with('amd64', None)
+ self.m_get_grub_config_file.assert_called_with(self.distroinfo)
+ self.m_get_carryover_params.assert_called_with(self.distroinfo)
+ self.m_prepare_grub_dir.assert_called_with(self.target, grub_conf)
+ self.m_write_grub_config.assert_called_with(self.target, grubcfg,
+ grub_conf, new_params)
+ self.m_get_grub_install_command.assert_called_with(
+ uefi, self.distroinfo)
+ self.m_gen_uefi_install_commands.assert_called_with(
+ grub_name, grub_target, grub_cmd, update_nvram, self.distroinfo,
+ devices, self.target)
+
+ self.m_subp.assert_has_calls([
+ mock.call(['/bin/true'], capture=True),
+ mock.call(['/bin/false'], capture=True),
+ ])
+
+
+# vi: ts=4 expandtab syntax=python
diff --git a/tests/unittests/test_curthooks.py b/tests/unittests/test_curthooks.py
index c126f3a..2349456 100644
--- a/tests/unittests/test_curthooks.py
+++ b/tests/unittests/test_curthooks.py
@@ -1,7 +1,7 @@
# This file is part of curtin. See LICENSE file for copyright and license info.
import os
-from mock import call, patch, MagicMock
+from mock import call, patch
import textwrap
from curtin.commands import curthooks
@@ -17,8 +17,10 @@ class TestGetFlashKernelPkgs(CiTestCase):
def setUp(self):
super(TestGetFlashKernelPkgs, self).setUp()
self.add_patch('curtin.util.subp', 'mock_subp')
- self.add_patch('curtin.util.get_architecture', 'mock_get_architecture')
- self.add_patch('curtin.util.is_uefi_bootable', 'mock_is_uefi_bootable')
+ self.add_patch('curtin.distro.get_architecture',
+ 'mock_get_architecture')
+ self.add_patch('curtin.util.is_uefi_bootable',
+ 'mock_is_uefi_bootable')
def test__returns_none_when_uefi(self):
self.assertIsNone(curthooks.get_flash_kernel_pkgs(uefi=True))
@@ -307,7 +309,7 @@ class TestSetupKernelImgConf(CiTestCase):
def setUp(self):
super(TestSetupKernelImgConf, self).setUp()
self.add_patch('platform.machine', 'mock_machine')
- self.add_patch('curtin.util.get_architecture', 'mock_arch')
+ self.add_patch('curtin.distro.get_architecture', 'mock_arch')
self.add_patch('curtin.util.write_file', 'mock_write_file')
self.target = 'not-a-real-target'
self.add_patch('curtin.distro.lsb_release', 'mock_lsb_release')
@@ -377,7 +379,7 @@ class TestInstallMissingPkgs(CiTestCase):
def setUp(self):
super(TestInstallMissingPkgs, self).setUp()
self.add_patch('platform.machine', 'mock_machine')
- self.add_patch('curtin.util.get_architecture', 'mock_arch')
+ self.add_patch('curtin.distro.get_architecture', 'mock_arch')
self.add_patch('curtin.distro.get_installed_packages',
'mock_get_installed_packages')
self.add_patch('curtin.util.load_command_environment',
@@ -536,41 +538,27 @@ class TestSetupGrub(CiTestCase):
self.target = self.tmp_dir()
self.distro_family = distro.DISTROS.debian
self.add_patch('curtin.distro.lsb_release', 'mock_lsb_release')
- self.mock_lsb_release.return_value = {
- 'codename': 'xenial',
- }
+ self.mock_lsb_release.return_value = {'codename': 'xenial'}
self.add_patch('curtin.util.is_uefi_bootable',
'mock_is_uefi_bootable')
self.mock_is_uefi_bootable.return_value = False
- self.add_patch('curtin.util.subp', 'mock_subp')
- self.subp_output = []
- self.mock_subp.side_effect = iter(self.subp_output)
self.add_patch('curtin.commands.block_meta.devsync', 'mock_devsync')
- self.add_patch('curtin.util.get_architecture', 'mock_arch')
- self.mock_arch.return_value = 'amd64'
- self.add_patch(
- 'curtin.util.ChrootableTarget', 'mock_chroot', autospec=False)
- self.mock_in_chroot = MagicMock()
- self.mock_in_chroot.__enter__.return_value = self.mock_in_chroot
- self.in_chroot_subp_output = []
- self.mock_in_chroot_subp = self.mock_in_chroot.subp
- self.mock_in_chroot_subp.side_effect = iter(self.in_chroot_subp_output)
- self.mock_chroot.return_value = self.mock_in_chroot
+ self.add_patch('curtin.util.subp', 'mock_subp')
+ self.add_patch('curtin.commands.curthooks.install_grub',
+ 'm_install_grub')
self.add_patch('curtin.commands.curthooks.configure_grub_debconf',
- 'm_grub_debconf')
+ 'm_configure_grub_debconf')
def test_uses_old_grub_install_devices_in_cfg(self):
cfg = {
'grub_install_devices': ['/dev/vdb']
}
- self.subp_output.append(('', ''))
+ updated_cfg = {
+ 'install_devices': ['/dev/vdb']
+ }
curthooks.setup_grub(cfg, self.target, osfamily=self.distro_family)
- self.assertEquals(
- ([
- 'sh', '-c', 'exec "$0" "$@" 2>&1',
- 'install-grub', '--os-family=%s' % self.distro_family,
- self.target, '/dev/vdb'],),
- self.mock_subp.call_args_list[0][0])
+ self.m_install_grub.assert_called_with(
+ ['/dev/vdb'], self.target, uefi=False, grubcfg=updated_cfg)
def test_uses_install_devices_in_grubcfg(self):
cfg = {
@@ -578,14 +566,9 @@ class TestSetupGrub(CiTestCase):
'install_devices': ['/dev/vdb'],
},
}
- self.subp_output.append(('', ''))
curthooks.setup_grub(cfg, self.target, osfamily=self.distro_family)
- self.assertEquals(
- ([
- 'sh', '-c', 'exec "$0" "$@" 2>&1',
- 'install-grub', '--os-family=%s' % self.distro_family,
- self.target, '/dev/vdb'],),
- self.mock_subp.call_args_list[0][0])
+ self.m_install_grub.assert_called_with(
+ ['/dev/vdb'], self.target, uefi=False, grubcfg=cfg.get('grub'))
@patch('curtin.commands.block_meta.multipath')
@patch('curtin.commands.curthooks.os.path.exists')
@@ -604,16 +587,11 @@ class TestSetupGrub(CiTestCase):
]
},
}
- self.subp_output.append(('', ''))
- self.subp_output.append(('', ''))
m_exists.return_value = True
curthooks.setup_grub(cfg, self.target, osfamily=self.distro_family)
- self.assertEquals(
- ([
- 'sh', '-c', 'exec "$0" "$@" 2>&1',
- 'install-grub', '--os-family=%s' % self.distro_family,
- self.target, '/dev/vdb'],),
- self.mock_subp.call_args_list[0][0])
+ self.m_install_grub.assert_called_with(
+ ['/dev/vdb'], self.target, uefi=False,
+ grubcfg={'install_devices': ['/dev/vdb']})
@patch('curtin.commands.block_meta.multipath')
@patch('curtin.block.is_valid_device')
@@ -658,17 +636,13 @@ class TestSetupGrub(CiTestCase):
'update_nvram': False,
},
}
- self.subp_output.append(('', ''))
m_exists.return_value = True
m_is_valid_device.side_effect = (False, True, False, True)
curthooks.setup_grub(cfg, self.target, osfamily=distro.DISTROS.redhat)
- self.assertEquals(
- ([
- 'sh', '-c', 'exec "$0" "$@" 2>&1',
- 'install-grub', '--uefi',
- '--os-family=%s' % distro.DISTROS.redhat, self.target,
- '/dev/vdb1'],),
- self.mock_subp.call_args_list[0][0])
+ self.m_install_grub.assert_called_with(
+ ['/dev/vdb1'], self.target, uefi=True,
+ grubcfg={'update_nvram': False, 'install_devices': ['/dev/vdb1']}
+ )
def test_grub_install_installs_to_none_if_install_devices_None(self):
cfg = {
@@ -676,15 +650,13 @@ class TestSetupGrub(CiTestCase):
'install_devices': None,
},
}
- self.subp_output.append(('', ''))
curthooks.setup_grub(cfg, self.target, osfamily=self.distro_family)
- self.assertEquals(
- ([
- 'sh', '-c', 'exec "$0" "$@" 2>&1',
- 'install-grub', '--os-family=%s' % self.distro_family,
- self.target, 'none'],),
- self.mock_subp.call_args_list[0][0])
+ self.m_install_grub.assert_called_with(
+ ['none'], self.target, uefi=False,
+ grubcfg={'install_devices': None}
+ )
+ @patch.object(util.ChrootableTarget, "__enter__", new=lambda a: a)
def test_grub_install_uefi_updates_nvram_skips_remove_and_reorder(self):
self.add_patch('curtin.distro.install_packages', 'mock_install')
self.add_patch('curtin.distro.has_pkg_available', 'mock_haspkg')
@@ -698,7 +670,6 @@ class TestSetupGrub(CiTestCase):
'reorder_uefi': False,
},
}
- self.subp_output.append(('', ''))
self.mock_haspkg.return_value = False
self.mock_efibootmgr.return_value = {
'current': '0000',
@@ -711,14 +682,11 @@ class TestSetupGrub(CiTestCase):
}
}
curthooks.setup_grub(cfg, self.target, osfamily=self.distro_family)
- self.assertEquals(
- ([
- 'sh', '-c', 'exec "$0" "$@" 2>&1',
- 'install-grub', '--uefi', '--update-nvram',
- '--os-family=%s' % self.distro_family,
- self.target, '/dev/vdb'],),
- self.mock_subp.call_args_list[0][0])
+ self.m_install_grub.assert_called_with(
+ ['/dev/vdb'], self.target, uefi=True, grubcfg=cfg.get('grub')
+ )
+ @patch.object(util.ChrootableTarget, "__enter__", new=lambda a: a)
def test_grub_install_uefi_updates_nvram_removes_old_loaders(self):
self.add_patch('curtin.distro.install_packages', 'mock_install')
self.add_patch('curtin.distro.has_pkg_available', 'mock_haspkg')
@@ -732,7 +700,6 @@ class TestSetupGrub(CiTestCase):
'reorder_uefi': False,
},
}
- self.subp_output.append(('', ''))
self.mock_efibootmgr.return_value = {
'current': '0000',
'entries': {
@@ -753,22 +720,19 @@ class TestSetupGrub(CiTestCase):
},
}
}
- self.in_chroot_subp_output.append(('', ''))
- self.in_chroot_subp_output.append(('', ''))
self.mock_haspkg.return_value = False
curthooks.setup_grub(cfg, self.target, osfamily=self.distro_family)
- self.assertEquals(
- ['efibootmgr', '-B', '-b'],
- self.mock_in_chroot_subp.call_args_list[0][0][0][:3])
- self.assertEquals(
- ['efibootmgr', '-B', '-b'],
- self.mock_in_chroot_subp.call_args_list[1][0][0][:3])
- self.assertEquals(
- set(['0001', '0002']),
- set([
- self.mock_in_chroot_subp.call_args_list[0][0][0][3],
- self.mock_in_chroot_subp.call_args_list[1][0][0][3]]))
+ expected_calls = [
+ call(['efibootmgr', '-B', '-b', '0001'],
+ capture=True, target=self.target),
+ call(['efibootmgr', '-B', '-b', '0002'],
+ capture=True, target=self.target),
+ ]
+ self.assertEqual(sorted(expected_calls),
+ sorted(self.mock_subp.call_args_list))
+
+ @patch.object(util.ChrootableTarget, "__enter__", new=lambda a: a)
def test_grub_install_uefi_updates_nvram_reorders_loaders(self):
self.add_patch('curtin.distro.install_packages', 'mock_install')
self.add_patch('curtin.distro.has_pkg_available', 'mock_haspkg')
@@ -782,7 +746,6 @@ class TestSetupGrub(CiTestCase):
'reorder_uefi': True,
},
}
- self.subp_output.append(('', ''))
self.mock_efibootmgr.return_value = {
'current': '0001',
'order': ['0000', '0001'],
@@ -798,12 +761,11 @@ class TestSetupGrub(CiTestCase):
},
}
}
- self.in_chroot_subp_output.append(('', ''))
self.mock_haspkg.return_value = False
curthooks.setup_grub(cfg, self.target, osfamily=self.distro_family)
- self.assertEquals(
- (['efibootmgr', '-o', '0001,0000'],),
- self.mock_in_chroot_subp.call_args_list[0][0])
+ self.assertEquals([
+ call(['efibootmgr', '-o', '0001,0000'], target=self.target)],
+ self.mock_subp.call_args_list)
class TestUefiRemoveDuplicateEntries(CiTestCase):
@@ -853,8 +815,8 @@ class TestUefiRemoveDuplicateEntries(CiTestCase):
call(['efibootmgr', '--bootnum=0001', '--delete-bootnum'],
target=self.target),
call(['efibootmgr', '--bootnum=0003', '--delete-bootnum'],
- target=self.target)],
- self.m_subp.call_args_list)
+ target=self.target)
+ ], self.m_subp.call_args_list)
@patch.object(util.ChrootableTarget, "__enter__", new=lambda a: a)
def test_uefi_remove_duplicate_entries_no_change(self):
Follow ups
-
[Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-20
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-20
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-20
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Ryan Harper, 2020-05-20
-
[Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Ryan Harper, 2020-05-20
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-20
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Chad Smith, 2020-05-20
-
[Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Chad Smith, 2020-05-20
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-20
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-20
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-20
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-20
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-20
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-20
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-20
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-19
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-19
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Ryan Harper, 2020-05-19
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-19
-
[Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Chad Smith, 2020-05-19
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Chad Smith, 2020-05-19
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-18
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Ryan Harper, 2020-05-18
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-18
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Chad Smith, 2020-05-09
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-05-06
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Ryan Harper, 2020-05-06
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Ryan Harper, 2020-05-05
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Chad Smith, 2020-05-04
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-04-27
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-04-27
-
Re: [Merge] ~raharper/curtin:fix/replace-grub-shell-helper into curtin:master
From: Server Team CI bot, 2020-04-24