diff --git a/Makefile b/Makefile index 8186587e9..c8281990d 100644 --- a/Makefile +++ b/Makefile @@ -188,7 +188,7 @@ payload: bots .PHONY: images images: bots - bots/image-download $(TEST_OS) debian-stable ubuntu-stable + bots/image-download $(TEST_OS) debian-stable ubuntu-stable fedora-41 $(UPDATES_IMG): prepare-test-deps test/prepare-updates-img diff --git a/src/apis/storage_partitioning.js b/src/apis/storage_partitioning.js index 1b32e9e87..873f1f0f8 100644 --- a/src/apis/storage_partitioning.js +++ b/src/apis/storage_partitioning.js @@ -95,6 +95,35 @@ export const partitioningSetEncrypt = ({ encrypt, partitioning }) => { }); }; +/** + * @param {string} partitioning DBus path to a partitioning + * @param {string} scheme autopartitioning scheme + */ +export const partitioningSetHomeReuse = async ({ partitioning, scheme }) => { + const request = await getPartitioningRequest({ partitioning }); + + const configurationSchemeToDBus = { + BTRFS: cockpit.variant("i", 1), + LVM: cockpit.variant("i", 2), + LVM_THINP: cockpit.variant("i", 3), + PLAIN: cockpit.variant("i", 0), + }; + request["partitioning-scheme"] = configurationSchemeToDBus?.[scheme]; + + request["reused-mount-points"] = cockpit.variant("as", ["/home"]); + if (scheme === "PLAIN") { + // "/" will be reallocated by autopartitioning + request["removed-mount-points"] = cockpit.variant("as", ["/", "/boot", "bootloader"]); + } else { + // "LVM", "BTRFS", "LVM_THINP" + // "/" can't be reallocated by autopartitioing as it is sharing container device with /home + request["removed-mount-points"] = cockpit.variant("as", ["/boot", "bootloader"]); + request["reformatted-mount-points"] = cockpit.variant("as", ["/"]); + } + + await setPartitioningRequest({ partitioning, request }); +}; + /** * @returns {Promise} The request of automatic partitioning */ diff --git a/src/components/Common.jsx b/src/components/Common.jsx index 8567dc0fb..2ab6117a0 100644 --- a/src/components/Common.jsx +++ b/src/components/Common.jsx @@ -25,6 +25,7 @@ export const LanguageContext = createContext(null); export const OsReleaseContext = createContext(null); export const RuntimeContext = createContext(null); export const StorageContext = createContext(null); +export const StorageDefaultsContext = createContext(null); export const SystemTypeContext = createContext(null); export const TargetSystemRootContext = createContext(null); export const UsersContext = createContext(null); @@ -66,13 +67,16 @@ const ModuleContextWrapper = ({ children, state }) => { const SystemInfoContextWrapper = ({ children, conf, osRelease }) => { const systemType = conf?.["Installation System"].type; + const defaultScheme = conf?.Storage.default_scheme; return ( - - {children} - + + + {children} + + ); diff --git a/src/components/review/StorageReview.jsx b/src/components/review/StorageReview.jsx index 4f8dd8fb0..07d3ab5d7 100644 --- a/src/components/review/StorageReview.jsx +++ b/src/components/review/StorageReview.jsx @@ -77,6 +77,7 @@ const DeviceRow = ({ disk }) => { const requests = partitioning.requests; const deviceData = devices?.[disk]; + const reuseHomeRequest = requests.find(request => request["reused-mount-points"]); if (!deviceData) { return null; @@ -86,11 +87,18 @@ const DeviceRow = ({ disk }) => { const size = cockpit.format_bytes(devices[device].size.v); const request = requests.find(request => request["device-spec"] === device); const format = devices[device].formatData.type.v; - const action = ( - request === undefined || request.reformat - ? (format ? cockpit.format(_("format as $0"), format) : null) - : ((format === "biosboot") ? format : _("mount")) - ); + + let action = null; + if (reuseHomeRequest?.["reused-mount-points"].includes(mount)) { + action = _("mount"); + } else if ((request === undefined || request.reformat) && format) { + action = cockpit.format(_("format as $0"), format); + } else if (format === "biosboot") { + action = format; + } else { + action = _("mount"); + } + const parents = getParentPartitions(devices, device); const showMaybeType = () => { if (checkDeviceOnStorageType(devices, device, "lvmvg")) { diff --git a/src/components/steps.js b/src/components/steps.js index 82cb3984e..127384fe3 100644 --- a/src/components/steps.js +++ b/src/components/steps.js @@ -11,16 +11,18 @@ import { Page as PageAccounts } from "./users/Accounts.jsx"; const _ = cockpit.gettext; export const getSteps = (...args) => { + const diskConfigurationSteps = [ + new PageMountPointMapping(...args), + new PageDiskEncryption(...args), + ]; const stepsOrder = [ new PageInstallationLanguage(...args), new PageInstallationMethod(...args), { id: "disk-configuration", + isHidden: diskConfigurationSteps.every(step => step.isHidden), label: _("Disk configuration"), - steps: [ - new PageMountPointMapping(...args), - new PageDiskEncryption(...args), - ] + steps: diskConfigurationSteps, }, new PageAccounts(...args), new PageReviewConfiguration(...args), diff --git a/src/components/storage/Common.jsx b/src/components/storage/Common.jsx index 0ff1c3c8c..a6bc27f8f 100644 --- a/src/components/storage/Common.jsx +++ b/src/components/storage/Common.jsx @@ -37,6 +37,7 @@ import { createPartitioning, getDeviceTree, partitioningSetEncrypt, + partitioningSetHomeReuse, partitioningSetPassphrase, } from "../../apis/storage_partitioning.js"; @@ -129,6 +130,7 @@ export const useMountPointConstraints = () => { }; export const getNewPartitioning = async ({ + autopartScheme, currentPartitioning, method = "AUTOMATIC", storageScenarioId, @@ -143,7 +145,14 @@ export const getNewPartitioning = async ({ const part = await createPartitioning({ method }); - if (currentPartitioning?.method === method && method === "AUTOMATIC" && currentPartitioning.requests[0].encrypted) { + if (storageScenarioId === "home-reuse") { + await partitioningSetHomeReuse({ partitioning: part, scheme: autopartScheme }); + } + + if (currentPartitioning?.method === method && + method === "AUTOMATIC" && + storageScenarioId !== "home-reuse" && + currentPartitioning.requests[0].encrypted) { await partitioningSetEncrypt({ encrypt: true, partitioning: part }); await partitioningSetPassphrase({ partitioning: part, passphrase: currentPartitioning.requests[0].passphrase }); } diff --git a/src/components/storage/DiskEncryption.jsx b/src/components/storage/DiskEncryption.jsx index a634abc27..ef38acf47 100644 --- a/src/components/storage/DiskEncryption.jsx +++ b/src/components/storage/DiskEncryption.jsx @@ -194,7 +194,7 @@ export class Page { constructor (isBootIso, storageScenarioId) { this.component = DiskEncryption; this.id = "disk-encryption"; - this.isHidden = ["mount-point-mapping", "use-configured-storage"].includes(storageScenarioId); + this.isHidden = ["mount-point-mapping", "use-configured-storage", "home-reuse"].includes(storageScenarioId); this.label = _("Disk encryption"); this.title = _("Encrypt the selected devices?"); this.usePageInit = usePageInit; diff --git a/src/components/storage/HelpAutopartOptions.jsx b/src/components/storage/HelpAutopartOptions.jsx index ee778c66c..da5c29074 100644 --- a/src/components/storage/HelpAutopartOptions.jsx +++ b/src/components/storage/HelpAutopartOptions.jsx @@ -8,4 +8,6 @@ export const helpUseFreeSpace = _("Keep current disk layout and use available sp export const helpMountPointMapping = _("Assign partitions to mount points. Useful for pre-configured custom layouts."); +export const helpHomeReuse = _("Replace current installation, but keep files in home."); + export const helpConfiguredStorage = _("Storage is based on the configuration from 'Modify storage'."); diff --git a/src/components/storage/InstallationMethod.jsx b/src/components/storage/InstallationMethod.jsx index 58798f292..27e5bcce0 100644 --- a/src/components/storage/InstallationMethod.jsx +++ b/src/components/storage/InstallationMethod.jsx @@ -25,10 +25,19 @@ import { useWizardFooter, } from "@patternfly/react-core"; -import { resetPartitioning } from "../../apis/storage_partitioning.js"; +import { + applyStorage, + resetPartitioning, +} from "../../apis/storage_partitioning.js"; import { AnacondaWizardFooter } from "../AnacondaWizardFooter.jsx"; -import { DialogsContext, FooterContext, OsReleaseContext, StorageContext } from "../Common.jsx"; +import { + DialogsContext, + FooterContext, + OsReleaseContext, + StorageContext, + StorageDefaultsContext, +} from "../Common.jsx"; import { getNewPartitioning } from "./Common.jsx"; import { InstallationDestination } from "./InstallationDestination.jsx"; import { InstallationScenario, scenarios } from "./InstallationScenario.jsx"; @@ -44,6 +53,7 @@ const InstallationMethod = ({ onCritFail, setIsFormDisabled, setIsFormValid, + setStepNotification, showStorage, }) => { const [isReclaimSpaceCheckboxChecked, setIsReclaimSpaceCheckboxChecked] = useState(); @@ -53,8 +63,9 @@ const InstallationMethod = ({ - ), [isFormDisabled, isReclaimSpaceCheckboxChecked]); + ), [isFormDisabled, isReclaimSpaceCheckboxChecked, setStepNotification]); useWizardFooter(getFooter); return ( @@ -86,13 +97,14 @@ const InstallationMethod = ({ ); }; -const CustomFooter = ({ isFormDisabled, isReclaimSpaceCheckboxChecked }) => { +const CustomFooter = ({ isFormDisabled, isReclaimSpaceCheckboxChecked, setStepNotification }) => { const [isReclaimSpaceModalOpen, setIsReclaimSpaceModalOpen] = useState(false); const [isNextClicked, setIsNextClicked] = useState(false); const { goToNextStep } = useWizardContext(); const [newPartitioning, setNewPartitioning] = useState(-1); const nextRef = useRef(); const { partitioning, storageScenarioId } = useContext(StorageContext); + const { defaultScheme } = useContext(StorageDefaultsContext); const method = ["mount-point-mapping", "use-configured-storage"].includes(storageScenarioId) ? "MANUAL" : "AUTOMATIC"; useEffect(() => { @@ -102,12 +114,17 @@ const CustomFooter = ({ isFormDisabled, isReclaimSpaceCheckboxChecked }) => { } }, [isNextClicked, goToNextStep, newPartitioning, partitioning.path]); - const onNext = async () => { + const onNext = async ({ setIsFormDisabled }) => { if (method === "MANUAL") { setNewPartitioning(partitioning.path); setIsNextClicked(true); } else { - const part = await getNewPartitioning({ currentPartitioning: partitioning, method, storageScenarioId }); + const part = await getNewPartitioning({ + autopartScheme: defaultScheme, + currentPartitioning: partitioning, + method, + storageScenarioId, + }); setNewPartitioning(part); const scenarioSupportsReclaimSpace = scenarios.find(sc => sc.id === storageScenarioId)?.canReclaimSpace; @@ -115,8 +132,27 @@ const CustomFooter = ({ isFormDisabled, isReclaimSpaceCheckboxChecked }) => { if (willShowReclaimSpaceModal) { setIsReclaimSpaceModalOpen(true); - } else { + } else if (storageScenarioId !== "home-reuse") { setIsNextClicked(true); + } else { + setIsFormDisabled(true); + const step = new Page().id; + await applyStorage({ + onFail: ex => { + console.error(ex); + setIsFormDisabled(false); + setStepNotification({ step, ...ex }); + }, + onSuccess: () => { + goToNextStep(); + + // Reset the state after the onNext call. Otherwise, + // React will try to render the current step again. + setIsFormDisabled(false); + setStepNotification(); + }, + partitioning: part, + }); } } }; @@ -165,12 +201,16 @@ const InstallationMethodFooterHelper = () => { const usePageInit = () => { const { setIsFormDisabled } = useContext(FooterContext); const { appliedPartitioning, partitioning } = useContext(StorageContext); + const pageHasMounted = useRef(false); + // Always reset the partitioning when entering the installation destination page // If the last partitioning applied was from the cockpit storage integration // we should not reset it, as this option does apply the partitioning onNext - const needsReset = partitioning.storageScenarioId !== "use-configured-storage" && appliedPartitioning; + const needsReset = partitioning.storageScenarioId !== "use-configured-storage" && + appliedPartitioning && + pageHasMounted.current !== true; useEffect(() => { - // Always reset the partitioning when entering the installation destination page + pageHasMounted.current = true; if (needsReset) { resetPartitioning(); } else { diff --git a/src/components/storage/InstallationScenario.jsx b/src/components/storage/InstallationScenario.jsx index aa8838362..67bff466b 100644 --- a/src/components/storage/InstallationScenario.jsx +++ b/src/components/storage/InstallationScenario.jsx @@ -29,18 +29,27 @@ import { import { setStorageScenarioAction } from "../../actions/storage-actions.js"; import { debug } from "../../helpers/log.js"; +import { + getDeviceAncestors, +} from "../../helpers/storage.js"; -import { DialogsContext, StorageContext, SystemTypeContext } from "../Common.jsx"; +import { + DialogsContext, + StorageContext, + StorageDefaultsContext, + SystemTypeContext +} from "../Common.jsx"; import { StorageReview } from "../review/StorageReview.jsx"; import { useDiskFreeSpace, useDiskTotalSpace, useMountPointConstraints, useOriginalDeviceTree, + useOriginalExistingSystems, useRequiredSize, useUsablePartitions, } from "./Common.jsx"; -import { helpConfiguredStorage, helpEraseAll, helpMountPointMapping, helpUseFreeSpace } from "./HelpAutopartOptions.jsx"; +import { helpConfiguredStorage, helpEraseAll, helpHomeReuse, helpMountPointMapping, helpUseFreeSpace } from "./HelpAutopartOptions.jsx"; import "./InstallationScenario.scss"; @@ -126,6 +135,69 @@ const checkMountPointMapping = ({ mountPointConstraints, selectedDisks, usablePa return availability; }; +const checkHomeReuse = ({ autopartScheme, devices, originalExistingSystems, selectedDisks }) => { + const availability = new AvailabilityState(); + let reusedOS = null; + + availability.hidden = false; + availability.available = !!selectedDisks.length; + + const isCompleteOSOnDisks = (osData, disks) => { + const osDisks = osData.devices.v.map(deviceId => getDeviceAncestors(devices, deviceId)) + .reduce((disks, ancestors) => disks.concat(ancestors)) + .filter(dev => devices[dev].type.v === "disk") + .reduce((uniqueDisks, disk) => uniqueDisks.includes(disk) ? uniqueDisks : [...uniqueDisks, disk], []); + const missingDisks = osDisks.filter(disk => !disks.includes(disk)); + return missingDisks.length === 0; + }; + + // Check that exactly one Linux OS is present and it is Fedora Linux + // (Stronger check for mountpoints uniqueness is in the backend + const linuxSystems = originalExistingSystems.filter(osdata => osdata["os-name"].v.includes("Linux")) + .filter(osdata => isCompleteOSOnDisks(osdata, selectedDisks)); + if (linuxSystems.length === 0) { + availability.available = false; + availability.hidden = true; + debug("home reuse: No existing Linux system found."); + } else if (linuxSystems.length > 1) { + availability.available = false; + availability.hidden = true; + debug("home reuse: Multiple existing Linux systems found."); + } else { + reusedOS = linuxSystems[0]; + if (!linuxSystems.some(osdata => osdata["os-name"].v.includes("Fedora"))) { + availability.available = false; + availability.hidden = true; + debug("home reuse: No existing Fedora Linux system found."); + } + } + + if (reusedOS) { + // Check that required autopartitioning scheme matches reused OS. + // Check just "/home". To be more generic we could check all reused devices (as the backend). + const homeDevice = reusedOS["mount-points"].v["/home"]; + const homeDeviceType = devices[homeDevice]?.type.v; + const requiredSchemeTypes = { + BTRFS: "btrfs subvolume", + LVM: "lvmlv", + LVM_THINP: "lvmthinlv", + PLAIN: "partition", + }; + if (homeDeviceType !== requiredSchemeTypes[autopartScheme]) { + availability.available = false; + availability.hidden = true; + debug(`home reuse: No reusable existing Linux system found, reused devices must have ${requiredSchemeTypes[autopartScheme]} type`); + } + } + + // TODO checks: + // - luks - partitions are unlocked - enforce? allow opt-out? + // - size ? + // - Windows system along (forbidden for now?) + + return availability; +}; + export const checkConfiguredStorage = ({ devices, mountPointConstraints, @@ -204,6 +276,16 @@ const ReclaimSpace = ({ availability }) => { }; export const scenarios = [{ + buttonLabel: _("Reinstall Fedora"), + buttonVariant: "danger", + check: checkHomeReuse, + default: false, + detail: helpHomeReuse, + id: "home-reuse", + // CLEAR_PARTITIONS_NONE = 0 + initializationMode: 0, + label: _("Reinstall Fedora"), +}, { buttonLabel: _("Erase data and install"), buttonVariant: "danger", check: checkEraseAll, @@ -282,6 +364,8 @@ const InstallationScenarioSelector = ({ const usablePartitions = useUsablePartitions({ devices, selectedDisks }); const requiredSize = useRequiredSize(); const { storageScenarioId } = useContext(StorageContext); + const originalExistingSystems = useOriginalExistingSystems(); + const { defaultScheme } = useContext(StorageDefaultsContext); useEffect(() => { if ([diskTotalSpace, diskFreeSpace, mountPointConstraints, requiredSize, usablePartitions].some(itm => itm === undefined)) { @@ -293,10 +377,12 @@ const InstallationScenarioSelector = ({ for (const scenario of scenarios) { const availability = scenario.check({ + autopartScheme: defaultScheme, devices, diskFreeSpace, diskTotalSpace, mountPointConstraints, + originalExistingSystems, partitioning: partitioning.path, requiredSize, selectedDisks, @@ -308,10 +394,12 @@ const InstallationScenarioSelector = ({ return newAvailability; }); }, [ + defaultScheme, devices, diskFreeSpace, diskTotalSpace, mountPointConstraints, + originalExistingSystems, partitioning.path, partitioning.storageScenarioId, requiredSize, diff --git a/test/check-storage-home-reuse b/test/check-storage-home-reuse new file mode 100755 index 000000000..00283bff0 --- /dev/null +++ b/test/check-storage-home-reuse @@ -0,0 +1,152 @@ +#!/usr/bin/python3 +# +# Copyright (C) 2024 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; If not, see . + +import os + +from anacondalib import VirtInstallMachineCase +from installer import Installer +from review import Review +from storage import Storage +from storagelib import StorageCase # pylint: disable=import-error +from testlib import nondestructive, skipImage, test_main # pylint: disable=import-error +from utils import pretend_default_scheme + +TEST_DIR = os.path.dirname(__file__) +ROOT_DIR = os.path.dirname(TEST_DIR) +BOTS_DIR = f'{ROOT_DIR}/bots' + + +@nondestructive +class TestHomeReuseFedora(VirtInstallMachineCase, StorageCase): + disk_image = "fedora-rawhide" + efi = False + + def testBasic(self): + b = self.browser + m = self.machine + i = Installer(b, m, scenario="home-reuse") + s = Storage(b, m) + r = Review(b, m) + + pretend_default_scheme(self, "BTRFS") + + dev="vda" + + i.open() + i.reach(i.steps.INSTALLATION_METHOD) + s.rescan_disks() + + s.set_partitioning("home-reuse") + i.reach(i.steps.REVIEW) + + + # check selected disks are shown + r.check_disk(dev, f"16.1 GB {dev} (0x1af4)") + r.check_disk_row(dev, parent=f"{dev}3", action="delete") + r.check_disk_row(dev, parent=f"{dev}1", action="delete") + r.check_disk_row(dev, "/boot", f"{dev}3", "1.07 GB", True, "xfs", is_encrypted=False) + r.check_disk_row(dev, "/", f"{dev}4", "12.8 GB", True, "btrfs", is_encrypted=False) + r.check_disk_row(dev, "/home", f"{dev}4", "12.8 GB", False, "btrfs", is_encrypted=False, + action="mount") + + + @skipImage("btrfs support missing on fedora-eln image", "fedora-eln-boot") + def testMultipleRoots(self): + b = self.browser + m = self.machine + i = Installer(b, m, scenario="home-reuse") + s = Storage(b, m) + r = Review(b, m) + + self.add_disk(15, os.path.join(BOTS_DIR, "./images/fedora-41")) + self.add_disk(15, os.path.join(BOTS_DIR, "./images/ubuntu-stable")) + + dev_fedora1 = "vda" + dev_fedora2 = "vdb" + dev_ubuntu = "vdc" + + s.udevadm_settle() + + pretend_default_scheme(self, "BTRFS") + + i.open() + i.reach(i.steps.INSTALLATION_METHOD) + + # Select both Fedora disks and verify that home reuse is not available + s.select_disks([(dev_fedora1, True), (dev_fedora2, True), (dev_ubuntu, False)]) + s.wait_scenario_visible("home-reuse", False) + + # Select only single Ubuntu disk and verify that home reuse is not available + s.select_disks([(dev_fedora1, False), (dev_fedora2, False), (dev_ubuntu, True)]) + s.wait_scenario_visible("home-reuse", False) + + # Select Ubuntu disk and Fedora disk and verify that home reuse is not available + s.select_disks([(dev_fedora1, True), (dev_fedora2, False), (dev_ubuntu, True)]) + s.wait_scenario_visible("home-reuse", False) + + # Select only single Fedora disk and verify that home reuse is available + s.select_disks([(dev_fedora1, True), (dev_fedora2, False), (dev_ubuntu, False)]) + s.wait_scenario_visible("home-reuse", True) + s.wait_scenario_available("home-reuse", True) + + s.set_partitioning("home-reuse") + i.reach(i.steps.REVIEW) + + # check selected disks are shown + r.check_disk(dev_fedora1, f"16.1 GB {dev_fedora1} (0x1af4)") + r.check_disk_row(dev_fedora1, parent=f"{dev_fedora1}3", action="delete") + r.check_disk_row(dev_fedora1, parent=f"{dev_fedora1}1", action="delete") + r.check_disk_row(dev_fedora1, "/boot", f"{dev_fedora1}3", "1.07 GB", True, "xfs", is_encrypted=False) + r.check_disk_row(dev_fedora1, "/", f"{dev_fedora1}4", "12.8 GB", True, "btrfs", is_encrypted=False) + r.check_disk_row(dev_fedora1, "/home", f"{dev_fedora1}4", "12.8 GB", False, "btrfs", is_encrypted=False, + action="mount") + + +class TestHomeReuseFedoraEFI(VirtInstallMachineCase, StorageCase): + disk_image = "fedora-rawhide" + efi = True + + def testBasic(self): + b = self.browser + m = self.machine + i = Installer(b, m, scenario="home-reuse") + s = Storage(b, m) + r = Review(b, m) + + pretend_default_scheme(self, "BTRFS") + + dev="vda" + + i.open() + i.reach(i.steps.INSTALLATION_METHOD) + s.rescan_disks() + + s.set_partitioning("home-reuse") + i.reach(i.steps.REVIEW) + + # check selected disks are shown + r.check_disk_row(dev, parent=f"{dev}2", action="delete") + r.check_disk_row(dev, parent=f"{dev}3", action="delete") + r.check_disk(dev, f"16.1 GB {dev} (0x1af4)") + r.check_disk_row(dev, "/boot", f"{dev}3", "1.07 GB", True, "xfs", is_encrypted=False) + r.check_disk_row(dev, "/boot/efi", f"{dev}2", "629 MB", True, "efi", is_encrypted=False) + r.check_disk_row(dev, "/", f"{dev}4", "12.8 GB", True, "btrfs", is_encrypted=False) + r.check_disk_row(dev, "/home", f"{dev}4", "12.8 GB", False, "btrfs", is_encrypted=False, + action="mount") + +if __name__ == '__main__': + test_main() diff --git a/test/helpers/installer.py b/test/helpers/installer.py index f9e2f1527..fe57c7b82 100644 --- a/test/helpers/installer.py +++ b/test/helpers/installer.py @@ -57,6 +57,9 @@ def __init__(self, browser, machine, hidden_steps=None, scenario=None): if (scenario == 'use-configured-storage'): self.steps._steps_jump[self.steps.INSTALLATION_METHOD] = [self.steps.ACCOUNTS] self.hidden_steps.extend([self.steps.CUSTOM_MOUNT_POINT, self.steps.DISK_ENCRYPTION]) + elif (scenario == 'home-reuse'): + self.steps._steps_jump[self.steps.INSTALLATION_METHOD] = [self.steps.ACCOUNTS] + self.hidden_steps.extend([self.steps.CUSTOM_MOUNT_POINT, self.steps.DISK_ENCRYPTION]) else: self.steps._steps_jump[self.steps.INSTALLATION_METHOD] = [self.steps.DISK_ENCRYPTION, self.steps.CUSTOM_MOUNT_POINT] diff --git a/test/helpers/utils.py b/test/helpers/utils.py index ee6166ce4..ba8f82b18 100644 --- a/test/helpers/utils.py +++ b/test/helpers/utils.py @@ -31,6 +31,9 @@ def pretend_live_iso(test, installer): test.restore_file('/run/anaconda/anaconda.conf') test.machine.execute("sed -i 's/type = BOOT_ISO/type = LIVE_OS/g' /run/anaconda/anaconda.conf") +def pretend_default_scheme(test, scheme): + test.restore_file('/run/anaconda/anaconda.conf') + test.machine.execute(f"sed -i 's/default_scheme =.*/default_scheme = {scheme}/g' /run/anaconda/anaconda.conf") def get_pretty_name(machine): return machine.execute("cat /etc/os-release | grep PRETTY_NAME | cut -d '\"' -f 2 | tr -d '\n'") diff --git a/test/reference b/test/reference index f613f73b9..6dd33cda3 160000 --- a/test/reference +++ b/test/reference @@ -1 +1 @@ -Subproject commit f613f73b9d21c6a75cda1db68e81b271aa4e5a0c +Subproject commit 6dd33cda3786b64deed1335f2a2b4060337fad06