at 25.11-pre 6.5 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7with lib; 8let 9 cfg = config.boot.iscsi-initiator; 10in 11{ 12 # If you're booting entirely off another machine you may want to add 13 # this snippet to always boot the latest "system" version. It is not 14 # enabled by default in case you have an initrd on a local disk: 15 # 16 # boot.initrd.postMountCommands = '' 17 # ln -sfn /nix/var/nix/profiles/system/init /mnt-root/init 18 # stage2Init=/init 19 # ''; 20 # 21 # Note: Theoretically you might want to connect to multiple portals and 22 # log in to multiple targets, however the authors of this module so far 23 # don't have the need or expertise to reasonably implement it. Also, 24 # consider carefully before making your boot chain depend on multiple 25 # machines to be up. 26 options.boot.iscsi-initiator = with types; { 27 name = mkOption { 28 description = '' 29 Name of the iSCSI initiator to boot from. Note, booting from iscsi 30 requires networkd based networking. 31 ''; 32 default = null; 33 example = "iqn.2020-08.org.linux-iscsi.initiatorhost:example"; 34 type = nullOr str; 35 }; 36 37 discoverPortal = mkOption { 38 description = '' 39 iSCSI portal to boot from. 40 ''; 41 default = null; 42 example = "192.168.1.1:3260"; 43 type = nullOr str; 44 }; 45 46 target = mkOption { 47 description = '' 48 Name of the iSCSI target to boot from. 49 ''; 50 default = null; 51 example = "iqn.2020-08.org.linux-iscsi.targethost:example"; 52 type = nullOr str; 53 }; 54 55 logLevel = mkOption { 56 description = '' 57 Higher numbers elicits more logs. 58 ''; 59 default = 1; 60 example = 8; 61 type = int; 62 }; 63 64 loginAll = mkOption { 65 description = '' 66 Do not log into a specific target on the portal, but to all that we discover. 67 This overrides setting target. 68 ''; 69 type = bool; 70 default = false; 71 }; 72 73 extraIscsiCommands = mkOption { 74 description = "Extra iscsi commands to run in the initrd."; 75 default = ""; 76 type = lines; 77 }; 78 79 extraConfig = mkOption { 80 description = "Extra lines to append to /etc/iscsid.conf"; 81 default = null; 82 type = nullOr lines; 83 }; 84 85 extraConfigFile = mkOption { 86 description = '' 87 Append an additional file's contents to `/etc/iscsid.conf`. Use a non-store path 88 and store passwords in this file. Note: the file specified here must be available 89 in the initrd, see: `boot.initrd.secrets`. 90 ''; 91 default = null; 92 type = nullOr str; 93 }; 94 }; 95 96 config = mkIf (cfg.name != null) { 97 # The "scripted" networking configuration (ie: non-networkd) 98 # doesn't properly order the start and stop of the interfaces, and the 99 # network interfaces are torn down before unmounting disks. Since this 100 # module is specifically for very-early-boot network mounts, we need 101 # the network to stay on. 102 # 103 # We could probably fix the scripted options to properly order, but I'm 104 # not inclined to invest that time today. Hopefully this gets users far 105 # enough along and they can just use networkd. 106 networking.useNetworkd = true; 107 networking.useDHCP = false; # Required to set useNetworkd = true 108 109 boot.initrd = { 110 network.enable = true; 111 112 # By default, the stage-1 disables the network and resets the interfaces 113 # on startup. Since our startup disks are on the network, we can't let 114 # the network not work. 115 network.flushBeforeStage2 = false; 116 117 kernelModules = [ "iscsi_tcp" ]; 118 119 extraUtilsCommands = '' 120 copy_bin_and_libs ${pkgs.openiscsi}/bin/iscsid 121 copy_bin_and_libs ${pkgs.openiscsi}/bin/iscsiadm 122 ${optionalString ( 123 !config.boot.initrd.network.ssh.enable 124 ) "cp -pv ${pkgs.glibc.out}/lib/libnss_files.so.* $out/lib"} 125 126 mkdir -p $out/etc/iscsi 127 cp ${config.environment.etc.hosts.source} $out/etc/hosts 128 cp ${pkgs.openiscsi}/etc/iscsi/iscsid.conf $out/etc/iscsi/iscsid.fragment.conf 129 chmod +w $out/etc/iscsi/iscsid.fragment.conf 130 cat << 'EOF' >> $out/etc/iscsi/iscsid.fragment.conf 131 ${optionalString (cfg.extraConfig != null) cfg.extraConfig} 132 EOF 133 ''; 134 135 extraUtilsCommandsTest = '' 136 $out/bin/iscsiadm --version 137 ''; 138 139 preLVMCommands = 140 let 141 extraCfgDumper = optionalString (cfg.extraConfigFile != null) '' 142 if [ -f "${cfg.extraConfigFile}" ]; then 143 printf "\n# The following is from ${cfg.extraConfigFile}:\n" 144 cat "${cfg.extraConfigFile}" 145 else 146 echo "Warning: boot.iscsi-initiator.extraConfigFile ${cfg.extraConfigFile} does not exist!" >&2 147 fi 148 ''; 149 in 150 '' 151 ${optionalString (!config.boot.initrd.network.ssh.enable) '' 152 # stolen from initrd-ssh.nix 153 echo 'root:x:0:0:root:/root:/bin/ash' > /etc/passwd 154 echo 'passwd: files' > /etc/nsswitch.conf 155 ''} 156 157 cp -f $extraUtils/etc/hosts /etc/hosts 158 159 mkdir -p /etc/iscsi /run/lock/iscsi 160 echo "InitiatorName=${cfg.name}" > /etc/iscsi/initiatorname.iscsi 161 162 ( 163 cat "$extraUtils/etc/iscsi/iscsid.fragment.conf" 164 printf "\n" 165 ${optionalString cfg.loginAll ''echo "node.startup = automatic"''} 166 ${extraCfgDumper} 167 ) > /etc/iscsi/iscsid.conf 168 169 iscsid --foreground --no-pid-file --debug ${toString cfg.logLevel} & 170 iscsiadm --mode discoverydb \ 171 --type sendtargets \ 172 --discover \ 173 --portal ${escapeShellArg cfg.discoverPortal} \ 174 --debug ${toString cfg.logLevel} 175 176 ${ 177 if cfg.loginAll then 178 '' 179 iscsiadm --mode node --loginall all 180 '' 181 else 182 '' 183 iscsiadm --mode node --targetname ${escapeShellArg cfg.target} --login 184 '' 185 } 186 187 ${cfg.extraIscsiCommands} 188 189 pkill -9 iscsid 190 ''; 191 }; 192 193 services.openiscsi = { 194 enable = true; 195 inherit (cfg) name; 196 }; 197 198 assertions = [ 199 { 200 assertion = cfg.loginAll -> cfg.target == null; 201 message = "iSCSI target name is set while login on all portals is enabled."; 202 } 203 { 204 assertion = !config.boot.initrd.systemd.enable; 205 message = "systemd stage 1 does not support iscsi yet."; 206 } 207 ]; 208 }; 209}