diff options
-rwxr-xr-x | bin/disk_stress_ng | 43 | ||||
-rwxr-xr-x | bin/efi-pxeboot | 149 | ||||
-rw-r--r-- | jobs/miscellanea.txt.in | 14 |
3 files changed, 201 insertions, 5 deletions
diff --git a/bin/disk_stress_ng b/bin/disk_stress_ng index 8445488..802d116 100755 --- a/bin/disk_stress_ng +++ b/bin/disk_stress_ng @@ -63,11 +63,40 @@ get_params() { } # get_params() -# Find the largest partition that holds a supported filesystem on $disk_device. +# Find the largest logical volume in an LVM partition. # Output: # $largest_part -- Device filename of largest qualifying partition # $largest_size -- Size of largest qualifying partition # $largest_fs -- Filesystem (ext4, etc.) used on largest qualifying partition +# Note: Above variables are initialized in find_largest_partition(), which +# calls this function. +# Caveat: If LVM is used, there can be no guarantee that a specific disk +# device is actually being tested. Thus, an LVM configuration should span +# just one disk device. LVM may be used on one disk, but subsequent disks +# should use "raw" partitions. +find_largest_lv() { + local partonly=$(echo $partition | cut -f 3 -d "/") + for syslv in $(ls -d /sys/block/dm-*/slaves/$partonly) ; do + lv=$(echo "$syslv" | cut -f 4 -d "/") + size=$(cat /sys/block/$lv/size) + sector_size=$(cat /sys/block/$lv/queue/hw_sector_size) + let size=$size*$sector_size + local blkid_info=$(blkid -s TYPE /dev/$lv | grep -E ext2\|ext3\|ext4\|xfs\|jfs\|btrfs) + if [ "$size" -gt "$largest_size" ] && [ -n "$blkid_info" ] ; then + local blkid_info=$(blkid -s TYPE /dev/$lv) + largest_size=$size + largest_part="/dev/$lv" + largest_fs=$(blkid -s TYPE "/dev/$lv" | cut -d "=" -f 2) + fi + done +} # find_largest_lv() + + +# Find the largest partition that holds a supported filesystem on $disk_device. +# Output: +# $largest_part -- Device filename of largest qualifying partition or logical volume +# $largest_size -- Size of largest qualifying partition or logical volume +# $largest_fs -- Filesystem (ext4, etc.) used on largest qualifying partition or logicl volume # $unsupported_fs -- Empty or contains name of unsupported filesystem found on disk find_largest_partition() { largest_part="" @@ -76,11 +105,15 @@ find_largest_partition() { unsupported_fs="" for partition in $(echo "$partitions" | cut -d " " -f 1) ; do part_size=$(echo "$partitions" | grep "$partition " | cut -d " " -f 2) - local blkid_info=$(blkid -s TYPE /dev/$partition | grep -E ext2\|ext3\|ext4\|xfs\|jfs\|btrfs) + local blkid_info=$(blkid -s TYPE /dev/$partition | grep -E ext2\|ext3\|ext4\|xfs\|jfs\|btrfs\|LVM2_member) if [ "$part_size" -gt "$largest_size" ] && [ -n "$blkid_info" ] ; then - largest_size=$part_size - largest_part="/dev/$partition" - largest_fs=$(blkid -s TYPE "/dev/$partition" | cut -d "=" -f 2) + if [[ "$blkid_info" =~ .*LVM2_member.* ]] ; then + find_largest_lv + else + largest_size=$part_size + largest_part="/dev/$partition" + largest_fs=$(blkid -s TYPE "/dev/$partition" | cut -d "=" -f 2) + fi fi local blkid_info=$(blkid -s TYPE /dev/$partition | grep -E ntfs\|vfat\|hfs) if [ -n "$blkid_info" ] ; then diff --git a/bin/efi-pxeboot b/bin/efi-pxeboot new file mode 100755 index 0000000..724fefb --- /dev/null +++ b/bin/efi-pxeboot @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 + +""" +Script to test that the system PXE-booted, if run in EFI mode + +Copyright (c) 2016 Canonical Ltd. + +Authors + Rod Smith <rod.smith@canonical.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License version 3, +as published by the Free Software Foundation. + +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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +The purpose of this script is to identify whether an EFI-based +system booted from the network (test passes) or from a local disk +(test fails). + +Usage: + efi-pxeboot +""" + +import os +import shlex +import shutil +import sys + +from subprocess import Popen, PIPE + + +def discover_data(): + """Extract boot entry and boot order information. + + :returns: + boot_entries, boot_order, boot_current + """ + command = "efibootmgr -v" + bootinfo_bytes = (Popen(shlex.split(command), stdout=PIPE) + .communicate()[0]) + bootinfo = (bootinfo_bytes.decode(encoding="utf-8", errors="ignore") + .splitlines()) + boot_entries = {} + boot_order = [] + if len(bootinfo) > 1: + for s in bootinfo: + if "BootOrder" in s: + try: + boot_order = s.split(":")[1].replace(" ", "").split(",") + except IndexError: + pass + elif "BootCurrent" in s: + try: + boot_current = s.split(":")[1].strip() + except IndexError: + pass + else: + # On Boot#### lines, #### is characters 4-8.... + hex_value = s[4:8] + # ....and the description starts at character 10 + name = s[10:] + try: + # In normal efibootmgr output, only Boot#### entries + # have characters 4-8 that can be interpreted as + # hex values, so this will harmlessly error out on all + # but Boot#### entries.... + int(hex_value, 16) + boot_entries[hex_value] = name + except ValueError: + pass + return boot_entries, boot_order, boot_current + + +def is_pxe_booted(boot_entries, boot_order, boot_current): + retval = 0 + desc = boot_entries[boot_current] + print("The current boot item is {}".format(boot_current)) + print("The first BootOrder item is {}".format(boot_order[0])) + print("The description of Boot{} is '{}'".format(boot_current, desc)) + if boot_current != boot_order[0]: + # If the BootCurrent entry isn't the same as the first of the + # BootOrder entries, then something is causing the first boot entry + # to fail or be bypassed. This could be a Secure Boot failure, manual + # intervention, a bad boot entry, etc. This is not necessarily a + # problem, but warn of it anyhow.... + desc2 = boot_entries[boot_order[0]] + print("The description of Boot{} is '{}'".format(boot_order[0], desc2)) + print("WARNING: The system is booted using Boot{}, but the first". + format(boot_current)) + print("boot item is Boot{}!".format(boot_order[0])) + if "Network" in desc or "PXE" in desc or "NIC" in desc \ + or "Ethernet" in desc or "IP4" in desc or "IP6" in desc: + # These strings are present in network-boot descriptions. + print("The system seems to have PXE-booted; all OK.") + elif "ubuntu" in desc or "grub" in desc or "shim" in desc or "rEFInd" \ + or "refind_" in desc: + # This string indicates a boot directly from the normal Ubuntu GRUB + # or rEFInd installation on the hard disk. + print("The system seems to have booted directly from the hard disk!") + retval = 1 + elif "SATA" in desc or "Sata" in desc or "Hard Drive" in desc: + # These strings indicate booting with a "generic" disk entry (one + # that uses the fallback filename, EFI/BOOT/bootx64.efi or similar). + print("The system seems to have booted from a disk with the fallback " + "boot loader!") + retval = 1 + else: + # Probably a rare description. Call it an error so we can flag it and + # improve this script. + print("Unable to identify boot path.") + retval = 1 + return retval + + +def main(): + """Check to see if the system PXE-booted.""" + + if shutil.which("efibootmgr") is None: + print("The efibootmgr utility is not installed; exiting!") + return(4) + if not os.geteuid() == 0: + print("This program must be run as root (or via sudo); exiting!") + return(4) + + retval = 0 + boot_entries, boot_order, boot_current = discover_data() + if boot_entries == {}: + print("No EFI boot entries are available. This may indicate a " + "firmware problem.") + retval = 2 + if boot_order == []: + print("The EFI BootOrder variable is not available. This may " + "indicate a firmware") + print("problem.") + retval = 3 + if (retval == 0): + retval = is_pxe_booted(boot_entries, boot_order, boot_current) + return(retval) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/jobs/miscellanea.txt.in b/jobs/miscellanea.txt.in index b5544c2..e018be5 100644 --- a/jobs/miscellanea.txt.in +++ b/jobs/miscellanea.txt.in @@ -132,6 +132,20 @@ command: boot_mode_test secureboot plugin: shell category_id: 2013.com.canonical.plainbox::miscellanea +estimated_duration: 0.5 +user: root +id: miscellanea/efi_pxeboot +requires: + cpuinfo.platform in ("i386", "x86_64", "aarch64") +depends: miscellanea/efi_boot_mode +_summary: Test that system booted from the network +_description: + Test to verify that the system booted from the network. + Works only on EFI-based systems. +command: efi-pxeboot + +plugin: shell +category_id: 2013.com.canonical.plainbox::miscellanea id: miscellanea/bmc_info requires: package.name == 'ipmitool' |