diff --git a/anaconda-Allow-to-detect-devices-with-the-iso9660-file-system.patch b/anaconda-Allow-to-detect-devices-with-the-iso9660-file-system.patch new file mode 100644 index 0000000..146cd2b --- /dev/null +++ b/anaconda-Allow-to-detect-devices-with-the-iso9660-file-system.patch @@ -0,0 +1,127 @@ +From 4e699fe30da24771b80ff1fe64d7791bcb444f79 Mon Sep 17 00:00:00 2001 +From: Vendula Poncova +Date: Tue, 21 Jul 2020 10:57:00 +0200 +Subject: [PATCH] Allow to detect devices with the iso9660 file system as + optical media + +Test that the DBus method FindOpticalMedia identifies devices with the iso9660 file +system as optical media, so it is able to find NVDIMM devices with iso9660. + +The DBus method GetDevicesToIgnore of the NVDIMM module shouldn't return NVDIMM +devices with the iso9660 file system. They can be used as an installation source. + +Protect all devices with the iso9660 file system. It will protect, for example, NVDIMM +devices with the iso9660 file system that can be used only as an installation source +anyway. + +Related: rhbz#1856264 +--- + .../modules/storage/devicetree/model.py | 5 ++++ + pyanaconda/modules/storage/nvdimm/nvdimm.py | 12 ++++++++- + .../module_device_tree_test.py | 27 ++++++++++++++++--- + 3 files changed, 39 insertions(+), 5 deletions(-) + +diff --git a/pyanaconda/modules/storage/devicetree/model.py b/pyanaconda/modules/storage/devicetree/model.py +index 4d0ecdb..cdee5a8 100644 +--- a/pyanaconda/modules/storage/devicetree/model.py ++++ b/pyanaconda/modules/storage/devicetree/model.py +@@ -303,6 +303,11 @@ class InstallerStorage(Blivet): + # cdroms, involves unmounting which is undesirable (see bug #1671713). + protected.extend(dev for dev in self.devicetree.devices if dev.type == "cdrom") + ++ # Protect also all devices with an iso9660 file system. It will protect ++ # NVDIMM devices that can be used only as an installation source anyway ++ # (see the bug #1856264). ++ protected.extend(dev for dev in self.devicetree.devices if dev.format.type == "iso9660") ++ + # Mark the collected devices as protected. + for dev in protected: + log.debug("Marking device %s as protected.", dev.name) +diff --git a/pyanaconda/modules/storage/nvdimm/nvdimm.py b/pyanaconda/modules/storage/nvdimm/nvdimm.py +index 0bbcc6e..4476dd1 100644 +--- a/pyanaconda/modules/storage/nvdimm/nvdimm.py ++++ b/pyanaconda/modules/storage/nvdimm/nvdimm.py +@@ -21,6 +21,7 @@ import gi + gi.require_version("BlockDev", "2.0") + from gi.repository import BlockDev as blockdev + ++from blivet import udev + from blivet.static_data import nvdimm + + from pykickstart.constants import NVDIMM_ACTION_RECONFIGURE, NVDIMM_ACTION_USE +@@ -90,6 +91,9 @@ class NVDIMMModule(KickstartBaseModule): + installation, the device(s) must be specified by nvdimm kickstart + command. Also, only devices in sector mode are allowed. + ++ Don't ignore devices that have an iso9660 file system. We might ++ want to use them as an installation source. ++ + :return: a set of device names + """ + namespaces_to_use = self.get_namespaces_to_use() +@@ -97,7 +101,13 @@ class NVDIMMModule(KickstartBaseModule): + devices_to_ignore = set() + + for ns_name, ns_info in nvdimm.namespaces.items(): +- if ns_info.mode != blockdev.NVDIMMNamespaceMode.SECTOR: ++ info = udev.get_device(device_node="/dev/" + ns_info.blockdev) ++ ++ if info and udev.device_get_format(info) == "iso9660": ++ log.debug("%s / %s won't be ignored - NVDIMM device has " ++ "an iso9660 file system", ns_name, ns_info.blockdev) ++ continue ++ elif ns_info.mode != blockdev.NVDIMMNamespaceMode.SECTOR: + log.debug("%s / %s will be ignored - NVDIMM device is not " + "in sector mode", ns_name, ns_info.blockdev) + elif ns_name not in namespaces_to_use and ns_info.blockdev not in devices_to_use: +diff --git a/tests/nosetests/pyanaconda_tests/module_device_tree_test.py b/tests/nosetests/pyanaconda_tests/module_device_tree_test.py +index 838c70e..5e52843 100644 +--- a/tests/nosetests/pyanaconda_tests/module_device_tree_test.py ++++ b/tests/nosetests/pyanaconda_tests/module_device_tree_test.py +@@ -24,10 +24,10 @@ from unittest.mock import patch, Mock, PropertyMock + from tests.nosetests.pyanaconda_tests import patch_dbus_publish_object, check_task_creation + + from blivet.devices import StorageDevice, DiskDevice, DASDDevice, ZFCPDiskDevice, PartitionDevice, \ +- LUKSDevice, iScsiDiskDevice, NVDIMMNamespaceDevice, FcoeDiskDevice ++ LUKSDevice, iScsiDiskDevice, NVDIMMNamespaceDevice, FcoeDiskDevice, OpticalDevice + from blivet.errors import StorageError, FSError + from blivet.formats import get_format +-from blivet.formats.fs import FS ++from blivet.formats.fs import FS, Iso9660FS + from blivet.formats.luks import LUKS + from blivet.size import Size + +@@ -627,9 +627,28 @@ class DeviceTreeInterfaceTestCase(unittest.TestCase): + str(cm.exception), "Failed to unmount dev1 from /path: Fake error." + ) + +- def find_install_media_test(self): ++ @patch.object(Iso9660FS, "check_module") ++ def find_install_media_test(self, check_module): + """Test FindInstallMedia.""" +- self.assertEqual(self.interface.FindOpticalMedia(), []) ++ dev1 = OpticalDevice("dev1") ++ dev1.size = Size("2 GiB") ++ dev1.format = get_format("iso9660") ++ dev1.controllable = True ++ self._add_device(dev1) ++ ++ dev2 = StorageDevice("dev2") ++ dev2.size = Size("2 GiB") ++ dev2.format = get_format("iso9660") ++ dev2.controllable = True ++ self._add_device(dev2) ++ ++ dev3 = StorageDevice("dev3") ++ dev3.size = Size("2 GiB") ++ dev3.format = get_format("ext4") ++ dev3.controllable = True ++ self._add_device(dev3) ++ ++ self.assertEqual(self.interface.FindOpticalMedia(), ["dev1", "dev2"]) + + @patch.object(FS, "update_size_info") + def find_mountable_partitions_test(self, update_size_info): +-- +2.23.0 + diff --git a/anaconda-Fix-stage2-as-default-sources.patch b/anaconda-Fix-stage2-as-default-sources.patch new file mode 100644 index 0000000..405c8dd --- /dev/null +++ b/anaconda-Fix-stage2-as-default-sources.patch @@ -0,0 +1,642 @@ +From 5283a20d41050551b54d6d12960ac28e0e5e1648 Mon Sep 17 00:00:00 2001 +From: Jiri Konecny +Date: Tue, 21 Jul 2020 11:17:40 +0200 +Subject: [PATCH] Fix stage2 as default sources + +We should prioritize stage2 device as the default source. +This is especially needed for DVD ISO because it is booting +with inst.stage2 instead and we should use the DVD +as the source for the default CDROM. +The situation is even worse thanks to the fact that +DVD ISOs are using inst.stage2=hd:... + +Find stage2 device and test this device first during +the auto-discover feature of CDRom source. + +Resolves: rhbz#1856264 +--- + .../modules/payloads/source/cdrom/cdrom.py | 7 +- + .../payloads/source/cdrom/cdrom_interface.py | 7 +- + .../payloads/source/cdrom/initialization.py | 64 +++- + pyanaconda/modules/payloads/source/utils.py | 8 +- + .../modules/storage/devicetree/handler.py | 5 +- + .../storage/devicetree/handler_interface.py | 5 +- + pyanaconda/payload/utils.py | 2 +- + .../module_device_tree_test.py | 23 +- + .../module_source_cdrom_test.py | 286 ++++++++++++++++-- + 9 files changed, 362 insertions(+), 45 deletions(-) + +diff --git a/pyanaconda/modules/payloads/source/cdrom/cdrom.py b/pyanaconda/modules/payloads/source/cdrom/cdrom.py +index 93df362..bb751ae 100644 +--- a/pyanaconda/modules/payloads/source/cdrom/cdrom.py ++++ b/pyanaconda/modules/payloads/source/cdrom/cdrom.py +@@ -32,7 +32,12 @@ log = get_module_logger(__name__) + + + class CdromSourceModule(PayloadSourceBase, MountingSourceMixin, RPMSourceMixin): +- """The CD-ROM source payload module.""" ++ """The CD-ROM source payload module. ++ ++ This source will try to automatically detect installation source. First it tries to look only ++ stage2 device used to boot the environment then it will use first valid iso9660 media with a ++ valid structure. ++ """ + + def __init__(self): + super().__init__() +diff --git a/pyanaconda/modules/payloads/source/cdrom/cdrom_interface.py b/pyanaconda/modules/payloads/source/cdrom/cdrom_interface.py +index 0c5b6d7..74d2f14 100644 +--- a/pyanaconda/modules/payloads/source/cdrom/cdrom_interface.py ++++ b/pyanaconda/modules/payloads/source/cdrom/cdrom_interface.py +@@ -25,7 +25,12 @@ from pyanaconda.modules.payloads.source.source_base_interface import PayloadSour + + @dbus_interface(PAYLOAD_SOURCE_CDROM.interface_name) + class CdromSourceInterface(PayloadSourceBaseInterface): +- """Interface for the payload CD-ROM image source.""" ++ """Interface for the payload CD-ROM image source. ++ ++ This source will try to automatically detect installation source. First it tries to look only ++ stage2 device used to boot the environment then it will use first valid iso9660 media with a ++ valid structure. ++ """ + + def connect_signals(self): + super().connect_signals() +diff --git a/pyanaconda/modules/payloads/source/cdrom/initialization.py b/pyanaconda/modules/payloads/source/cdrom/initialization.py +index a182fcd..7fc38fc 100644 +--- a/pyanaconda/modules/payloads/source/cdrom/initialization.py ++++ b/pyanaconda/modules/payloads/source/cdrom/initialization.py +@@ -15,13 +15,15 @@ + # License and may only be used or replicated with the express permission of + # Red Hat, Inc. + # ++from pyanaconda.core.kernel import kernel_arguments + from pyanaconda.modules.common.constants.objects import DEVICE_TREE + from pyanaconda.modules.common.constants.services import STORAGE + from pyanaconda.modules.common.errors.payload import SourceSetupError +-from pyanaconda.modules.payloads.source.mount_tasks import SetUpMountTask + from pyanaconda.modules.common.structures.storage import DeviceData +-from pyanaconda.payload.utils import mount, unmount, PayloadSetupError ++from pyanaconda.modules.payloads.source.mount_tasks import SetUpMountTask + from pyanaconda.modules.payloads.source.utils import is_valid_install_disk ++from pyanaconda.payload.source.factory import SourceFactory, PayloadSourceTypeUnrecognized ++from pyanaconda.payload.utils import mount, unmount, PayloadSetupError + + from pyanaconda.anaconda_loggers import get_module_logger + log = get_module_logger(__name__) +@@ -37,13 +39,62 @@ class SetUpCdromSourceTask(SetUpMountTask): + return "Set up CD-ROM Installation Source" + + def _do_mount(self): +- """Run CD-ROM installation source setup.""" +- log.debug("Trying to detect CD-ROM automatically") ++ """Run CD-ROM installation source setup. + ++ Try to discover installation media and mount that. Device used for booting (inst.stage2) ++ has a priority. ++ """ ++ log.debug("Trying to detect CD-ROM automatically") + device_tree = STORAGE.get_proxy(DEVICE_TREE) ++ ++ device_candidates = self._get_device_candidate_list(device_tree) ++ device_name = self._choose_installation_device(device_tree, device_candidates) ++ ++ if not device_name: ++ raise SourceSetupError("Found no CD-ROM") ++ ++ return device_name ++ ++ def _get_device_candidate_list(self, device_tree): ++ stage2_device = self._probe_stage2_for_cdrom(device_tree) ++ device_candidates = device_tree.FindOpticalMedia() ++ ++ if stage2_device in device_candidates: ++ device_candidates = [stage2_device] + device_candidates ++ ++ return device_candidates ++ ++ @staticmethod ++ def _probe_stage2_for_cdrom(device_tree): ++ # TODO: This is temporary method which should be moved closer to the inst.repo logic ++ log.debug("Testing if inst.stage2 is a CDROM device") ++ stage2_string = kernel_arguments.get("stage2") ++ ++ if not stage2_string: ++ return None ++ ++ try: ++ source = SourceFactory.parse_repo_cmdline_string(stage2_string) ++ except PayloadSourceTypeUnrecognized: ++ log.warning("Unknown stage2 method: %s", stage2_string) ++ return None ++ ++ # We have HDD here because DVD ISO has inst.stage2=hd:LABEL=.... ++ # TODO: Let's return back support of inst.cdrom= which should work based on the ++ # documentation and use that as inst.stage2 parameter for Pungi ++ if not source.is_harddrive: ++ log.debug("Stage2 can't be used as source %s", stage2_string) ++ return None ++ ++ # We can ignore source.path here because DVD ISOs are not using that. ++ stage2_device = device_tree.ResolveDevice(source.partition) ++ log.debug("Found possible stage2 default installation source %s", stage2_device) ++ return stage2_device ++ ++ def _choose_installation_device(self, device_tree, devices_candidates): + device_name = "" + +- for dev_name in device_tree.FindOpticalMedia(): ++ for dev_name in devices_candidates: + try: + device_data = DeviceData.from_structure(device_tree.GetDeviceData(dev_name)) + mount(device_data.path, self._target_mount, "iso9660", "ro") +@@ -57,7 +108,4 @@ class SetUpCdromSourceTask(SetUpMountTask): + else: + unmount(self._target_mount) + +- if not device_name: +- raise SourceSetupError("Found no CD-ROM") +- + return device_name +diff --git a/pyanaconda/modules/payloads/source/utils.py b/pyanaconda/modules/payloads/source/utils.py +index b9642a9..5030fc5 100644 +--- a/pyanaconda/modules/payloads/source/utils.py ++++ b/pyanaconda/modules/payloads/source/utils.py +@@ -84,10 +84,10 @@ def find_and_mount_device(device_spec, mount_point): + device_path = "/dev/" + matches[0] + + try: +- # FIXME: Add back RO mounting. This was removed because we can't mount one source +- # RW and RO at the same time. This source is also mounted by IsoChooser dialog in the +- # SourceSpoke. +- mount(device_path, mount_point, "auto") ++ mount(device=device_path, ++ mountpoint=mount_point, ++ fstype="auto", ++ options="defaults,ro") + return True + except OSError as e: + log.error("Mount of device failed: %s", e) +diff --git a/pyanaconda/modules/storage/devicetree/handler.py b/pyanaconda/modules/storage/devicetree/handler.py +index 1fca6c0..453f27d 100644 +--- a/pyanaconda/modules/storage/devicetree/handler.py ++++ b/pyanaconda/modules/storage/devicetree/handler.py +@@ -82,16 +82,17 @@ class DeviceTreeHandler(ABC): + msg = "Failed to tear down {}: {}".format(device_name, str(e)) + raise DeviceSetupError(msg) from None + +- def mount_device(self, device_name, mount_point): ++ def mount_device(self, device_name, mount_point, options): + """Mount a filesystem on the device. + + :param device_name: a name of the device + :param mount_point: a path to the mount point ++ :param options: a string with mount options or an empty string to use defaults + :raise: MountFilesystemError if mount fails + """ + device = self._get_device(device_name) + try: +- device.format.mount(mountpoint=mount_point) ++ device.format.mount(mountpoint=mount_point, options=options or None) + except FSError as e: + msg = "Failed to mount {} at {}: {}". format( + device_name, +diff --git a/pyanaconda/modules/storage/devicetree/handler_interface.py b/pyanaconda/modules/storage/devicetree/handler_interface.py +index 3839e17..2a16eb7 100644 +--- a/pyanaconda/modules/storage/devicetree/handler_interface.py ++++ b/pyanaconda/modules/storage/devicetree/handler_interface.py +@@ -46,14 +46,15 @@ class DeviceTreeHandlerInterface(InterfaceTemplate): + """ + self.implementation.teardown_device(device_name) + +- def MountDevice(self, device_name: Str, mount_point: Str): ++ def MountDevice(self, device_name: Str, mount_point: Str, options: Str): + """Mount a filesystem on the device. + + :param device_name: a name of the device + :param mount_point: a path to the mount point ++ :param options: a string with mount options or an empty string to use defaults + :raise: MountFilesystemError if mount fails + """ +- self.implementation.mount_device(device_name, mount_point) ++ self.implementation.mount_device(device_name, mount_point, options) + + def UnmountDevice(self, device_name: Str, mount_point: Str): + """Unmount a filesystem on the device. +diff --git a/pyanaconda/payload/utils.py b/pyanaconda/payload/utils.py +index e0c7d6c..eb94f79 100644 +--- a/pyanaconda/payload/utils.py ++++ b/pyanaconda/payload/utils.py +@@ -71,7 +71,7 @@ def mount_device(device_name, mount_point): + :param str mount_point: a path to the mount point + """ + device_tree = STORAGE.get_proxy(DEVICE_TREE) +- device_tree.MountDevice(device_name, mount_point) ++ device_tree.MountDevice(device_name, mount_point, "ro") + + + def unmount_device(device_name, mount_point): +diff --git a/tests/nosetests/pyanaconda_tests/module_device_tree_test.py b/tests/nosetests/pyanaconda_tests/module_device_tree_test.py +index 33b06e8..838c70e 100644 +--- a/tests/nosetests/pyanaconda_tests/module_device_tree_test.py ++++ b/tests/nosetests/pyanaconda_tests/module_device_tree_test.py +@@ -582,12 +582,29 @@ class DeviceTreeInterfaceTestCase(unittest.TestCase): + self._add_device(StorageDevice("dev1", fmt=get_format("ext4"))) + + with tempfile.TemporaryDirectory() as d: +- self.interface.MountDevice("dev1", d) +- mount.assert_called_once_with(mountpoint=d) ++ self.interface.MountDevice("dev1", d, "") ++ mount.assert_called_once_with(mountpoint=d, options=None) + + mount.side_effect = FSError("Fake error.") + with self.assertRaises(MountFilesystemError) as cm: +- self.interface.MountDevice("dev1", "/path") ++ self.interface.MountDevice("dev1", "/path", "") ++ ++ self.assertEqual( ++ str(cm.exception), "Failed to mount dev1 at /path: Fake error." ++ ) ++ ++ @patch.object(FS, "mount") ++ def mount_device_with_options_test(self, mount): ++ """Test MountDevice with options specified.""" ++ self._add_device(StorageDevice("dev1", fmt=get_format("ext4"))) ++ ++ with tempfile.TemporaryDirectory() as d: ++ self.interface.MountDevice("dev1", d, "ro,auto") ++ mount.assert_called_once_with(mountpoint=d, options="ro,auto") ++ ++ mount.side_effect = FSError("Fake error.") ++ with self.assertRaises(MountFilesystemError) as cm: ++ self.interface.MountDevice("dev1", "/path", "ro,auto") + + self.assertEqual( + str(cm.exception), "Failed to mount dev1 at /path: Fake error." +diff --git a/tests/nosetests/pyanaconda_tests/module_source_cdrom_test.py b/tests/nosetests/pyanaconda_tests/module_source_cdrom_test.py +index 386322d..4c964a7 100644 +--- a/tests/nosetests/pyanaconda_tests/module_source_cdrom_test.py ++++ b/tests/nosetests/pyanaconda_tests/module_source_cdrom_test.py +@@ -124,6 +124,8 @@ class CdromSourceTestCase(unittest.TestCase): + + class CdromSourceSetupTaskTestCase(unittest.TestCase): + ++ # TODO: To avoid so much patching it would be great to split tests to parts and test those ++ + mount_location = "/mnt/put-cdrom-here" + + def setup_install_source_task_name_test(self): +@@ -156,8 +158,15 @@ class CdromSourceSetupTaskTestCase(unittest.TestCase): + device_tree.FindOpticalMedia = Mock() + device_tree.FindOpticalMedia.return_value = [dev.name for dev in devices] + ++ def _find_device_by_name(name): ++ for dev in devices: ++ if dev.name == name: ++ return DeviceData.to_structure(dev) ++ ++ return None ++ + device_tree.GetDeviceData = Mock() +- device_tree.GetDeviceData.side_effect = [DeviceData.to_structure(dev) for dev in devices] ++ device_tree.GetDeviceData.side_effect = _find_device_by_name + + return device_tree + +@@ -172,42 +181,261 @@ class CdromSourceSetupTaskTestCase(unittest.TestCase): + This matches the logic in tested method. + """ + for n in range(num_called): +- self.assertIn( +- call("test{}".format(n)), +- device_tree_mock.GetDeviceData.mock_calls +- ) +- self.assertIn( +- call("/dev/cdrom-test{}".format(n), self.mount_location, "iso9660", "ro"), +- mount_mock.mock_calls +- ) ++ self._check_if_device_was_tried(device_tree_mock, ++ mount_mock, ++ "test{}".format(n)) + + for n in range(num_called, num_called + num_untouched): +- self.assertNotIn( +- call("test{}".format(n)), +- device_tree_mock.GetDeviceData.mock_calls +- ) +- self.assertNotIn( +- call("/dev/cdrom-test{}".format(n), self.mount_location, "iso9660", "ro"), +- mount_mock.mock_calls +- ) ++ self._check_if_device_was_not_tried(device_tree_mock, ++ mount_mock, ++ "test{}".format(n)) + + self.assertEqual(device_tree_mock.GetDeviceData.call_count, num_called) + self.assertEqual(mount_mock.call_count, num_called) + ++ def _check_if_device_was_tried(self, ++ device_tree_mock, ++ mount_mock, ++ device_name): ++ self.assertIn( ++ call(device_name), ++ device_tree_mock.GetDeviceData.mock_calls ++ ) ++ ++ self.assertIn( ++ call("/dev/cdrom-{}".format(device_name), self.mount_location, "iso9660", "ro"), ++ mount_mock.mock_calls ++ ) ++ ++ def _check_if_device_was_not_tried(self, ++ device_tree_mock, ++ mount_mock, ++ device_name): ++ self.assertNotIn( ++ call(device_name), ++ device_tree_mock.GetDeviceData.mock_calls ++ ) ++ ++ self.assertNotIn( ++ call("/dev/cdrom-{}".format(device_name), self.mount_location, "iso9660", "ro"), ++ mount_mock.mock_calls ++ ) ++ ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.kernel_arguments") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.is_valid_install_disk") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.unmount") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.mount") ++ @patch_dbus_get_proxy ++ def priority_stage2_cdrom_test(self, ++ proxy_getter, ++ mount_mock, ++ unmount_mock, ++ valid_mock, ++ kernel_arguments_mock): ++ """Test CD-ROM Source setup installation source task run - prioritize inst.stage2 CD-ROMs. ++ ++ Add valid stage2 CDROM device and it has to be tested first. ++ """ ++ kernel_arguments_mock.get.return_value = "hd:LABEL=my-cool-dvd" ++ device_tree = self.set_up_device_tree(2) ++ device_tree.ResolveDevice.return_value = "test1" ++ proxy_getter.return_value = device_tree ++ valid_mock.return_value = True ++ ++ task = SetUpCdromSourceTask(self.mount_location) ++ result = task.run() ++ ++ # Only one device was checked ++ device_tree.ResolveDevice.assert_called_once_with("LABEL=my-cool-dvd") ++ ++ self._check_if_device_was_tried(device_tree, mount_mock, "test1") ++ self._check_if_device_was_not_tried(device_tree, mount_mock, "test0") ++ ++ # First device (stage2 device) is valid one ++ valid_mock.assert_called_once() ++ ++ # First device works so no unmount is called here ++ unmount_mock.assert_not_called() ++ ++ # Test device name returned ++ self.assertEqual(result, "test1") ++ ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.kernel_arguments") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.is_valid_install_disk") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.unmount") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.mount") ++ @patch_dbus_get_proxy ++ def priority_stage2_unrecognized_source_cdrom_test(self, ++ proxy_getter, ++ mount_mock, ++ unmount_mock, ++ valid_mock, ++ kernel_arguments_mock): ++ """Test CD-ROM Source setup installation source task run - unrecognized stage2 source. ++ ++ This should not happen but when we have the code there let's check it. ++ """ ++ kernel_arguments_mock.get.return_value = "wrong source!" ++ device_tree = self.set_up_device_tree(1) ++ proxy_getter.return_value = device_tree ++ valid_mock.return_value = True ++ ++ task = SetUpCdromSourceTask(self.mount_location) ++ result = task.run() ++ ++ device_tree.ResolveDevice.assert_not_called() ++ ++ # 1/2 devices tried, 1/2 untried ++ self.assert_resolve_and_mount_calls(device_tree, mount_mock, 1, 1) ++ ++ # Only first was mounted ++ self.assertEqual(valid_mock.call_count, 1) ++ ++ # First device was used no unmount should be called ++ unmount_mock.assert_not_called() ++ ++ # Test device name returned ++ self.assertEqual(result, "test0") ++ ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.kernel_arguments") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.is_valid_install_disk") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.unmount") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.mount") ++ @patch_dbus_get_proxy ++ def priority_stage2_not_hdd_source_cdrom_test(self, ++ proxy_getter, ++ mount_mock, ++ unmount_mock, ++ valid_mock, ++ kernel_arguments_mock): ++ """Test CD-ROM Source setup installation source task run - stage2 is not HDD source. ++ ++ We are testing HDD because DVD ISOs are created with inst.stage2=hd: . We want to change ++ this behavior on master so let's change this test too then. ++ ++ TODO: Change this test when DVD ISOs will use cdrom: instead of inst.stage2=hd:... ++ """ ++ kernel_arguments_mock.get.return_value = "nfs:test.org:/super/cool/path" ++ device_tree = self.set_up_device_tree(1) ++ proxy_getter.return_value = device_tree ++ valid_mock.return_value = True ++ ++ task = SetUpCdromSourceTask(self.mount_location) ++ result = task.run() ++ ++ device_tree.ResolveDevice.assert_not_called() ++ ++ # 1/2 devices tried, 1/2 untried ++ self.assert_resolve_and_mount_calls(device_tree, mount_mock, 1, 1) ++ ++ # Only first was mounted ++ self.assertEqual(valid_mock.call_count, 1) ++ ++ # First device was used no unmount should be called ++ unmount_mock.assert_not_called() ++ ++ # Test device name returned ++ self.assertEqual(result, "test0") ++ ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.kernel_arguments") + @patch("pyanaconda.modules.payloads.source.cdrom.initialization.is_valid_install_disk") + @patch("pyanaconda.modules.payloads.source.cdrom.initialization.unmount") + @patch("pyanaconda.modules.payloads.source.cdrom.initialization.mount") + @patch_dbus_get_proxy +- def choose_from_multiple_cdroms_test(self, proxy_getter, mount_mock, unmount_mock, valid_mock): ++ def priority_stage2_cant_be_resolved_source_cdrom_test(self, ++ proxy_getter, ++ mount_mock, ++ unmount_mock, ++ valid_mock, ++ kernel_arguments_mock): ++ """Test CD-ROM Source setup installation source task run - can't resolve stage2 device. ++ ++ Stage2 device can't be resolved. This should not happen but let's make sure the code works. ++ """ ++ kernel_arguments_mock.get.return_value = "hd:LABEL=my-cool-dvd" ++ device_tree = self.set_up_device_tree(1) ++ proxy_getter.return_value = device_tree ++ # When device can't be resolved it returns an empty string. ++ device_tree.ResolveDevice.return_value = "" ++ valid_mock.return_value = True ++ ++ task = SetUpCdromSourceTask(self.mount_location) ++ result = task.run() ++ ++ self._check_if_device_was_not_tried(device_tree, mount_mock, "") ++ ++ # 1/2 devices tried, 1/2 untried ++ self.assert_resolve_and_mount_calls(device_tree, mount_mock, 1, 1) ++ ++ # Only first was mounted ++ self.assertEqual(valid_mock.call_count, 1) ++ ++ # First device was used no unmount should be called ++ unmount_mock.assert_not_called() ++ ++ # Test device name returned ++ self.assertEqual(result, "test0") ++ ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.kernel_arguments") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.is_valid_install_disk") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.unmount") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.mount") ++ @patch_dbus_get_proxy ++ def priority_stage2_not_optical_media_cdrom_test(self, ++ proxy_getter, ++ mount_mock, ++ unmount_mock, ++ valid_mock, ++ kernel_arguments_mock): ++ """Test CD-ROM Source setup installation source task run - stage2 is not optical media. ++ ++ We should not pick stage2 device if it is not an optical_media which means type iso9660. ++ """ ++ kernel_arguments_mock.get.return_value = "hd:LABEL=correct-device" ++ device_tree = self.set_up_device_tree(1) ++ device_tree.ResolveDevice.return_value = "not-optical-media" ++ proxy_getter.return_value = device_tree ++ valid_mock.return_value = True ++ ++ task = SetUpCdromSourceTask(self.mount_location) ++ result = task.run() ++ ++ device_tree.ResolveDevice.assert_called_once_with("LABEL=correct-device") ++ ++ self._check_if_device_was_not_tried(device_tree, mount_mock, "correct-device") ++ ++ # 1/2 devices tried, 1/2 untried ++ self.assert_resolve_and_mount_calls(device_tree, mount_mock, 1, 1) ++ ++ # Only first was mounted ++ self.assertEqual(valid_mock.call_count, 1) ++ ++ # First device was used no unmount should be called ++ unmount_mock.assert_not_called() ++ ++ # Test device name returned ++ self.assertEqual(result, "test0") ++ ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.kernel_arguments") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.is_valid_install_disk") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.unmount") ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.mount") ++ @patch_dbus_get_proxy ++ def choose_from_multiple_cdroms_test(self, ++ proxy_getter, ++ mount_mock, ++ unmount_mock, ++ valid_mock, ++ kernel_arguments_mock): + """Test CD-ROM Source setup installation source task run - choice from multiple CD-ROMs. + + Fake four CD-ROM devices: First fails to mount, second has nothing useful, third has what + we want so is left mounted, fourth is entirely skipped. + The other two tests below are needed only to test the exit when nothing is found. + """ ++ kernel_arguments_mock.get.return_value = None + device_tree = self.set_up_device_tree(4) + proxy_getter.return_value = device_tree +- + mount_mock.side_effect = \ + [PayloadSetupError("Mocked failure"), DEFAULT, DEFAULT, DEFAULT] + +@@ -231,18 +459,24 @@ class CdromSourceSetupTaskTestCase(unittest.TestCase): + # Test device name returned + self.assertEqual(result, "test2") + ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.kernel_arguments") + @patch("pyanaconda.modules.payloads.source.cdrom.initialization.is_valid_install_disk") + @patch("pyanaconda.modules.payloads.source.cdrom.initialization.unmount") + @patch("pyanaconda.modules.payloads.source.cdrom.initialization.mount") + @patch_dbus_get_proxy +- def failure_to_mount_test(self, proxy_getter, mount_mock, unmount_mock, valid_mock): ++ def failure_to_mount_test(self, ++ proxy_getter, ++ mount_mock, ++ unmount_mock, ++ valid_mock, ++ kernel_arguments_mock): + """Test CD-ROM Source setup installation source task run - mount failure. + + Mocks one disk which fails to mount, expect exception. + """ ++ kernel_arguments_mock.get.return_value = None + device_tree = self.set_up_device_tree(1) + proxy_getter.return_value = device_tree +- + mount_mock.side_effect = PayloadSetupError("Mocked failure") + valid_mock.return_value = True + +@@ -258,18 +492,24 @@ class CdromSourceSetupTaskTestCase(unittest.TestCase): + # exception happened due to no disk + self.assertEqual(str(cm.exception), "Found no CD-ROM") + ++ @patch("pyanaconda.modules.payloads.source.cdrom.initialization.kernel_arguments") + @patch("pyanaconda.modules.payloads.source.cdrom.initialization.is_valid_install_disk") + @patch("pyanaconda.modules.payloads.source.cdrom.initialization.unmount") + @patch("pyanaconda.modules.payloads.source.cdrom.initialization.mount") + @patch_dbus_get_proxy +- def no_cdrom_with_valid_source_test(self, proxy_getter, mount_mock, unmount_mock, valid_mock): ++ def no_cdrom_with_valid_source_test(self, ++ proxy_getter, ++ mount_mock, ++ unmount_mock, ++ valid_mock, ++ kernel_arguments_mock): + """Test CD-ROM Source setup installation source task run - no valid source CD-ROMs. + + Mocks one CD-ROM device which has nothing useful, expect exception. + """ ++ kernel_arguments_mock.get.return_value = None + device_tree = self.set_up_device_tree(1) + proxy_getter.return_value = device_tree +- + valid_mock.return_value = False + + with self.assertRaises(SourceSetupError) as cm: +-- +2.23.0 + diff --git a/anaconda.spec b/anaconda.spec index d4ccdb5..24d83c8 100644 --- a/anaconda.spec +++ b/anaconda.spec @@ -1,7 +1,7 @@ %define _empty_manifest_terminate_build 0 Name: anaconda Version: 33.19 -Release: 2 +Release: 3 Summary: Graphical system installer License: GPLv2+ and MIT URL: http://fedoraproject.org/wiki/Anaconda @@ -29,6 +29,9 @@ Patch9015: modify-network-hostname-dot-illegal.patch Patch9016: disable-ssh-login-checkbox.patch Patch9017: bugfix-add-kdump-parameter-into-kernel-cmdline.patch +Patch6001: anaconda-Fix-stage2-as-default-sources.patch +Patch6002: anaconda-Allow-to-detect-devices-with-the-iso9660-file-system.patch + %define dbusver 1.2.3 %define dnfver 3.6.0 %define dracutver 034-7 @@ -239,6 +242,12 @@ update-desktop-database &> /dev/null || : %{_datadir}/gtk-doc %changelog +* Fri Aug 7 2020 fengtao - 33.19-3 +- Type:bugfix +- Id:NA +- SUG:NA +- DESC:fix stage2 as default sources + * Tue Jul 14 2020 zhangqiumiao - 33.19-2 - Type:bugfix - Id:NA