# 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