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