From fc45c605c27c34270c0ab8de0b015c163215aa28 Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Wed, 14 Dec 2022 11:46:37 +0100 Subject: [PATCH 01/11] New diskutil.getHumanDiskLabel to centralize formatting of disk name for user Signed-off-by: Yann Dirson --- diskutil.py | 4 ++++ tui/installer/screens.py | 8 ++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/diskutil.py b/diskutil.py index 952977b4..d2943a16 100644 --- a/diskutil.py +++ b/diskutil.py @@ -392,6 +392,10 @@ def getHumanDiskName(disk): return disk[5:] return disk +def getHumanDiskLabel(disk): + (vendor, model, size) = getExtendedDiskInfo(disk) + return "%s - %s [%s %s]" % (getHumanDiskName(disk), getHumanDiskSize(size), vendor, model) + # given a list of disks, work out which ones are part of volume # groups that will cause a problem if we install XE to those disks: def findProblematicVGs(disks): diff --git a/tui/installer/screens.py b/tui/installer/screens.py index e7b52721..e83f158d 100644 --- a/tui/installer/screens.py +++ b/tui/installer/screens.py @@ -556,9 +556,7 @@ def select_primary_disk(answers): (boot, root, state, storage, logs) = diskutil.probeDisk(de) if storage[0]: target_is_sr[de] = True - (vendor, model, size) = diskutil.getExtendedDiskInfo(de) - stringEntry = "%s - %s [%s %s]" % (diskutil.getHumanDiskName(de), diskutil.getHumanDiskSize(size), vendor, model) - e = (stringEntry, de) + e = (diskutil.getHumanDiskLabel(de), de) entries.append(e) # we should have at least one disk @@ -665,9 +663,7 @@ def select_guest_disks(answers): # Make a list of entries: (text, item) entries = [] for de in diskEntries: - (vendor, model, size) = diskutil.getExtendedDiskInfo(de) - entry = "%s - %s [%s %s]" % (diskutil.getHumanDiskName(de), diskutil.getHumanDiskSize(size), vendor, model) - entries.append((entry, de)) + entries.append((diskutil.getHumanDiskLabel(de), de)) text = TextboxReflowed(54, "Which disks would you like to use for %s storage? \n\nOne storage repository will be created that spans the selected disks. You can choose not to prepare any storage if you wish to create an advanced configuration after installation." % BRAND_GUEST) buttons = ButtonBar(tui.screen, [('Ok', 'ok'), ('Back', 'back')]) From 97052fc75a85093e8a9335c42bec8482a5976e3c Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Thu, 8 Dec 2022 17:19:53 +0100 Subject: [PATCH 02/11] tui: show the disk on which an existing installation or backup is found Adding disk vendor and model would be useful, but can take too much horizontal space, especially for good old 80x25 resolution, so we use a shorter string with just the disk size for disambiguation. Signed-off-by: Yann Dirson --- diskutil.py | 6 ++++-- tui/installer/screens.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/diskutil.py b/diskutil.py index d2943a16..616dae11 100644 --- a/diskutil.py +++ b/diskutil.py @@ -392,9 +392,11 @@ def getHumanDiskName(disk): return disk[5:] return disk -def getHumanDiskLabel(disk): +def getHumanDiskLabel(disk, short=False): (vendor, model, size) = getExtendedDiskInfo(disk) - return "%s - %s [%s %s]" % (getHumanDiskName(disk), getHumanDiskSize(size), vendor, model) + template = "{device} - {size} [{vendor} {model}]" if not short else "{device} - {size}" + return template.format(device=getHumanDiskName(disk), size=getHumanDiskSize(size), + vendor=vendor, model=model) # given a list of disks, work out which ones are part of volume # groups that will cause a problem if we install XE to those disks: diff --git a/tui/installer/screens.py b/tui/installer/screens.py index e83f158d..bd594a0c 100644 --- a/tui/installer/screens.py +++ b/tui/installer/screens.py @@ -218,9 +218,11 @@ def get_admin_interface_configuration(answers): def get_installation_type(answers): entries = [] for x in answers['upgradeable-products']: - entries.append(("Upgrade %s" % str(x), (x, x.settingsAvailable()))) + entries.append(("Upgrade %s on %s" % (x, diskutil.getHumanDiskLabel(x.primary_disk, short=True)), + (x, x.settingsAvailable()))) for b in answers['backups']: - entries.append(("Restore %s from backup" % str(b), (b, None))) + entries.append(("Restore %s from backup to %s" % (b, diskutil.getHumanDiskLabel(b.root_disk, short=True)), + (b, None))) entries.append( ("Perform clean installation", None) ) From f43e47e35228a91cafce4d7cbc508a602522f3ed Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Thu, 8 Dec 2022 14:15:38 +0100 Subject: [PATCH 03/11] Provide a Makefile for installation Reasons to have this here include: * don't require changes to srpm when the set of installed files change * make installer development faster by deploying directly to a filesystem This installation process still depends by default on the sm package being installed, but through SM_ROOT variable it can now be run on a dev machine where this is not the case, it just needs an unpacked version of the package. Signed-off-by: Yann Dirson --- Makefile | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..27a385af --- /dev/null +++ b/Makefile @@ -0,0 +1,95 @@ +# destinations +DESTDIR = +INSTALLER_DIR = /opt/xensource/installer +EFI_DIR = /EFI/xenserver + +# root of a tree with sm.rpm unpacked +SM_ROOTDIR = + +INSTALL = install + +install: + $(INSTALL) -d $(DESTDIR)/usr/bin + $(INSTALL) -m755 support.sh $(DESTDIR)/usr/bin + $(INSTALL) -d $(DESTDIR)$(INSTALLER_DIR)/tui/installer/ + $(INSTALL) -m755 \ + init \ + $(DESTDIR)$(INSTALLER_DIR)/ + $(INSTALL) -m644 \ + keymaps \ + timezones \ + answerfile.py \ + backend.py \ + common_criteria_firewall_rules \ + constants.py \ + cpiofile.py \ + disktools.py \ + diskutil.py \ + driver.py \ + fcoeutil.py \ + generalui.py \ + hardware.py \ + init_constants.py \ + install.py \ + netinterface.py \ + netutil.py \ + product.py \ + report.py \ + repository.py \ + restore.py \ + scripts.py \ + snackutil.py \ + uicontroller.py \ + upgrade.py \ + util.py \ + xelogging.py \ + $(DESTDIR)$(INSTALLER_DIR)/ + $(INSTALL) -m644 \ + tui/__init__.py \ + tui/init.py \ + tui/fcoe.py \ + tui/network.py \ + tui/progress.py \ + tui/repo.py \ + $(DESTDIR)$(INSTALLER_DIR)/tui/ + $(INSTALL) -m644 \ + tui/installer/__init__.py \ + tui/installer/screens.py \ + $(DESTDIR)$(INSTALLER_DIR)/tui/installer/ + + # Startup files + $(INSTALL) -d \ + $(DESTDIR)/etc/init.d \ + $(DESTDIR)/etc/modprobe.d \ + $(DESTDIR)/etc/modules-load.d \ + $(DESTDIR)/etc/depmod.d \ + $(DESTDIR)/etc/dracut.conf.d \ + $(DESTDIR)/etc/systemd/system/systemd-udevd.d + + $(INSTALL) -m755 startup/interface-rename-sideway startup/early-blacklist $(DESTDIR)/etc/init.d/ + $(INSTALL) -m644 startup/functions $(DESTDIR)/etc/init.d/installer-functions + $(INSTALL) -m644 startup/early-blacklist.conf startup/bnx2x.conf $(DESTDIR)/etc/modprobe.d/ + $(INSTALL) -m644 startup/blacklist $(DESTDIR)/etc/modprobe.d/installer-blacklist.conf + $(INSTALL) -m644 startup/modprobe.mlx4 $(DESTDIR)/etc/modprobe.d/mlx4.conf + $(INSTALL) -m644 startup/iscsi-modules $(DESTDIR)/etc/modules-load.d/iscsi.conf + $(INSTALL) -m644 startup/depmod.conf $(DESTDIR)/etc/depmod.d/ + $(INSTALL) -m755 startup/preinit startup/S05ramdisk startup/S06mount $(DESTDIR)/$(INSTALLER_DIR)/ + $(INSTALL) -m644 startup/systemd-udevd_depmod.conf $(DESTDIR)/etc/systemd/system/systemd-udevd.d/installer.conf + + # Generate a multipath configuration from sm's copy, removing + # the blacklist and blacklist_exception sections. + sed 's/\(^[[:space:]]*find_multipaths[[:space:]]*\)yes/\1no/' \ + < $(SM_ROOTDIR)/etc/multipath.xenserver/multipath.conf \ + > $(DESTDIR)/etc/multipath.conf.disabled + + # bootloader files + $(INSTALL) -D -m644 bootloader/grub.cfg $(DESTDIR)$(EFI_DIR)/grub.cfg + $(INSTALL) -D -m644 bootloader/grub.cfg $(DESTDIR)$(EFI_DIR)/grub-usb.cfg + + sed -i '/^set timeout=[0-9]\+$/asearch --file --set /install.img' \ + $(DESTDIR)$(EFI_DIR)/grub-usb.cfg + + $(INSTALL) -D -m644 bootloader/isolinux.cfg $(DESTDIR)/boot/isolinux/isolinux.cfg + + printf "echo Skipping initrd creation in the installer\nexit 0\n" \ + > $(DESTDIR)/etc/dracut.conf.d/installer.conf From f95e3d7f0189884924ec35412f2c497a25d92458 Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Wed, 25 Jan 2023 15:10:30 +0100 Subject: [PATCH 04/11] diskutil: make md device name more human-readable mdadm output is like "MD_DEVNAME=127 which results in getHumanDiskName giving a name of "RAID: 127(sda,sdb)". This fixes the problem and gets us "RAID: md127(sda,sdb)" instead. Also slightly improve readability with tuple unpacking. Signed-off-by: Yann Dirson --- diskutil.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/diskutil.py b/diskutil.py index 616dae11..cac8d2a0 100644 --- a/diskutil.py +++ b/diskutil.py @@ -365,9 +365,9 @@ def getMdDeviceName(disk): rv, out = util.runCmd2(['mdadm', '--detail', '--export', disk], with_stdout=True) for line in out.split("\n"): - line = line.strip().split('=', 1) - if line[0] == 'MD_DEVNAME': - return line[1] + key, value = line.strip().split('=', 1) + if key == 'MD_DEVNAME': + return "md%s" % value return disk From 03b3bb10d8ff4240e7611a9ba2cc4e1389332913 Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Thu, 8 Dec 2022 15:05:16 +0100 Subject: [PATCH 05/11] udev: force ANACONDA flag to prevent RAID assembling This prevents 65-md-incremental.rules from assembling every RAID it identifies, we want to have control over that, so we can reuse a former RAID member for other purposes. Signed-off-by: Yann Dirson --- Makefile | 2 ++ startup/01-installer.rules | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 startup/01-installer.rules diff --git a/Makefile b/Makefile index 27a385af..d830bb97 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,7 @@ install: $(DESTDIR)/etc/modules-load.d \ $(DESTDIR)/etc/depmod.d \ $(DESTDIR)/etc/dracut.conf.d \ + $(DESTDIR)/etc/udev/rules.d \ $(DESTDIR)/etc/systemd/system/systemd-udevd.d $(INSTALL) -m755 startup/interface-rename-sideway startup/early-blacklist $(DESTDIR)/etc/init.d/ @@ -74,6 +75,7 @@ install: $(INSTALL) -m644 startup/iscsi-modules $(DESTDIR)/etc/modules-load.d/iscsi.conf $(INSTALL) -m644 startup/depmod.conf $(DESTDIR)/etc/depmod.d/ $(INSTALL) -m755 startup/preinit startup/S05ramdisk startup/S06mount $(DESTDIR)/$(INSTALLER_DIR)/ + $(INSTALL) -m644 startup/01-installer.rules $(DESTDIR)/etc/udev/rules.d/ $(INSTALL) -m644 startup/systemd-udevd_depmod.conf $(DESTDIR)/etc/systemd/system/systemd-udevd.d/installer.conf # Generate a multipath configuration from sm's copy, removing diff --git a/startup/01-installer.rules b/startup/01-installer.rules new file mode 100644 index 00000000..5267d3ef --- /dev/null +++ b/startup/01-installer.rules @@ -0,0 +1,2 @@ +# disable 65-md-incremental.rules by telling an installer is running +ENV{ANACONDA}="1" From 8e7a74a9f3712998a06167129718c974e39aacf8 Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Fri, 9 Dec 2022 11:39:39 +0100 Subject: [PATCH 06/11] main sequence: scan for existing products as late as possible This causes the "Back" button in primary-disk selection to trigger a rescan for products. This provides support for allowing the user to enable layers of block-device composition (e.g. "md" software RAID, not part of this PR) and then scan those RAID volumes for products. This could even be used for arbitrary manual block-device setup from shell on alternate console. Signed-off-by: Yann Dirson --- tui/installer/__init__.py | 1 + tui/installer/screens.py | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/tui/installer/__init__.py b/tui/installer/__init__.py index 7a8f588f..99c68d65 100644 --- a/tui/installer/__init__.py +++ b/tui/installer/__init__.py @@ -124,6 +124,7 @@ def out_of_order_pool_upgrade_fn(answers): Step(uis.hardware_warnings, args=[ram_warning, vt_warning], predicates=[lambda _:(ram_warning or vt_warning)]), + Step(uis.scan_existing), Step(uis.overwrite_warning, predicates=[only_unupgradeable_products]), Step(uis.get_installation_type, diff --git a/tui/installer/screens.py b/tui/installer/screens.py index bd594a0c..02ed9abd 100644 --- a/tui/installer/screens.py +++ b/tui/installer/screens.py @@ -111,14 +111,6 @@ def fn10(): lvm.deactivateAll() del lvm - tui.progress.showMessageDialog("Please wait", "Checking for existing products...") - answers['installed-products'] = product.find_installed_products() - answers['upgradeable-products'] = upgrade.filter_for_upgradeable_products(answers['installed-products']) - answers['backups'] = product.findXenSourceBackups() - tui.progress.clearModelessDialog() - - diskutil.log_available_disks() - # CA-41142, ensure we have at least one network interface and one disk before proceeding label = None if len(diskutil.getDiskList()) == 0: @@ -160,6 +152,17 @@ def hardware_warnings(answers, ram_warning, vt_warning): if button == 'back': return LEFT_BACKWARDS return RIGHT_FORWARDS +def scan_existing(answers): + tui.progress.showMessageDialog("Please wait", "Checking for existing products...") + answers['installed-products'] = product.find_installed_products() + answers['upgradeable-products'] = upgrade.filter_for_upgradeable_products(answers['installed-products']) + answers['backups'] = product.findXenSourceBackups() + tui.progress.clearModelessDialog() + + diskutil.log_available_disks() + + return RIGHT_FORWARDS + def overwrite_warning(answers): warning_string = "Continuing will result in a clean installation, all existing configuration will be lost." warning_string += "\n\nAlternatively, please contact a Technical Support Representative for the recommended upgrade path." From d35bc84479963e20a8938f406d72896aede053c2 Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Wed, 25 Jan 2023 12:17:27 +0100 Subject: [PATCH 07/11] get_installation_type: make the screen unconditional It has value for a user expecting an existing product to get notified that none was found. Moreover, this will allow a user to get to the "assemble RAID" choice even when no product was detected. Signed-off-by: Yann Dirson --- tui/installer/__init__.py | 3 +-- tui/installer/screens.py | 8 +++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tui/installer/__init__.py b/tui/installer/__init__.py index 99c68d65..9e3f46d9 100644 --- a/tui/installer/__init__.py +++ b/tui/installer/__init__.py @@ -127,8 +127,7 @@ def out_of_order_pool_upgrade_fn(answers): Step(uis.scan_existing), Step(uis.overwrite_warning, predicates=[only_unupgradeable_products]), - Step(uis.get_installation_type, - predicates=[lambda _:len(results['upgradeable-products']) > 0 or len(results['backups']) > 0]), + Step(uis.get_installation_type), Step(uis.upgrade_settings_warning, predicates=[upgrade_but_no_settings_predicate]), Step(uis.ha_master_upgrade, diff --git a/tui/installer/screens.py b/tui/installer/screens.py index 02ed9abd..86b2434a 100644 --- a/tui/installer/screens.py +++ b/tui/installer/screens.py @@ -237,12 +237,14 @@ def get_installation_type(answers): else: default = None - if len(answers['upgradeable-products']) > 0: + if answers['upgradeable-products']: text = "One or more existing product installations that can be upgraded have been detected." - if len(answers['backups']) > 0: + if answers['backups']: text += " In addition one or more backups have been detected." - else: + elif answers['backups']: text = "One or more backups have been detected." + else: + text = "No existing product installation or backup was detected." text += "\n\nWhat would you like to do?" tui.update_help_line([None, " more info"]) From 7e06b7761d82c3fa7f04375bbb466537b7535e74 Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Fri, 9 Dec 2022 14:13:52 +0100 Subject: [PATCH 08/11] RAID: when a MD superblock is found on a disk, offer user to assemble RAID This adds an option to enable *all* RAID devices found. This is less flexible than a more selective mechanism would be, but really simple and covering all known use-cases. It filters out from choices presented to the user both "update of" and "restore to" entries refering to a disk that is part of a md RAID (though in practice only the "update" case is likely to appear). This avoids the case where a user gets those entries before explicitly assembling RAIDs, and thus avoids breaking a RAID by mistake. Signed-off-by: Yann Dirson --- tui/installer/screens.py | 60 ++++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/tui/installer/screens.py b/tui/installer/screens.py index 86b2434a..e361b914 100644 --- a/tui/installer/screens.py +++ b/tui/installer/screens.py @@ -154,6 +154,11 @@ def hardware_warnings(answers, ram_warning, vt_warning): def scan_existing(answers): tui.progress.showMessageDialog("Please wait", "Checking for existing products...") + + if 'assemble-raid' in answers: + logger.log("Assembling any RAID volumes") + rv = util.runCmd2([ 'mdadm', '--assemble', "--scan" ]) + answers['installed-products'] = product.find_installed_products() answers['upgradeable-products'] = upgrade.filter_for_upgradeable_products(answers['installed-products']) answers['backups'] = product.findXenSourceBackups() @@ -219,14 +224,42 @@ def get_admin_interface_configuration(answers): return rc def get_installation_type(answers): - entries = [] + + # If we were not already told to enable RAID, build a full list of + # RAID members, for filtering out from upgradable-products and + # backups, and to decide whether to propose to activate existing RAID. + raid_members = [] + if "assemble-raid" not in answers: + for disk in diskutil.getQualifiedDiskList(): + rv, out = util.runCmd2([ 'mdadm', '--examine', disk ], with_stdout=True) + if rv == 0 and re.search("Array UUID :", out): + raid_members.append(disk) + + upgradeable_products = [] for x in answers['upgradeable-products']: + if x.primary_disk in raid_members: + logger.log("%s: disk %s in %s, skipping" % (x, x.primary_disk, raid_members)) + continue + upgradeable_products.append(x) + backups = [] + for b in answers['backups']: + if b.root_disk in raid_members: + logger.log("%s: disk %s in %s, skipping" % (b, b.root_disk, raid_members)) + continue + backups.append(b) + + entries = [] + for x in upgradeable_products: entries.append(("Upgrade %s on %s" % (x, diskutil.getHumanDiskLabel(x.primary_disk, short=True)), (x, x.settingsAvailable()))) - for b in answers['backups']: + for b in backups: entries.append(("Restore %s from backup to %s" % (b, diskutil.getHumanDiskLabel(b.root_disk, short=True)), (b, None))) + if raid_members: + logger.log("Found a MD RAID on: %s" % ", ".join(raid_members)) + entries.append(("Assemble software RAID volumes", ("RAID", None))) + entries.append( ("Perform clean installation", None) ) # default value? @@ -237,14 +270,21 @@ def get_installation_type(answers): else: default = None - if answers['upgradeable-products']: - text = "One or more existing product installations that can be upgraded have been detected." - if answers['backups']: - text += " In addition one or more backups have been detected." - elif answers['backups']: - text = "One or more backups have been detected." + if upgradeable_products or backups: + if upgradeable_products: + text = "One or more existing product installations that can be upgraded have been detected." + if backups: + text += " In addition one or more backups have been detected." + else: + text = "One or more backups have been detected." + if raid_members: + text += " Also, some disks have been identified as members of a sofware-RAID volume." + elif raid_members: + text = "Some disks have been identified as members of a sofware-RAID volume." else: text = "No existing product installation or backup was detected." + if raid_members: + text += " RAID volumes may themselves contain more upgradeable products or backups." text += "\n\nWhat would you like to do?" tui.update_help_line([None, " more info"]) @@ -313,6 +353,10 @@ def more_info(context): elif isinstance(entry[0], product.XenServerBackup): answers['install-type'] = constants.INSTALL_TYPE_RESTORE answers['backup-to-restore'], _ = entry + elif entry[0] == "RAID": + # go rescan for products after assembling RAID volumes + answers['assemble-raid'] = True + return LEFT_BACKWARDS return RIGHT_FORWARDS From 140fec5dbe1c4f8786fc3ec974ed3a84ad336d0c Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Wed, 14 Dec 2022 17:48:33 +0100 Subject: [PATCH 09/11] later-squash! RAID: when a MD superblock is found on a disk, offer user to assemble RAID This commit is kept as separate until decided this is the way to go, but would be better squashed. Introduce installer feature flags, and hide the RAID-assembling feature behind the `raid-assemble` flag. --- constants.py | 4 ++++ doc/features.txt | 18 ++++++++++++++++++ tui/installer/screens.py | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 doc/features.txt diff --git a/constants.py b/constants.py index 7b414802..1dc3d4eb 100644 --- a/constants.py +++ b/constants.py @@ -181,3 +181,7 @@ def error_string(error, logname, with_hd): 'var/lib/misc/ran-network-init', 'var/lib/misc/ran-storage-init', ] + +# optional features +FEATURES_DIR = "/etc/xensource/features" +HAS_RAID_ASSEMBLE = os.path.exists(os.path.join(FEATURES_DIR, "raid-assemble")) diff --git a/doc/features.txt b/doc/features.txt new file mode 100644 index 00000000..20fabd43 --- /dev/null +++ b/doc/features.txt @@ -0,0 +1,18 @@ +Features flags +============== + +Some host-installer features are not enabled by default, and +downstream installers can activate them by creating a file in +/etc/xensource/features/ in their installer filesystem. + +Currently available feature flags are: + + raid-assemble + + Detect Linux software-RAID (a.k.a "md") superblocks in disks, adds + a choice for the user to activate software RAID volumes, and do + not offer the user the ability to upgrade or restore a system on a + software-RAID device. + + This only impacts the UI, the answerfile + construct does not need this feature flag. diff --git a/tui/installer/screens.py b/tui/installer/screens.py index e361b914..d923cf8a 100644 --- a/tui/installer/screens.py +++ b/tui/installer/screens.py @@ -229,7 +229,7 @@ def get_installation_type(answers): # RAID members, for filtering out from upgradable-products and # backups, and to decide whether to propose to activate existing RAID. raid_members = [] - if "assemble-raid" not in answers: + if constants.HAS_RAID_ASSEMBLE and "assemble-raid" not in answers: for disk in diskutil.getQualifiedDiskList(): rv, out = util.runCmd2([ 'mdadm', '--examine', disk ], with_stdout=True) if rv == 0 and re.search("Array UUID :", out): From cab52a924aa4bdee888bf77274e8f09135120c07 Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Tue, 24 Jan 2023 18:32:36 +0100 Subject: [PATCH 10/11] products discovery: don't propose to restore a backup to a disk not found This will avoid issues where users attempt to upgrade from a very old version, and a dom0 kernel driver evolution changed the /dev/disk/by-id/ identifier for the disk, and when the backup became invalid after a hardware change. Signed-off-by: Yann Dirson --- tui/installer/screens.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tui/installer/screens.py b/tui/installer/screens.py index d923cf8a..4051ba42 100644 --- a/tui/installer/screens.py +++ b/tui/installer/screens.py @@ -243,6 +243,9 @@ def get_installation_type(answers): upgradeable_products.append(x) backups = [] for b in answers['backups']: + if not os.path.exists(b.root_disk): + logger.log("%s: disk %s not found, skipping" % (b, b.root_disk)) + continue if b.root_disk in raid_members: logger.log("%s: disk %s in %s, skipping" % (b, b.root_disk, raid_members)) continue From 406503faefd56b4352a252022d42b06b46f23e03 Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Mon, 12 Dec 2022 10:44:50 +0100 Subject: [PATCH 11/11] answerfile: add support for assembling pre-existing RAID Signed-off-by: Yann Dirson --- answerfile.py | 12 ++++++++++++ doc/answerfile.txt | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/answerfile.py b/answerfile.py index 490b49ec..2dd5360e 100644 --- a/answerfile.py +++ b/answerfile.py @@ -133,6 +133,7 @@ def parseFreshInstall(self): results['preserve-settings'] = False results['backup-existing-installation'] = False + results.update(self.parseAssembleRaid()) results.update(self.parseDisks()) results.update(self.parseInterface()) results.update(self.parseRootPassword()) @@ -170,6 +171,7 @@ def parseRestore(self): results['install-type'] = INSTALL_TYPE_RESTORE + results.update(self.parseAssembleRaid()) backups = product.findXenSourceBackups() if len(backups) == 0: raise AnswerfileException("Could not locate exsisting backup.") @@ -227,6 +229,7 @@ def parseCommon(self): def parseExistingInstallation(self): results = {} + results.update(self.parseAssembleRaid()) inst = getElementsByTagName(self.top_node, ['existing-installation'], mandatory=True) disk = normalize_disk(getText(inst[0])) @@ -293,6 +296,15 @@ def parseDriverSource(self): results['extra-repos'].append((rtype, address)) return results + def parseAssembleRaid(self): + results = {} + nodes = getElementsByTagName(self.top_node, ['assemble-raid']) + if nodes: + results['assemble-raid'] = True # possibly useless + logger.log("Assembling any RAID volumes") + rv = util.runCmd2([ 'mdadm', '--assemble', "--scan" ]) + return results + def parseDisks(self): results = {} diff --git a/doc/answerfile.txt b/doc/answerfile.txt index 76221624..a4093b62 100644 --- a/doc/answerfile.txt +++ b/doc/answerfile.txt @@ -129,6 +129,15 @@ Common Elements Discovery on. + ? + + Run `mdadm --assemble --scan` before looking for the device + specified in , , or + . + + Used to be the default behavior. + + (Re)Install Elements --------------------