mirror of
https://github.com/NiklasGollenstede/nixos-installer.git
synced 2024-11-21 15:33:21 +01:00
add --skip-formatting flag,
open debug shells with variables+functions
This commit is contained in:
parent
41c75410e1
commit
b2cbacc21e
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -59,6 +59,7 @@
|
||||
"extra_isize", // ext4 option
|
||||
"fdisk", // program
|
||||
"fetchurl", // nix function
|
||||
"fido2", // protocol
|
||||
"filesystems", // plural
|
||||
"fmask", // mount
|
||||
"foldl", // nix (fold left)
|
||||
@ -203,5 +204,6 @@
|
||||
"yubikey", // program
|
||||
"YubiKeys", // plural
|
||||
"zfsutil", // program / function
|
||||
"zpool", "zpools", // zfs
|
||||
],
|
||||
}
|
||||
|
BIN
flake.lock
BIN
flake.lock
Binary file not shown.
@ -36,7 +36,7 @@ in rec {
|
||||
{ networking.hostName = name; }
|
||||
]; _file = "${dirname}/nixos.nix#modules"; } ];
|
||||
|
||||
extraModules = (nixosArgs.extraModules or [ ]) ++ modules ++ extraModules ++ [ ({ config, ... }: { imports = [ ({
|
||||
extraModules = (nixosArgs.extraModules or [ ]) ++ modules ++ extraModules ++ [ { imports = [ (args: {
|
||||
# These are passed as »extraModules« module argument and can thus be reused when defining containers and such (so define as much stuff as possible here).
|
||||
# There is, unfortunately, no way to directly pass modules into all containers. Each container will need to be defined with »config.containers."${name}".config.imports = extraModules«.
|
||||
# (One could do that automatically by defining »options.security.containers = lib.mkOption { type = lib.types.submodule (cfg: { options.config = lib.mkOption { apply = _:_.extendModules { modules = extraModules; }; }); }«.)
|
||||
@ -47,7 +47,7 @@ in rec {
|
||||
|
||||
system.nixos.revision = lib.mkIf (inputs?nixpkgs.rev) inputs.nixpkgs.rev; # (evaluating the default value fails under some circumstances)
|
||||
|
||||
}) ]; _file = "${dirname}/nixos.nix#mkNixosConfiguration-extraModule"; }) ];
|
||||
}) ]; _file = "${dirname}/nixos.nix#mkNixosConfiguration-extraModule"; } ];
|
||||
|
||||
specialArgs = (nixosArgs.specialArgs or { }) // { inherit inputs; };
|
||||
# (This is already set during module import, while »_module.args« only becomes available during module evaluation (before that, using it causes infinite recursion). Since it can't be ensured that this is set in every circumstance where »extraModules« are being used, it should generally not be used to set custom arguments.)
|
||||
@ -77,7 +77,7 @@ in rec {
|
||||
inherit name mainModule;
|
||||
moduleArgs = (moduleArgs // { inherit preface; });
|
||||
nixosArgs = (args.nixosArgs or { }) // { specialArgs = (args.nixosArgs.specialArgs or { }) // { inherit preface; }; }; # make this available early, and only for the main evaluation (+specialisations, -containers)
|
||||
extraModules = (args.extraModules or [ ]) ++ [ { imports = [ ({
|
||||
extraModules = (args.extraModules or [ ]) ++ [ { imports = [ (args: {
|
||||
options.${preface'} = {
|
||||
instances = lib.mkOption { description = "List of host names to instantiate this host config for, instead of just for the file name."; type = lib.types.listOf lib.types.str; readOnly = true; } // (lib.optionalAttrs (!preface?instances) { default = instances; });
|
||||
id = lib.mkOption { description = "This system's ID. If set, »mkSystemsFlake« will ensure that the ID is unique among all »moduleArgs.nodes«."; type = lib.types.nullOr (lib.types.either lib.types.int lib.types.str); readOnly = true; apply = id: if id == null then null else toString id; } // (lib.optionalAttrs (!preface?id) { default = null; });
|
||||
@ -171,7 +171,7 @@ in rec {
|
||||
description = ''
|
||||
Call per-host setup and maintenance commands. Most importantly, »install-system«.
|
||||
'';
|
||||
ownPath = if (system.config.${installer}.outputName != null) then "nix run REPO#${system.config.${installer}.outputName} --" else "$0";
|
||||
ownPath = if (system.config.${installer}.outputName != null) then "nix run REPO#${system.config.${installer}.outputName} --" else builtins.placeholder "out";
|
||||
usageLine = ''
|
||||
Usage:
|
||||
%s [sudo] [bash] [--FLAG[=value]]... [--] [COMMAND [ARG]...]
|
||||
@ -207,13 +207,14 @@ in rec {
|
||||
tools = lib.unique (map (p: p.outPath) (lib.filter lib.isDerivation pkgs.stdenv.allowedRequisites));
|
||||
esc = lib.escapeShellArg;
|
||||
in pkgs.writeShellScript "scripts-${name}" ''
|
||||
self=${builtins.placeholder "out"}
|
||||
|
||||
# if first arg is »sudo«, re-execute this script with sudo (as root)
|
||||
if [[ ''${1:-} == sudo ]] ; then shift ; exec sudo --preserve-env=SSH_AUTH_SOCK -- "$0" "$@" ; fi
|
||||
if [[ ''${1:-} == sudo ]] ; then shift ; exec sudo --preserve-env=SSH_AUTH_SOCK -- "$self" "$@" ; fi
|
||||
|
||||
# if the (now) first arg is »bash« or there are no args, re-execute this script as bash »--init-file«, starting an interactive bash in the context of the script
|
||||
if [[ ''${1:-} == bash ]] || [[ $# == 0 && $0 != ${pkgs.bashInteractive}/bin/bash ]] ; then
|
||||
shift ; exec ${pkgs.bashInteractive}/bin/bash --init-file <(cat << "EOS"${"\n"+''
|
||||
shift ; exec ${pkgs.bashInteractive}/bin/bash --init-file <(echo '
|
||||
# prefix the script to also include the default init files
|
||||
! [[ -e /etc/profile ]] || . /etc/profile
|
||||
for file in ~/.bash_profile ~/.bash_login ~/.profile ; do
|
||||
@ -222,8 +223,9 @@ in rec {
|
||||
|
||||
# add active »hostName« to shell prompt
|
||||
PS1=''${PS1/\\$/\\[\\e[93m\\](${name})\\[\\e[97m\\]\\$}
|
||||
''}EOS
|
||||
cat $0) -i -s ':' "$@"
|
||||
|
||||
source "'"$self"'" ; PATH=$hostPath
|
||||
') -i -s ':' "$@"
|
||||
fi
|
||||
|
||||
# provide installer tools (not necessarily for system.pkgs.config.hostPlatform)
|
||||
@ -238,19 +240,18 @@ in rec {
|
||||
shopt -s expand_aliases # enable aliases in non-interactive bash
|
||||
for control in return exit ; do alias $control='{
|
||||
status=$? ; if ! (( status )) ; then '$control' 0 ; fi # control flow return
|
||||
if ! ${pkgs.bashInteractive}/bin/bash --init-file ${system.config.environment.etc.bashrc.source} ; then '$control' $status ; fi # »|| '$control'« as an error-catch
|
||||
if ! PATH=$hostPath "$self" bash ; then '$control' $status ; fi # »|| '$control'« as an error-catch
|
||||
#if ! ${pkgs.bashInteractive}/bin/bash --init-file ${system.config.environment.etc.bashrc.source} ; then '$control' $status ; fi # »|| '$control'« as an error-catch
|
||||
}' ; done
|
||||
fi
|
||||
|
||||
declare -g -A allowedArgs=( ) allowedArgCtx=( ) ; function declare-flag { # 1: context, 2: name, 3?: value, 4: description
|
||||
if [[ ''${allowedArgCtx[$2]:-} && ''${allowedArgCtx[$2]:-} != "$1" ]] ; then echo "Flag $2 was declared in conflicting contexts ''${allowedArgCtx[$2]} and $1" >&2 ; \exit 1 ; fi
|
||||
allowedArgCtx[$2]=$1
|
||||
declare -g -A allowedArgs=( ) ; function declare-flag { # 1: context, 2: name, 3?: value, 4: description
|
||||
local name=--$2 ; if [[ $3 ]]; then name+='='$3 ; fi ; allowedArgs[$name]="($1) $4"
|
||||
}
|
||||
declare-flag global command "" 'Interpret the first positional argument as bash script (instead of the name of a single command) and »eval« it (with access to all commands and internal functions and variables).'
|
||||
declare-flag global debug "" 'Hook into any »|| exit« / »|| return« statements and open a shell if they are triggered by an error. Implies »--trace«.'
|
||||
declare-flag global trace "" "Turn on bash's »errtrace« option before running »COMMAND«."
|
||||
declare-flag global quiet "" "Try to suppress all non-error output. May also swallow some error related output."
|
||||
declare-flag '*' command "" 'Interpret the first positional argument as bash script (instead of the name of a single command) and »eval« it (with access to all commands and internal functions and variables).'
|
||||
declare-flag '*' debug "" 'Hook into any »|| exit« / »|| return« statements and open a shell if they are triggered by an error. Implies »--trace«.'
|
||||
declare-flag '*' trace "" "Turn on bash's »errtrace« option before running »COMMAND«."
|
||||
declare-flag '*' quiet "" "Try to suppress all non-error output. May also swallow some error related output."
|
||||
declare -g -A allowedCommands=( ) ; function declare-command { allowedCommands[$@]=$(< /dev/stdin) ; }
|
||||
${system.config.${installer}.build.scripts { native = pkgs; }}
|
||||
if [[ ''${args[help]:-} ]] ; then (
|
||||
|
@ -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
|
||||
|
@ -71,7 +71,7 @@ in {
|
||||
|
||||
system.boot.loader.id = "extlinux";
|
||||
system.build.installBootLoader = "${pkgs.writeShellScript "install-extlinux.sh" ''
|
||||
if [[ ! ''${1:-} || $1 != /nix/store/* ]] ; then echo "Usage: $0 TOPLEVEL_PATH" 1>&2 ; exit 1 ; fi
|
||||
if [[ ! ''${1:-} || $1 != /nix/store/* ]] ; then echo "Usage: ${builtins.placeholder "out"} TOPLEVEL_PATH" 1>&2 ; exit 1 ; fi
|
||||
export PATH=$PATH:${pkgs.stdenv}/bin
|
||||
${extlinux-conf-builder} "$1" -d ${esc cfg.targetDir}
|
||||
|
||||
|
@ -12,9 +12,9 @@ The default functions in [`lib/setup-scripts`](../../lib/setup-scripts/README.md
|
||||
What keys are used for is derived from the attribute name in the `.keys` specification, which (plus a `.key` suffix) also becomes their storage path in the keystore:
|
||||
* Keys in `luks/` are used for LUKS devices, where the second path label is both the target device name and source device GPT partition label, and the third and final label is the LUKS key slot (`0` is required to be specified, `1` to `7` are optional).
|
||||
* Keys in `zfs/` are used for ZFS datasets, where the further path is that of the dataset. Datasets implicitly inherit their parent's encryption by default. An empty key (created by method `unencrypted`) explicitly disables encryption on a dataset. Other keys are by default used with `keyformat=hex` and must thus be exactly 64 (lowercase) hex digits.
|
||||
* Keys in `home/` are meant to be used as composites for home directory encryption, where the second and only other path label us the user name.
|
||||
* Keys in `home/` are meant to be used as composites for home directory encryption, where the second and only other path label is the user name.
|
||||
|
||||
The attribute value in the `.keys` keys specification dictates how the key is acquired, primarily initially during installation, but (depending on the keys usage) also during boot unlocking, etc.
|
||||
The attribute value in the `.keys` keys specification dictates how the key is acquired, primarily initially during installation, but (depending on the key's usage) also during boot unlocking, etc.
|
||||
The format of the key specification is `method[=args]`, where `method` is the suffix of a bash function call `gen-key-<method>` (the default functions are in [`add-key.sh`](../../lib/setup-scripts/add-key.sh), but others could be added to the installer), and `args` is the second argument to the respective function (often a `:` separated list of arguments, but some methods don't need any arguments at all).
|
||||
Most key generation methods only make sense in some key usage contexts. A `random` key is impossible to provide to unlock the keystore (which it is stored in), but is well suited to unlock other devices (if the keystore has backups); conversely a USB-partition can be used to headlessly unlock the keystore, but would be redundant for any further devices, as it would also be copied into the keystore.
|
||||
|
||||
|
@ -10,7 +10,7 @@ Such state generally falls into one of four categories:
|
||||
3) It may or may not be secret and can be re-generated quickly.
|
||||
|
||||
Category 1 data can not be included in the nix store and thus can not (directly) be derived from the system configuration.
|
||||
It needs to be stored in a way that the host (and only the host) can access it an that it can't be lost.
|
||||
It needs to be stored in a way that the host (and only the host) can access it and that it can't be lost.
|
||||
It is therefore referred to as `remote` data (even though it would usually also be stored locally).
|
||||
|
||||
Category 2 data is required for the system to boot (in reasonable time), and should thus, as `local` data, be stored persistently on the host.
|
||||
@ -204,7 +204,15 @@ in {
|
||||
|
||||
}) (lib.mkIf cfg.persistenceFixes { # Cope with the consequences of having »/« (including »/{etc,var,root,...}«) cleared on every reboot.
|
||||
|
||||
environment.etc.nixos.source = "/local/etc/nixos";
|
||||
environment.etc = {
|
||||
nixos.source = "/local/etc/nixos";
|
||||
|
||||
# SSHd host keys:
|
||||
"ssh/ssh_host_ed25519_key".source = "/${keep}/etc/ssh/ssh_host_ed25519_key";
|
||||
"ssh/ssh_host_ed25519_key.pub".source = "/${keep}/etc/ssh/ssh_host_ed25519_key.pub";
|
||||
"ssh/ssh_host_rsa_key".source = "/${keep}/etc/ssh/ssh_host_rsa_key";
|
||||
"ssh/ssh_host_rsa_key.pub".source = "/${keep}/etc/ssh/ssh_host_rsa_key.pub";
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [ # keep in mind: this does not get applied super early ...
|
||||
# »/root/.nix-channels« is already being restored.
|
||||
@ -216,12 +224,7 @@ in {
|
||||
"f /${keep}/root/.local/share/nix/repl-history 0600 root root -"
|
||||
"L+ /root/.local/share/nix/repl-history - - - - ../../../../${keep}/root/.local/share/nix/repl-history"
|
||||
|
||||
# SSHd host keys:
|
||||
"d /${keep}/etc/ssh/ 0755 root root - -"
|
||||
"L /etc/ssh/ssh_host_ed25519_key - - - - /${keep}/etc/ssh/ssh_host_ed25519_key"
|
||||
"L /etc/ssh/ssh_host_ed25519_key.pub - - - - /${keep}/etc/ssh/ssh_host_ed25519_key.pub"
|
||||
"L /etc/ssh/ssh_host_rsa_key - - - - /${keep}/etc/ssh/ssh_host_rsa_key"
|
||||
"L /etc/ssh/ssh_host_rsa_key.pub - - - - /${keep}/etc/ssh/ssh_host_rsa_key.pub"
|
||||
];
|
||||
|
||||
fileSystems = { # this does get applied early
|
||||
|
@ -3,7 +3,7 @@
|
||||
# ZFS Pools and Datasets
|
||||
|
||||
This module primarily allows the specification of ZFS pools and datasets. The declared pools and datasets are complemented with some default and are then used by [`lib/setup-scripts/zfs.sh`](../../lib/setup-scripts/zfs.sh) to create them during system installation, and can optionally later be kept up to date (with the config) at config activation time or during reboot.
|
||||
Additionally, this module sets some defaults for ZFS (but only in a "always better than nothing" style, so `lib.mkForce null` should never be necessary).
|
||||
Additionally, this module sets some defaults for ZFS (but only in an "always better than nothing" style, so `lib.mkForce null` should never be necessary).
|
||||
|
||||
|
||||
## Implementation
|
||||
|
Loading…
Reference in New Issue
Block a user