#!/usr/bin/python3## Copyright (C) 2025 Red Hat, Inc.# SPDX-License-Identifier: LGPL-2.1-or-laterfrom anacondalib import INSTALLER_VM_MEMORY_MB, VirtInstallMachineCase, disk_images, run_bootfrom installer import Installerfrom review import Reviewfrom storage import Storagefrom storagelib import StorageCase # pylint: disable=import-errorfrom testlib import test_main, timeout # pylint: disable=import-errorclass TestStorageCockpitIntegration_E2E(VirtInstallMachineCase, StorageCase):provision = {"machine1": {"memory_mb": INSTALLER_VM_MEMORY_MB}}def cockpitCreateBootloaderPartitions(self):self.click_dropdown(self.card_row("Storage", 1), "Create partition table")self.confirm()self.click_dropdown(self.card_row("Storage", 2), "Create partition")if self.is_efi:self.dialog({"size": 100, "type": "efi", "mount_point": "/boot/efi"})else:self.dialog({"size": 1, "type": "biosboot"})self.click_dropdown(self.card_row("Storage", 3), "Create partition")self.dialog({"size": 1070, "type": "ext4", "mount_point": "/boot"})@disk_images([('', 15), ('', 15), ('', 15)])@timeout(1200)def testRAIDonPartitions(self):"""Description:Test scenario with three disks:- ESP and '/boot' are on 'vda'.- A RAID 0 array is created using partitions on 'vdb1' and 'vdc1'.- The root filesystem ('/') is placed on the RAID 0 device.Expected results:- The installer can create a RAID0 array on partitions and use it for rootfs- The installed system storage layout is as expected"""b = self.browserm = self.machinei = Installer(b, m, scenario="use-configured-storage")s = Storage(b, m)r = Review(b, m)i.open()i.reach(i.steps.INSTALLATION_METHOD)s.select_disks([("vdb", True), ("vda", True), ("vdc", True)])s.enter_cockpit_storage()# Create ESP and /boot partitions on vdaself.cockpitCreateBootloaderPartitions()self.click_dropdown(self.card_row("Storage", 4), "Create partition")self.dialog({ "type": "empty"})# Create partitions for the RAID device on vdb and vdcself.click_dropdown(self.card_row("Storage", 5), "Create partition table")self.dialog({"type": "gpt"})self.click_dropdown(self.card_row("Storage", 6), "Create partition")self.dialog({"type": "empty"})self.click_dropdown(self.card_row("Storage", 7), "Create partition table")self.dialog({"type": "gpt"})self.click_dropdown(self.card_row("Storage", 8), "Create partition")self.dialog({"type": "empty"})# Create RAID1 on vdaself.click_dropdown(self.card_header("Storage"), "Create MDRAID device")self.dialog_wait_open()self.dialog_set_val("level", "raid0")self.dialog_set_val("disks", {"/dev/vda3": True, "/dev/vdb1": True, "/dev/vdc1": True})self.dialog_set_val("name", "SOMERAID")self.dialog_apply()self.dialog_wait_close()b.wait_visible(self.card_row("Storage", name="/dev/md/SOMERAID"))# Format and mount the RAID device partition as /self.click_dropdown(self.card_row("Storage", 9), "Format")self.dialog({"type": "ext4", "mount_point": "/"})# Exit the cockpit-storage iframe and return to installationb.switch_to_top()s.return_to_installation()s.return_to_installation_confirm()i.reach(i.steps.REVIEW)def checkStorageReview(prefix=""):with b.wait_timeout(30):for disk in ("vda", "vdb", "vdc"):r.check_disk(disk, f"16.1 GB {disk} (Virtio Block Device)")r.check_disk_row(disk, "/", "vda3, vdc1, vdb1, RAID", "47.1 GB", False, prefix=prefix)# verify review screencheckStorageReview()r.check_checkbox_not_present()self.install(needs_confirmation=False)# Check that the expected partition layout is created and spans all the target deviceslsblk = s.get_lsblk_json()block_devs = lsblk["blockdevices"]vda = next(dev for dev in block_devs if dev["name"] == "vda")vda3 = next(part for part in vda["children"] if part["name"] == "vda3")self.assertIn("raid0", [part["type"] for part in vda3["children"]])vdb = next(dev for dev in block_devs if dev["name"] == "vdb")vdb1 = next(part for part in vdb["children"] if part["name"] == "vdb1")self.assertIn("raid0", [part["type"] for part in vdb1["children"]])vdc = next(dev for dev in block_devs if dev["name"] == "vdc")vdc1 = next(part for part in vdc["children"] if part["name"] == "vdc1")self.assertIn("raid0", [part["type"] for part in vdc1["children"]])raid_root = next(part for part in vda3["children"] if part["type"] == "raid0")self.assertEqual(raid_root["mountpoints"], ["/"])self.assertEqual(raid_root["size"], "43.9G")@disk_images([("", 15), ("", 15), ("", 15)])@run_boot("bios", "efi")@timeout(1200)def testRAID0Scenario_0(self):"""Description:Test scenario with three disks:- ESP or BIOS boot and '/boot' are on 'vda'.- A RAID 0 array is created using 'vdb' and 'vdc'.- The root filesystem ('/') is placed on the RAID 0 device.Expected results:- The installer can create a RAID 0 array on disks and use it for rootfs.- The installed system storage layout is as expected."""b = self.browserm = self.machinei = Installer(b, m, scenario="use-configured-storage")s = Storage(b, m)r = Review(b, m)i.open()i.reach(i.steps.INSTALLATION_METHOD)s.select_disks([("vdb", True), ("vda", True), ("vdc", True)])s.enter_cockpit_storage()# Create RAID device on vdb, and vdcself.click_dropdown(self.card_header("Storage"), "Create MDRAID device")self.dialog_wait_open()self.dialog_set_val("level", "raid0")self.dialog_set_val("disks", {"/dev/vdb": True, "/dev/vdc": True})self.dialog_set_val("name", "SOMERAID")self.dialog_apply()self.dialog_wait_close()# Create bootloader and /boot partitions on vdaif self.is_efi:self.cockpitCreateBootloaderPartitions()else:self.click_dropdown(self.card_row("Storage", 1), "Create partition table")self.confirm()self.click_dropdown(self.card_row("Storage", 2), "Create partition")self.dialog({"size": 1, "type": "biosboot"})self.click_dropdown(self.card_row("Storage", 3), "Create partition")self.dialog({"size": 1070, "type": "ext4", "mount_point": "/boot"})# Create / partition on the RAID deviceself.click_dropdown(self.card_row("Storage", 7), "Create partition table")self.dialog({"type": "gpt"})self.click_dropdown(self.card_row("Storage", 8), "Create partition")self.dialog({"type": "ext4", "mount_point": "/"})def checkStorageReview(prefix=""):with b.wait_timeout(30):disk = "vda"r.check_disk(disk, f"16.1 GB {disk} (Virtio Block Device)", prefix=prefix)if self.is_efi:r.check_disk_row(disk, "/boot/efi", "vda1", "99.6 MB", False, prefix=prefix)r.check_disk_row(disk, "/boot", "vda2", "1.07 GB", False, prefix=prefix)disk = "MDRAID-SOMERAID"r.check_disk(disk, f"32.2 GB {disk} (MDRAID set (stripe))", prefix=prefix)r.check_disk_row(disk, "/", "SOMERAID1, RAID", "32.2 GB", False, prefix=prefix)# Exit the cockpit-storage iframe and return to installationb.switch_to_top()s.return_to_installation()checkStorageReview(prefix="#cockpit-storage-integration-check-storage-dialog")s.return_to_installation_confirm()i.reach(i.steps.REVIEW)# verify review screencheckStorageReview()r.check_checkbox_not_present()self.install(needs_confirmation=False)# Check that the expected partition layout is created and spans all the target deviceslsblk = s.get_lsblk_json()block_devs = lsblk["blockdevices"]vda = next(dev for dev in block_devs if dev["name"] == "vda")vda2 = next(part for part in vda["children"] if part["name"] == "vda2")self.assertEqual(vda2["mountpoints"], ["/boot"])vdb = next(dev for dev in block_devs if dev["name"] == "vdb")raid_dev = next(part for part in vdb["children"] if part["type"] == "raid0")raid_part = next(part for part in raid_dev["children"] if part["type"] == "part")self.assertEqual(raid_part["mountpoints"], ["/"])self.assertEqual(raid_part["size"], "30G")@timeout(1200)def testSWAP(self):"""Description:Test an installation using 'storage editor' and including a disk-based swap partitionExpected results:- The install process should complete successfully and the installed system should boot as expected.- The expected partition layout should be created on the target device(s).- The disk-based swap partition should be active (you can check /proc/swaps or the output of swapon --show)."""b = self.browserm = self.machinei = Installer(b, m, scenario="use-configured-storage")s = Storage(b, m)r = Review(b, m)i.open()i.reach(i.steps.INSTALLATION_METHOD)s.enter_cockpit_storage()# Create ESP and /boot partitions on vdaself.cockpitCreateBootloaderPartitions()# Create a partition for /self.click_dropdown(self.card_row("Storage", 4), "Create partition")self.dialog({"size": 4096, "type": "ext4", "mount_point": "/"})# Create a partition for swapself.click_dropdown(self.card_row("Storage", 5), "Create partition")self.dialog({"size": 1024, "type": "swap"})# Exit the cockpit-storage iframe and return to installations.exit_cockpit_storage()s.check_scenario_selected("use-configured-storage")i.reach(i.steps.REVIEW)r.check_disk("vda", "16.1 GB vda (Virtio Block Device)")r.check_disk_row("vda", "/boot", "vda2", "1.07 GB", False)r.check_disk_row("vda", "/", "vda3", "4.10 GB", False)r.check_disk_row("vda", "swap", "vda4", "1.02 GB", False)self.install(needs_confirmation=False)# Check that the expected partition layout is createdlsblk = s.get_lsblk_json()block_devs = lsblk["blockdevices"]vda = next(dev for dev in block_devs if dev["name"] == "vda")for dev, mountpoint in (("vda2", "/boot"),("vda3", "/"),("vda4", "[SWAP]"),):part = next(part for part in vda["children"] if part["name"] == dev)self.assertEqual(part["mountpoints"], [mountpoint])# Check that the swap partition is activeself.assertIn("/dev/vda4", m.execute("swapon --show"))if __name__ == '__main__':test_main()