mirror of
https://github.com/NiklasGollenstede/nixos-installer.git
synced 2025-08-08 23:21:28 +02:00
add --skip-formatting flag,
open debug shells with variables+functions
This commit is contained in:
@ -3,22 +3,36 @@
|
||||
# Disk Partitioning and Formatting
|
||||
##
|
||||
|
||||
declare-flag install-system skip-formatting "" "Skip partitioning, formatting, and their post-commands. Instead, assume that all required disks/images/zpools are correctly partitioned/formatted, and simply (unlock/import and) mount them. This is useful to skip the destruktive part of the installation, but still do the (largely idempotent) part of copying and linking the current system generation and installing the bootloader -- i.e, repair an installation."
|
||||
|
||||
## Prepares the disks of the target system for the copying of files.
|
||||
function do-disk-setup { # 1: diskPaths
|
||||
|
||||
ensure-disks "$1" || return
|
||||
prompt-for-user-passwords || return
|
||||
populate-keystore || return
|
||||
|
||||
mnt=/tmp/nixos-install-@{config.networking.hostName} && mkdir -p "$mnt" && prepend_trap "rmdir $mnt" EXIT || return # »mnt=/run/user/0/...« would be more appropriate, but »nixos-install« does not like the »700« permissions on »/run/user/0«
|
||||
export mnt=/tmp/nixos-install-@{config.networking.hostName} && mkdir -p "$mnt" && prepend_trap "rmdir $mnt" EXIT || return # »mnt=/run/user/0/...« would be more appropriate, but »nixos-install« does not like the »700« permissions on »/run/user/0«
|
||||
|
||||
partition-disks || return
|
||||
create-luks-layers && open-luks-layers || return # other block layers would go here too (but figuring out their dependencies would be difficult)
|
||||
run-hook-script 'Post Partitioning' @{config.installer.commands.postPartition!writeText.postPartitionCommands} || return
|
||||
if [[ ${args[skip-formatting]:-} ]] ; then
|
||||
if [[ @{config.setup.keystore.enable} ]] ; then
|
||||
mount-keystore-luks-primary || return
|
||||
else
|
||||
populate-keystore || return # (this may be insufficient)
|
||||
fi
|
||||
open-luks-layers || return
|
||||
if [[ $(LC_ALL=C type -t import-zpools) == function ]] ; then import-zpools $mnt || return ; fi
|
||||
else
|
||||
populate-keystore || return
|
||||
partition-disks || return
|
||||
create-luks-layers || return
|
||||
open-luks-layers || return
|
||||
# other block layers would go here too (but figuring out their dependencies would be difficult)
|
||||
run-hook-script 'Post Partitioning' @{config.installer.commands.postPartition!writeText.postPartitionCommands} || return
|
||||
|
||||
format-partitions || return
|
||||
if [[ $(LC_ALL=C type -t create-zpools) == function ]] ; then create-zpools $mnt || return ; fi
|
||||
run-hook-script 'Post Formatting' @{config.installer.commands.postFormat!writeText.postFormatCommands} || return
|
||||
format-partitions || return
|
||||
if [[ $(LC_ALL=C type -t create-zpools) == function ]] ; then create-zpools $mnt || return ; fi
|
||||
run-hook-script 'Post Formatting' @{config.installer.commands.postFormat!writeText.postFormatCommands} || return
|
||||
fi
|
||||
|
||||
fix-grub-install || return
|
||||
|
||||
@ -52,7 +66,7 @@ function ensure-disks { # 1: diskPaths, 2?: skipLosetup
|
||||
fi
|
||||
|
||||
local name ; for name in "@{!config.setup.disks.devices[@]}" ; do
|
||||
if [[ ! @{config.setup.disks.devices!catAttrSets.partitionDuringInstallation[$name]} ]] ; then continue ; fi
|
||||
if [[ ! @{config.setup.disks.devices!catAttrSets.partitionDuringInstallation[$name]} ]] ; then unset blockDevs[$name] ; continue ; fi
|
||||
if [[ ! ${blockDevs[$name]:-} ]] ; then echo "Path for block device $name not provided" 1>&2 ; \return 1 ; fi
|
||||
eval 'local -A disk='"@{config.setup.disks.devices[$name]}"
|
||||
if [[ ${blockDevs[$name]} != /dev/* ]] ; then
|
||||
|
@ -103,7 +103,7 @@ function reexec-in-qemu {
|
||||
echo 'Performing the installation in a cross-ISA qemu system VM; this will be very, very slow (many hours) ...'
|
||||
output=@{inputs.self}'#'nixosConfigurations.@{config.installer.outputName:?}.config.system.build.vmExec-@{pkgs.buildPackages.system}
|
||||
fi
|
||||
local scripts=$0 ; if [[ @{pkgs.system} != "@{native.system}" ]] ; then
|
||||
local scripts=$self ; if [[ @{pkgs.system} != "@{native.system}" ]] ; then
|
||||
scripts=$( build-lazy @{inputs.self}'#'apps.@{pkgs.system}.@{config.installer.outputName:?}.derivation ) || return
|
||||
fi
|
||||
local command="$scripts install-system $( printf '%q ' "${newArgs[@]}" ) || exit"
|
||||
@ -129,7 +129,7 @@ declare-flag install-system toplevel "" "Optional replacement for the actual »c
|
||||
declare-flag install-system no-inspect "" "Do not inspect the (successfully) installed system before unmounting its filesystems."
|
||||
declare-flag install-system inspect-cmd "script" "Instead of opening an interactive shell for the post-installation inspection, »eval« this script."
|
||||
|
||||
## Copies the system's dependencies to the disks mounted at »$mnt« and installs the bootloader. If »$inspect« is set, a root shell will be opened in »$mnt« afterwards.
|
||||
## Copies the system's dependencies to the disks mounted at »$mnt« and installs the bootloader. By default, a root shell will be opened in »$mnt« afterwards.
|
||||
# »$topLevel« may point to an alternative top-level dependency to install.
|
||||
function install-system-to {( set -u # 1: mnt, 2?: topLevel
|
||||
targetSystem=${args[toplevel]:-@{config.system.build.toplevel}}
|
||||
@ -200,7 +200,7 @@ function install-system-to {( set -u # 1: mnt, 2?: topLevel
|
||||
else
|
||||
( set +x ; echo "[1;32mInstallation done![0m This shell is in a chroot in the mounted system for inspection. Exiting the shell will unmount the system." 1>&2 )
|
||||
fi
|
||||
LC_ALL=C PATH=$PATH:@{native.util-linux}/bin @{native.nixos-install-tools}/bin/nixos-enter --root $mnt -- /nix/var/nix/profiles/system/sw/bin/bash -c 'source /etc/set-environment ; exec bash --login' || exit # +o monitor
|
||||
LC_ALL=C PATH=$PATH:@{native.util-linux}/bin @{native.nixos-install-tools}/bin/nixos-enter --root $mnt -- /nix/var/nix/profiles/system/sw/bin/bash -c 'source /etc/set-environment ; CHROOT_DIR="'"$mnt"'" mnt=/ exec "'"$self"'" bash' || exit # +o monitor
|
||||
fi
|
||||
|
||||
mkdir -p $mnt/var/lib/systemd/timesync && touch $mnt/var/lib/systemd/timesync/clock || true # save current time
|
||||
|
@ -161,7 +161,7 @@ function run-qemu {
|
||||
done ; fi
|
||||
if [[ ${args[install]:-} == always ]] ; then
|
||||
local verbosity=--quiet ; if [[ ${args[trace]:-} ]] ; then verbosity=--trace ; fi ; if [[ ${args[debug]:-} ]] ; then verbosity=--debug ; fi
|
||||
hostPath=${hostPath:-} ${args[dry-run]:+echo} $0 install-system "$diskImages" $verbosity --no-inspect || return
|
||||
hostPath=${hostPath:-} ${args[dry-run]:+echo} "$self" install-system "$diskImages" $verbosity --no-inspect || return
|
||||
fi
|
||||
|
||||
qemu+=( "${argv[@]}" )
|
||||
@ -198,6 +198,18 @@ function mount-keystore-luks {
|
||||
@{native.util-linux}/bin/mount -o nodev,umask=0077,fmask=0077,dmask=0077,ro /dev/mapper/$keystore /run/$keystore && prepend_trap "@{native.util-linux}/bin/umount /run/$keystore" EXIT || return
|
||||
}
|
||||
|
||||
## Opens the keystore with the primary unlock method, which may not be convenient to use, but should always be defined.
|
||||
function mount-keystore-luks-primary {
|
||||
local usage=luks/keystore-@{config.networking.hostName!hashString.sha256:0:8}/0
|
||||
local method=@{config.setup.keystore.keys[$usage]%%=*}
|
||||
local options=@{config.setup.keystore.keys[$usage]:$(( ${#method} + 1 ))}
|
||||
|
||||
local attempt ; for attempt in 2 3 x ; do
|
||||
if mount-keystore-luks --key-file=<( gen-key-"$method" "$usage" "$options" ) ; then break ; fi
|
||||
if [[ $attempt == x ]] ; then \return 1 ; fi ; echo "Retrying ($attempt/3):"
|
||||
done
|
||||
}
|
||||
|
||||
declare-command open-system diskImages << 'EOD'
|
||||
Performs any steps necessary to mount the target system at »/tmp/nixos-install-@{config.networking.hostName}« on the current host.
|
||||
For any steps taken, it also adds the steps to undo them on exit from the calling shell (so this is not useful as a standalone »COMMAND«, use the »bash« or »--command« options, and don't call this from a sub-shell that exits too early).
|
||||
@ -220,27 +232,19 @@ function open-system {
|
||||
@{native.systemd}/bin/udevadm settle -t 15 || true # sometimes partitions aren't quite made available yet
|
||||
|
||||
if [[ @{config.setup.keystore.enable} && ! -e /dev/mapper/keystore-@{config.networking.hostName!hashString.sha256:0:8} ]] ; then # Try a bunch of approaches for opening the keystore:
|
||||
mount-keystore-luks --key-file=<( printf %s "@{config.networking.hostName}" ) || return
|
||||
mount-keystore-luks --key-file=/dev/disk/by-partlabel/bootkey-@{config.networking.hostName!hashString.sha256:0:8} || return
|
||||
mount-keystore-luks --key-file=<( read -s -p PIN: pin && echo ' touch!' >&2 && @{native.yubikey-personalization}/bin/ykchalresp -2 "$pin" ) || return
|
||||
# TODO: try static yubikey challenge
|
||||
mount-keystore-luks || return
|
||||
mount-keystore-luks --key-file=<( printf %s "@{config.networking.hostName}" ) || # costs nothing to try
|
||||
mount-keystore-luks --key-file=/dev/disk/by-partlabel/bootkey-@{config.networking.hostName!hashString.sha256:0:8} || # costs nothing to try
|
||||
mount-keystore-luks-primary || # should always be applicable
|
||||
mount-keystore-luks --key-file=<( read -s -p PIN: pin && echo ' touch!' >&2 && @{native.yubikey-personalization}/bin/ykchalresp -2 "$pin" ) ||
|
||||
mount-keystore-luks || # (getting desperate)
|
||||
return # oh well
|
||||
fi
|
||||
|
||||
mnt=/tmp/nixos-install-@{config.networking.hostName} # allow this to leak into the calling scope
|
||||
export mnt=/tmp/nixos-install-@{config.networking.hostName} # allow this to leak into the calling scope
|
||||
if [[ ! -e $mnt ]] ; then mkdir -p "$mnt" && prepend_trap "rmdir '$mnt'" EXIT || return ; fi
|
||||
|
||||
open-luks-layers || return # Load crypt layers and zfs pools:
|
||||
if [[ $( LC_ALL=C type -t ensure-datasets ) == 'function' ]] ; then
|
||||
local poolName ; for poolName in "@{!config.setup.zfs.pools[@]}" ; do
|
||||
if [[ ! @{config.setup.zfs.pools!catAttrSets.createDuringInstallation[$poolName]} ]] ; then continue ; fi
|
||||
if ! @{native.zfs}/bin/zfs get -o value -H name "$poolName" &>/dev/null ; then
|
||||
@{native.zfs}/bin/zpool import -f -N -R "$mnt" "$poolName" && prepend_trap "@{native.zfs}/bin/zpool export '$poolName'" EXIT || return
|
||||
fi
|
||||
: | @{native.zfs}/bin/zfs load-key -r "$poolName" || true
|
||||
ensure-datasets "$mnt" '^'"$poolName"'($|[/])' || return
|
||||
done
|
||||
fi
|
||||
if [[ $( LC_ALL=C type -t import-zpools ) == 'function' ]] ; then import-zpools "$mnt" skipImported ; fi
|
||||
|
||||
prepend_trap "unmount-system '$mnt'" EXIT && mount-system "$mnt" '' 1 || return
|
||||
df -h | grep $mnt | cat
|
||||
|
@ -79,7 +79,7 @@ function copy-function { # 1: existingName, 2: newName
|
||||
function mkdir-sticky { # 1: path, 2?: fallbackOwner, 3?: fallbackGroup, 4?: fallbackMode
|
||||
local path ; path=$1 ; shift
|
||||
if [[ -d $path ]] ; then return ; fi # existing (symlink to existing) dir
|
||||
if [[ -L $path || -e $path ]] ; then echo "Can't create (child of) existing file (or broken symlink) '$path'" 1>&2 ; return 1 ; fi
|
||||
if [[ -L $path || -e $path ]] ; then echo "Can't create (child of) existing file (or broken symlink) '$path'" 1>&2 ; \return 1 ; fi
|
||||
local parent ; parent=$( dirname "$path" ) || return
|
||||
mkdir-sticky "$parent" "$@" || return
|
||||
parent=$( realpath "$parent" ) || return
|
||||
|
@ -7,11 +7,23 @@ function create-zpools { # 1: mnt
|
||||
done
|
||||
}
|
||||
|
||||
## Imports all of the system's ZFS pools that are »createDuringInstallation« and not imported yet.
|
||||
function import-zpools { # 1: mnt, 2: skipImported
|
||||
local mnt=$1 ; local skipImported=${2:-}
|
||||
local poolName ; for poolName in "@{!config.setup.zfs.pools[@]}" ; do
|
||||
if [[ ! @{config.setup.zfs.pools!catAttrSets.createDuringInstallation[$poolName]} ]] ; then continue ; fi
|
||||
if @{native.zfs}/bin/zfs get -o value -H name "$poolName" &>/dev/null && [[ $skipImported ]] ; then continue ; fi
|
||||
@{native.zfs}/bin/zpool import -f -N -R "$mnt" "$poolName" && prepend_trap "@{native.zfs}/bin/zpool export '$poolName'" EXIT || return
|
||||
: | @{native.zfs}/bin/zfs load-key -r "$poolName" || true
|
||||
ensure-datasets "$mnt" '^'"$poolName"'($|[/])' || return
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
declare-command create-zpool mnt poolName << 'EOD'
|
||||
Creates a single of the system's ZFS pools, and its datasets. Can be called manually to create pools that were added to the configuration, or to create those declared with »createDuringInstallation = false«. Expects the backing device(-partition)s to exist as declared for the pool.
|
||||
EOD
|
||||
declare-flag install-system zpool-force "" "(create-zpool) When creating ZFS storage pools, pass the »-f« (force) option. This may be required when installing to disks that are currently part of a pool, or ZFS refuses do reuse them."
|
||||
declare-flag install-system,create-zpool zpool-force "" "When creating ZFS storage pools, pass the »-f« (force) option. This may be required when installing to disks that are currently part of a pool, or ZFS refuses do reuse them."
|
||||
function create-zpool {
|
||||
local mnt=$1 ; local poolName=$2
|
||||
eval 'local -A pool='"@{config.setup.zfs.pools[$poolName]}"
|
||||
@ -67,7 +79,8 @@ function ensure-datasets {
|
||||
if $zfs get -o value -H name "${dataset[name]}" &>/dev/null ; then # dataset exists: check its properties
|
||||
|
||||
if [[ ${props[mountpoint]:-} ]] ; then # don't set the current mount point again (no-op), cuz that fails if the dataset is mounted
|
||||
local current=$($zfs get -o value -H mountpoint "${dataset[name]}") ; current=${current/$mnt/}
|
||||
# (The behavior inside a (nixos-enter) chroot is quite odd: ZFS ignores the chroot when printing the mountpoint, but heeds it when setting it. So this test fails (if the CHROOT_DIR is not set), but the set operation still sets the correct value.)
|
||||
local current=$($zfs get -o value -H mountpoint "${dataset[name]}") ; current=${current/${CHROOT_DIR:-}$mnt/}
|
||||
if [[ ${props[mountpoint]} == "${current:-/}" ]] ; then unset props[mountpoint] ; fi
|
||||
fi
|
||||
if [[ ${props[keyformat]:-} == ephemeral ]] ; then
|
||||
|
Reference in New Issue
Block a user