# This file is part of cloud-init. See LICENSE file for license information.
import pytest
from unittest import mock
from logging import Logger
from cloudinit.subp import ProcessExecutionError
from cloudinit.config.cc_grub_dpkg import fetch_idevs, handle
class TestFetchIdevs:
"""Tests cc_grub_dpkg.fetch_idevs()"""
# Note: udevadm info returns devices in a large single line string
@pytest.mark.parametrize(
"grub_output,path_exists,expected_log_call,udevadm_output"
",expected_idevs",
[
# Inside a container, grub not installed
(
ProcessExecutionError(reason=FileNotFoundError()),
False,
mock.call("'grub-probe' not found in $PATH"),
'',
'',
),
# Inside a container, grub installed
(
ProcessExecutionError(stderr="failed to get canonical path"),
False,
mock.call("grub-probe 'failed to get canonical path'"),
'',
'',
),
# KVM Instance
(
['/dev/vda'],
True,
None,
(
'/dev/disk/by-path/pci-0000:00:00.0 ',
'/dev/disk/by-path/virtio-pci-0000:00:00.0 '
),
'/dev/vda',
),
# Xen Instance
(
['/dev/xvda'],
True,
None,
'',
'/dev/xvda',
),
# NVMe Hardware Instance
(
['/dev/nvme1n1'],
True,
None,
(
'/dev/disk/by-id/nvme-Company_hash000 ',
'/dev/disk/by-id/nvme-nvme.000-000-000-000-000 ',
'/dev/disk/by-path/pci-0000:00:00.0-nvme-0 '
),
'/dev/disk/by-id/nvme-Company_hash000',
),
# SCSI Hardware Instance
(
['/dev/sda'],
True,
None,
(
'/dev/disk/by-id/company-user-1 ',
'/dev/disk/by-id/scsi-0Company_user-1 ',
'/dev/disk/by-path/pci-0000:00:00.0-scsi-0:0:0:0 '
),
'/dev/disk/by-id/company-user-1',
),
],
)
@mock.patch("cloudinit.config.cc_grub_dpkg.util.logexc")
@mock.patch("cloudinit.config.cc_grub_dpkg.os.path.exists")
@mock.patch("cloudinit.config.cc_grub_dpkg.subp.subp")
def test_fetch_idevs(self, m_subp, m_exists, m_logexc, grub_output,
path_exists, expected_log_call, udevadm_output,
expected_idevs):
"""Tests outputs from grub-probe and udevadm info against grub-dpkg"""
m_subp.side_effect = [
grub_output,
["".join(udevadm_output)]
]
m_exists.return_value = path_exists
log = mock.Mock(spec=Logger)
idevs = fetch_idevs(log)
assert expected_idevs == idevs
if expected_log_call is not None:
assert expected_log_call in log.debug.call_args_list
class TestHandle:
"""Tests cc_grub_dpkg.handle()"""
@pytest.mark.parametrize(
"cfg_idevs,cfg_idevs_empty,fetch_idevs_output,expected_log_output",
[
(
# No configuration
None,
None,
'/dev/disk/by-id/nvme-Company_hash000',
(
"Setting grub debconf-set-selections with ",
"'/dev/disk/by-id/nvme-Company_hash000','false'"
),
),
(
# idevs set, idevs_empty unset
'/dev/sda',
None,
'/dev/sda',
(
"Setting grub debconf-set-selections with ",
"'/dev/sda','false'"
),
),
(
# idevs unset, idevs_empty set
None,
'true',
'/dev/xvda',
(
"Setting grub debconf-set-selections with ",
"'/dev/xvda','true'"
),
),
(
# idevs set, idevs_empty set
'/dev/vda',
'false',
'/dev/disk/by-id/company-user-1',
(
"Setting grub debconf-set-selections with ",
"'/dev/vda','false'"
),
),
(
# idevs set, idevs_empty set
# Respect what the user defines, even if its logically wrong
'/dev/nvme0n1',
'true',
'',
(
"Setting grub debconf-set-selections with ",
"'/dev/nvme0n1','true'"
),
)
],
)
@mock.patch("cloudinit.config.cc_grub_dpkg.fetch_idevs")
@mock.patch("cloudinit.config.cc_grub_dpkg.util.get_cfg_option_str")
@mock.patch("cloudinit.config.cc_grub_dpkg.util.logexc")
@mock.patch("cloudinit.config.cc_grub_dpkg.subp.subp")
def test_handle(self, m_subp, m_logexc, m_get_cfg_str, m_fetch_idevs,
cfg_idevs, cfg_idevs_empty, fetch_idevs_output,
expected_log_output):
"""Test setting of correct debconf database entries"""
m_get_cfg_str.side_effect = [
cfg_idevs,
cfg_idevs_empty
]
m_fetch_idevs.return_value = fetch_idevs_output
log = mock.Mock(spec=Logger)
handle(mock.Mock(), mock.Mock(), mock.Mock(), log, mock.Mock())
log.debug.assert_called_with("".join(expected_log_output))
# vi: ts=4 expandtab