From a5cfe872a3ef597c9ec6fb41bd470c4b3b9168ee Mon Sep 17 00:00:00 2001 From: oddlama Date: Thu, 27 May 2021 20:35:28 +0200 Subject: [PATCH] Added zfs pool creation --- configure | 16 +++--- gentoo.conf.example | 9 ++++ install | 29 +++++------ scripts/functions.sh | 107 +++++++++++++++++++++++++++++++++-------- scripts/main.sh | 7 +-- tests/gentoo-mdadm.sh | 4 -- tests/vm-gentoo-zfs.sh | 17 +++++++ 7 files changed, 137 insertions(+), 52 deletions(-) delete mode 100644 tests/gentoo-mdadm.sh create mode 100755 tests/vm-gentoo-zfs.sh diff --git a/configure b/configure index caeaf6d..cfe312a 100755 --- a/configure +++ b/configure @@ -167,7 +167,7 @@ ALL_PARTITIONING_SCHEMES=( PARTITIONING_BOOT_TYPES=("efi" "bios") PARTITIONING_ROOT_FS_TYPES=("ext4" "btrfs") PARTITIONING_BTRFS_RAID_TYPES=("raid0" "raid1") -PARTITIONING_ZFS_POOL_TYPES=("stripe" "mirror") +PARTITIONING_ZFS_POOL_TYPES=("standard" "custom") function create_single_disk_layout() { create_classic_single_disk_layout @@ -220,7 +220,7 @@ function create_zfs_centric_layout() { PARTITIONING_DEVICES=("${extra_arguments[@]}") parse_swap "${arguments[swap]}" PARTITIONING_BOOT_TYPE="${arguments[type]}" - PARTITIONING_ZFS_POOL_TYPE="${arguments[pool_type]:-stripe}" + PARTITIONING_ZFS_POOL_TYPE="${arguments[pool_type]:-standard}" PARTITIONING_ZFS_ENCRYPTION="${arguments[encrypt]:-false}" } @@ -319,7 +319,7 @@ function load_default_config() { LOCALE="C.utf8" function disk_configuration() { - create_zfs_centric_layout swap=8GiB type=efi encrypt=true pool_type=stripe /dev/sdX + create_zfs_centric_layout swap=8GiB type=efi encrypt=true pool_type=standard /dev/sdX } SYSTEMD=true @@ -682,8 +682,8 @@ MENU_ITEMS=( "PARTITIONING_SWAP" "PARTITIONING_ROOT_FS" "PARTITIONING_USE_LUKS" - "PARTITIONING_ZFS_ENCRYPTION" "PARTITIONING_ZFS_POOL_TYPE" + "PARTITIONING_ZFS_ENCRYPTION" "PARTITIONING_BTRFS_RAID_TYPE" "PARTITIONING_DEVICE" "PARTITIONING_DEVICES" @@ -727,7 +727,7 @@ function PARTITIONING_SCHEME_menu() { # Set disk scheme case "$dialog_out" in "classic_single_disk") create_classic_single_disk_layout swap=8GiB type=efi luks=false root_fs=ext4 /dev/sdX ;; - "zfs_centric") create_zfs_centric_layout swap=8GiB type=efi encrypt=true pool_type=stripe /dev/sdX ;; + "zfs_centric") create_zfs_centric_layout swap=8GiB type=efi encrypt=true pool_type=standard /dev/sdX ;; "btrfs_centric") create_btrfs_centric_layout swap=8GiB type=efi raid_type=raid0 luks=false /dev/sdX ;; "raid0_luks") create_raid0_luks_layout swap=8GiB type=efi root_fs=ext4 /dev/sdX /dev/sdY ;; "custom") PARTITIONING_SCHEME="$dialog_out" ;; @@ -812,7 +812,7 @@ function PARTITIONING_USE_LUKS_menu() { function PARTITIONING_ZFS_ENCRYPTION_tag() { echo " ├ ZFS Encryption"; } function PARTITIONING_ZFS_ENCRYPTION_label() { on_off_label "$PARTITIONING_ZFS_ENCRYPTION" " ├ "; } -function PARTITIONING_ZFS_ENCRYPTION_show() { [[ $PARTITIONING_SCHEME != "custom" ]] && one_of "$PARTITIONING_SCHEME" "zfs_centric"; } +function PARTITIONING_ZFS_ENCRYPTION_show() { [[ $PARTITIONING_SCHEME != "custom" ]] && one_of "$PARTITIONING_SCHEME" "zfs_centric" && one_of "$PARTITIONING_ZFS_POOL_TYPE" "standard"; } function PARTITIONING_ZFS_ENCRYPTION_help() { echo "Determines if ZFS encryption will be used to encrypt your root partition."; } function PARTITIONING_ZFS_ENCRYPTION_menu() { on_off_toggle "PARTITIONING_ZFS_ENCRYPTION" @@ -822,11 +822,11 @@ function PARTITIONING_ZFS_ENCRYPTION_menu() { function PARTITIONING_ZFS_POOL_TYPE_tag() { echo " ├ Pool type"; } function PARTITIONING_ZFS_POOL_TYPE_label() { echo " ├ ($PARTITIONING_ZFS_POOL_TYPE)"; } function PARTITIONING_ZFS_POOL_TYPE_show() { [[ $PARTITIONING_SCHEME != "custom" ]] && one_of "$PARTITIONING_SCHEME" "zfs_centric"; } -function PARTITIONING_ZFS_POOL_TYPE_help() { echo "Determines the pool type of the created zfs pool (stripe / mirror)."; } +function PARTITIONING_ZFS_POOL_TYPE_help() { echo "Determines how the zfs pool will be initialized. Select 'standard' for a default pool setup that puts all given devices in one pool with ZSTD compression. Selecting 'custom' will require you to write your own pool creation function in the output config."; } function PARTITIONING_ZFS_POOL_TYPE_menu() { if menu_radiolist \ "Select ZFS pool type" \ - "Select which ZFS pool type you want to use. By default pools are striping in ZFS." \ + "Select 'standard' for a default pool setup that puts all given devices in one pool with ZSTD compression. Selecting 'custom' will require you to write your own pool creation function in the output config." \ "$PARTITIONING_ZFS_POOL_TYPE" \ "${PARTITIONING_ZFS_POOL_TYPES[@]}" then diff --git a/gentoo.conf.example b/gentoo.conf.example index aa16703..fe4d2ef 100644 --- a/gentoo.conf.example +++ b/gentoo.conf.example @@ -15,6 +15,15 @@ # # Be sure to only define one layout! +# This function will be called when a custom zfs pool type has been chosen. +# $1: either 'true' or 'false' determining if the pool should be encrypted +# $2: a string describing all device paths (for error messages) +# $@: device paths +function format_zfs_custom() { + # See format_zfs_standard() function in scripts/functions.sh for an example! + die "You need to implement format_zfs_custom() in your .conf file!" +} + function disk_configuration() { create_classic_single_disk_layout swap=8GiB type=efi luks=true root_fs=ext4 /dev/sdX diff --git a/install b/install index 50401b7..82fb39d 100755 --- a/install +++ b/install @@ -57,18 +57,17 @@ while [[ $# -gt 0 ]]; do echo "be started instead." echo "" echo "Options:" - echo " -c, --config Use the given configuration file instead of the default" - echo " location (gentoo.conf). Applies to installation as well" - echo " as initial configuration in case it doesn't exist." + echo " -c, --config Use the given configuration file instead of the default" + echo " location (gentoo.conf). Applies to installation as well" + echo " as initial configuration in case it doesn't exist." echo "" echo "Actions:" - echo " -i, --install Installs gentoo as configured. (default if configuration exists)" - echo " -R, --chroot Chroot into an existing system. The root filesystem" - echo " is mounted automatically based on the partition" - echo " UUIDs (generated when installing for the first time)," - echo " and unmounted when the chroot exits" - echo " -u, --umount Try to unmount all associated mountpoints. (Only needed" - echo " if anything gets forcefully interrupted)" + echo " -i, --install Installs gentoo as configured. This is the default mode," + echo " if the given configuration file exists." + echo " -R, --chroot [CMD...] Chroot into an existing system. The root filesystem" + echo " must already be mounted under DIR. All required special" + echo " filesystems will be mounted inside, and unmounted when" + echo " the chroot exits." exit 0 ;; "-c"|"--config") @@ -80,15 +79,14 @@ while [[ $# -gt 0 ]]; do "-R"|"--chroot") [[ -z $ACTION ]] || die "Multiple actions given" ACTION="chroot" + CHROOT_DIR="$2" + [[ -e "$CHROOT_DIR" ]] || die "Chroot directory not found: '$CHROOT_DIR'" + shift ;; "-i"|"--install") [[ -z $ACTION ]] || die "Multiple actions given" ACTION="install" ;; - "-u"|"--umount"|"--unmount") - [[ -z $ACTION ]] || die "Multiple actions given" - ACTION="umount" - ;; "__install_gentoo_in_chroot") ACTION="__install_gentoo_in_chroot" ;; @@ -127,9 +125,8 @@ preprocess_config mkdir_or_die 0755 "$TMP_DIR" case "$ACTION" in - "chroot") main_chroot "$@" ;; + "chroot") main_chroot "$CHROOT_DIR" "$@" ;; "install") main_install "$@" ;; - "umount") main_umount "$@" ;; "__install_gentoo_in_chroot") main_install_gentoo_in_chroot "$@" ;; *) die "Invalid action '$ACTION'" ;; esac diff --git a/scripts/functions.sh b/scripts/functions.sh index 908c65a..60bec50 100644 --- a/scripts/functions.sh +++ b/scripts/functions.sh @@ -372,11 +372,53 @@ function disk_format() { esac } +# This function will be called when a custom zfs pool type has been chosen. +# $1: either 'true' or 'false' determining if the pool should be encrypted +# $2: a string describing all device paths (for error messages) +# $@: device paths +function format_zfs_standard() { + local encrypt="$1" + local device_desc="$2" + shift 2 + local devices=("$@") + + einfo "Creating zfs pool on $devices_desc" + local extra_args=() + if [[ "$encrypt" == true ]]; then + extra_args+=( + "-O" "encryption=aes-256-gcm" + "-O" "keyformat=passphrase" + "-O" "keylocation=prompt" + ) + fi + + # dnodesize=legacy might be needed for GRUB2, but auto is preferred for xattr=sa. + zpool create \ + -R /mnt \ + -o ashift=12 \ + -O acltype=posix \ + -O atime=off \ + -O xattr=sa \ + -O dnodesize=auto \ + -O mountpoint=none \ + -O canmount=noauto \ + -O devices=off \ + -O compression=zstd \ + "${extra_args[@]}" \ + rpool \ + "${devices[@]}" \ + || die "Could not create zfs pool on $devices_desc" + + zfs create -o mountpoint=/ rpool/ROOT/default \ + || die "Could not create zfs default dataset" + zpool set bootfs=rpool/ROOT/default rpool \ + || die "Could not set zfs property bootfs on rpool" +} + function disk_format_zfs() { local ids="${arguments[ids]}" - local label="${arguments[label]}" local pool_type="${arguments[pool_type]}" - local encrypt="${arguments[encrypt]}" + local encrypt="${arguments[encrypt]-false}" if [[ $disk_action_summarize_only == "true" ]]; then local id # Splitting is intentional here @@ -387,6 +429,25 @@ function disk_format_zfs() { return 0 fi + local devices_desc="" + local devices=() + local id + local dev + # Splitting is intentional here + # shellcheck disable=SC2086 + for id in ${ids//';'/ }; do + dev="$(resolve_device_by_id "$id")" \ + || die "Could not resolve device with id=$id" + devices+=("$dev") + devices_desc+="$dev ($id), " + done + devices_desc="${devices_desc:0:-2}" + + if [[ "$pool_type" == "custom" ]]; then + format_zfs_custom "$encrypt" "$devices_desc" "${devices[@]}" + else + format_zfs_standard "$encrypt" "$devices_desc" "${devices[@]}" + fi } function disk_format_btrfs() { @@ -617,7 +678,11 @@ function mount_by_id() { } function mount_root() { - mount_by_id "$DISK_ID_ROOT" "$ROOT_MOUNTPOINT" + if [[ $USED_ZFS == "true" ]] && ! mountpoint -q -- "$ROOT_MOUNTPOINT"; then + die "Error: Expected zfs to be mounted under '$ROOT_MOUNTPOINT', but it isn't." + else + mount_by_id "$DISK_ID_ROOT" "$ROOT_MOUNTPOINT" + fi } function bind_repo_dir() { @@ -746,37 +811,41 @@ function touch_or_die() { chmod "$1" "$2" } +# $1: root directory +# $@: command... function gentoo_chroot() { - if [[ $# -eq 0 ]]; then - gentoo_chroot /bin/bash --init-file <(echo 'init_bash') + if [[ $# -eq 1 ]]; then + gentoo_chroot "$1" /bin/bash --init-file <(echo 'init_bash') fi [[ $EXECUTED_IN_CHROOT != "true" ]] \ || die "Already in chroot" - gentoo_umount - mount_root + local chroot_dir="$1" + shift + + # Bind repo directory to tmp bind_repo_dir # Copy resolv.conf einfo "Preparing chroot environment" - install --mode=0644 /etc/resolv.conf "$ROOT_MOUNTPOINT/etc/resolv.conf" \ + install --mode=0644 /etc/resolv.conf "$chroot_dir/etc/resolv.conf" \ || die "Could not copy resolv.conf" # Mount virtual filesystems einfo "Mounting virtual filesystems" ( - mountpoint -q -- "$ROOT_MOUNTPOINT/proc" || mount -t proc /proc "$ROOT_MOUNTPOINT/proc" || exit 1 - mountpoint -q -- "$ROOT_MOUNTPOINT/tmp" || mount --rbind /tmp "$ROOT_MOUNTPOINT/tmp" || exit 1 - mountpoint -q -- "$ROOT_MOUNTPOINT/sys" || { - mount --rbind /sys "$ROOT_MOUNTPOINT/sys" && - mount --make-rslave "$ROOT_MOUNTPOINT/sys"; } || exit 1 - mountpoint -q -- "$ROOT_MOUNTPOINT/dev" || { - mount --rbind /dev "$ROOT_MOUNTPOINT/dev" && - mount --make-rslave "$ROOT_MOUNTPOINT/dev"; } || exit 1 + mountpoint -q -- "$chroot_dir/proc" || mount -t proc /proc "$chroot_dir/proc" || exit 1 + mountpoint -q -- "$chroot_dir/tmp" || mount --rbind /tmp "$chroot_dir/tmp" || exit 1 + mountpoint -q -- "$chroot_dir/sys" || { + mount --rbind /sys "$chroot_dir/sys" && + mount --make-rslave "$chroot_dir/sys"; } || exit 1 + mountpoint -q -- "$chroot_dir/dev" || { + mount --rbind /dev "$chroot_dir/dev" && + mount --make-rslave "$chroot_dir/dev"; } || exit 1 ) || die "Could not mount virtual filesystems" - # Cache lsblk output, because apparently it doesn't work correctly in chroot (returns almost no info for devices, e.g. empty uuids) + # Cache lsblk output, because it doesn't work correctly in chroot (returns almost no info for devices, e.g. empty uuids) cache_lsblk_output # Execute command @@ -784,8 +853,8 @@ function gentoo_chroot() { EXECUTED_IN_CHROOT=true \ TMP_DIR="$TMP_DIR" \ CACHED_LSBLK_OUTPUT="$CACHED_LSBLK_OUTPUT" \ - exec chroot -- "$ROOT_MOUNTPOINT" "$GENTOO_INSTALL_REPO_DIR/scripts/dispatch_chroot.sh" "$@" \ - || die "Failed to chroot into '$ROOT_MOUNTPOINT'" + exec chroot -- "$chroot_dir" "$GENTOO_INSTALL_REPO_DIR/scripts/dispatch_chroot.sh" "$@" \ + || die "Failed to chroot into '$chroot_dir'" } function enable_service() { diff --git a/scripts/main.sh b/scripts/main.sh index 5f9c37c..69a4d7b 100644 --- a/scripts/main.sh +++ b/scripts/main.sh @@ -369,15 +369,12 @@ function main_install() { [[ $IS_EFI == "true" ]] \ && mount_efivars - gentoo_chroot "$GENTOO_INSTALL_REPO_BIND/scripts/main.sh" __install_gentoo_in_chroot + gentoo_chroot "$ROOT_MOUNTPOINT" "$GENTOO_INSTALL_REPO_BIND/scripts/main.sh" __install_gentoo_in_chroot gentoo_umount } function main_chroot() { gentoo_chroot "$@" - gentoo_umount -} - -function main_umount() { + einfo "Unmounting chroot environment" gentoo_umount } diff --git a/tests/gentoo-mdadm.sh b/tests/gentoo-mdadm.sh deleted file mode 100644 index 86d30d6..0000000 --- a/tests/gentoo-mdadm.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -# virt-install -# virsh diff --git a/tests/vm-gentoo-zfs.sh b/tests/vm-gentoo-zfs.sh new file mode 100755 index 0000000..f446e5a --- /dev/null +++ b/tests/vm-gentoo-zfs.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +virt-install \ + --connect=qemu:///system \ + --name=vm-gentoo-zfs \ + --vcpus=2 \ + --memory=2048 \ + --cdrom=/vm/images/archlinux-2021.05.01-x86_64.iso \ + --disk path=/vm/disks/disk-vm-gentoo-zfs.disk,size=25 \ + --graphics none \ + --console pty,target.type=virtio \ + --serial pty \ + --extra-args 'console=ttyS0,115200n8 --- console=ttyS0,115200n8' \ + --os-variant=gentoo \ + --noautoconsole + +# virsh