182 lines
5.8 KiB
Nix
182 lines
5.8 KiB
Nix
|
{ config, lib, pkgs, ... }: with lib;
|
||
|
let
|
||
|
cfg = config.boot.iscsi-initiator;
|
||
|
in
|
||
|
{
|
||
|
# If you're booting entirely off another machine you may want to add
|
||
|
# this snippet to always boot the latest "system" version. It is not
|
||
|
# enabled by default in case you have an initrd on a local disk:
|
||
|
#
|
||
|
# boot.initrd.postMountCommands = ''
|
||
|
# ln -sfn /nix/var/nix/profiles/system/init /mnt-root/init
|
||
|
# stage2Init=/init
|
||
|
# '';
|
||
|
#
|
||
|
# Note: Theoretically you might want to connect to multiple portals and
|
||
|
# log in to multiple targets, however the authors of this module so far
|
||
|
# don't have the need or expertise to reasonably implement it. Also,
|
||
|
# consider carefully before making your boot chain depend on multiple
|
||
|
# machines to be up.
|
||
|
options.boot.iscsi-initiator = with types; {
|
||
|
name = mkOption {
|
||
|
description = ''
|
||
|
Name of the iSCSI initiator to boot from. Note, booting from iscsi
|
||
|
requires networkd based networking.
|
||
|
'';
|
||
|
default = null;
|
||
|
example = "iqn.2020-08.org.linux-iscsi.initiatorhost:example";
|
||
|
type = nullOr str;
|
||
|
};
|
||
|
|
||
|
discoverPortal = mkOption {
|
||
|
description = ''
|
||
|
iSCSI portal to boot from.
|
||
|
'';
|
||
|
default = null;
|
||
|
example = "192.168.1.1:3260";
|
||
|
type = nullOr str;
|
||
|
};
|
||
|
|
||
|
target = mkOption {
|
||
|
description = ''
|
||
|
Name of the iSCSI target to boot from.
|
||
|
'';
|
||
|
default = null;
|
||
|
example = "iqn.2020-08.org.linux-iscsi.targethost:example";
|
||
|
type = nullOr str;
|
||
|
};
|
||
|
|
||
|
logLevel = mkOption {
|
||
|
description = ''
|
||
|
Higher numbers elicits more logs.
|
||
|
'';
|
||
|
default = 1;
|
||
|
example = 8;
|
||
|
type = int;
|
||
|
};
|
||
|
|
||
|
loginAll = mkOption {
|
||
|
description = ''
|
||
|
Do not log into a specific target on the portal, but to all that we discover.
|
||
|
This overrides setting target.
|
||
|
'';
|
||
|
type = bool;
|
||
|
default = false;
|
||
|
};
|
||
|
|
||
|
extraConfig = mkOption {
|
||
|
description = "Extra lines to append to /etc/iscsid.conf";
|
||
|
default = null;
|
||
|
type = nullOr lines;
|
||
|
};
|
||
|
|
||
|
extraConfigFile = mkOption {
|
||
|
description = ''
|
||
|
Append an additional file's contents to `/etc/iscsid.conf`. Use a non-store path
|
||
|
and store passwords in this file. Note: the file specified here must be available
|
||
|
in the initrd, see: `boot.initrd.secrets`.
|
||
|
'';
|
||
|
default = null;
|
||
|
type = nullOr str;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
config = mkIf (cfg.name != null) {
|
||
|
# The "scripted" networking configuration (ie: non-networkd)
|
||
|
# doesn't properly order the start and stop of the interfaces, and the
|
||
|
# network interfaces are torn down before unmounting disks. Since this
|
||
|
# module is specifically for very-early-boot network mounts, we need
|
||
|
# the network to stay on.
|
||
|
#
|
||
|
# We could probably fix the scripted options to properly order, but I'm
|
||
|
# not inclined to invest that time today. Hopefully this gets users far
|
||
|
# enough along and they can just use networkd.
|
||
|
networking.useNetworkd = true;
|
||
|
networking.useDHCP = false; # Required to set useNetworkd = true
|
||
|
|
||
|
boot.initrd = {
|
||
|
network.enable = true;
|
||
|
|
||
|
# By default, the stage-1 disables the network and resets the interfaces
|
||
|
# on startup. Since our startup disks are on the network, we can't let
|
||
|
# the network not work.
|
||
|
network.flushBeforeStage2 = false;
|
||
|
|
||
|
kernelModules = [ "iscsi_tcp" ];
|
||
|
|
||
|
extraUtilsCommands = ''
|
||
|
copy_bin_and_libs ${pkgs.openiscsi}/bin/iscsid
|
||
|
copy_bin_and_libs ${pkgs.openiscsi}/bin/iscsiadm
|
||
|
${optionalString (!config.boot.initrd.network.ssh.enable) "cp -pv ${pkgs.glibc.out}/lib/libnss_files.so.* $out/lib"}
|
||
|
|
||
|
mkdir -p $out/etc/iscsi
|
||
|
cp ${config.environment.etc.hosts.source} $out/etc/hosts
|
||
|
cp ${pkgs.openiscsi}/etc/iscsi/iscsid.conf $out/etc/iscsi/iscsid.fragment.conf
|
||
|
chmod +w $out/etc/iscsi/iscsid.fragment.conf
|
||
|
cat << 'EOF' >> $out/etc/iscsi/iscsid.fragment.conf
|
||
|
${optionalString (cfg.extraConfig != null) cfg.extraConfig}
|
||
|
EOF
|
||
|
'';
|
||
|
|
||
|
extraUtilsCommandsTest = ''
|
||
|
$out/bin/iscsiadm --version
|
||
|
'';
|
||
|
|
||
|
preLVMCommands = let
|
||
|
extraCfgDumper = optionalString (cfg.extraConfigFile != null) ''
|
||
|
if [ -f "${cfg.extraConfigFile}" ]; then
|
||
|
printf "\n# The following is from ${cfg.extraConfigFile}:\n"
|
||
|
cat "${cfg.extraConfigFile}"
|
||
|
else
|
||
|
echo "Warning: boot.iscsi-initiator.extraConfigFile ${cfg.extraConfigFile} does not exist!" >&2
|
||
|
fi
|
||
|
'';
|
||
|
in ''
|
||
|
${optionalString (!config.boot.initrd.network.ssh.enable) ''
|
||
|
# stolen from initrd-ssh.nix
|
||
|
echo 'root:x:0:0:root:/root:/bin/ash' > /etc/passwd
|
||
|
echo 'passwd: files' > /etc/nsswitch.conf
|
||
|
''}
|
||
|
|
||
|
cp -f $extraUtils/etc/hosts /etc/hosts
|
||
|
|
||
|
mkdir -p /etc/iscsi /run/lock/iscsi
|
||
|
echo "InitiatorName=${cfg.name}" > /etc/iscsi/initiatorname.iscsi
|
||
|
|
||
|
(
|
||
|
cat "$extraUtils/etc/iscsi/iscsid.fragment.conf"
|
||
|
printf "\n"
|
||
|
${optionalString cfg.loginAll ''echo "node.startup = automatic"''}
|
||
|
${extraCfgDumper}
|
||
|
) > /etc/iscsi/iscsid.conf
|
||
|
|
||
|
iscsid --foreground --no-pid-file --debug ${toString cfg.logLevel} &
|
||
|
iscsiadm --mode discoverydb \
|
||
|
--type sendtargets \
|
||
|
--discover \
|
||
|
--portal ${escapeShellArg cfg.discoverPortal} \
|
||
|
--debug ${toString cfg.logLevel}
|
||
|
|
||
|
${if cfg.loginAll then ''
|
||
|
iscsiadm --mode node --loginall all
|
||
|
'' else ''
|
||
|
iscsiadm --mode node --targetname ${escapeShellArg cfg.target} --login
|
||
|
''}
|
||
|
pkill -9 iscsid
|
||
|
'';
|
||
|
};
|
||
|
|
||
|
services.openiscsi = {
|
||
|
enable = true;
|
||
|
inherit (cfg) name;
|
||
|
};
|
||
|
|
||
|
assertions = [
|
||
|
{
|
||
|
assertion = cfg.loginAll -> cfg.target == null;
|
||
|
message = "iSCSI target name is set while login on all portals is enabled.";
|
||
|
}
|
||
|
];
|
||
|
};
|
||
|
}
|