1{ pkgs, lib, ... }:
2let
3 initiatorName = "iqn.2020-08.org.linux-iscsi.initiatorhost:example";
4 targetName = "iqn.2003-01.org.linux-iscsi.target.x8664:sn.acf8fd9c23af";
5in
6{
7 name = "iscsi";
8 meta = {
9 maintainers = lib.teams.deshaw.members ++ lib.teams.helsinki-systems.members;
10 };
11
12 nodes = {
13 target =
14 {
15 config,
16 pkgs,
17 lib,
18 ...
19 }:
20 {
21 services.target = {
22 enable = true;
23 config = {
24 fabric_modules = [ ];
25 storage_objects = [
26 {
27 dev = "/dev/vdb";
28 name = "test";
29 plugin = "block";
30 write_back = true;
31 wwn = "92b17c3f-6b40-4168-b082-ceeb7b495522";
32 }
33 ];
34 targets = [
35 {
36 fabric = "iscsi";
37 tpgs = [
38 {
39 enable = true;
40 attributes = {
41 authentication = 0;
42 generate_node_acls = 1;
43 };
44 luns = [
45 {
46 alias = "94dfe06967";
47 alua_tg_pt_gp_name = "default_tg_pt_gp";
48 index = 0;
49 storage_object = "/backstores/block/test";
50 }
51 ];
52 node_acls = [
53 {
54 mapped_luns = [
55 {
56 alias = "d42f5bdf8a";
57 index = 0;
58 tpg_lun = 0;
59 write_protect = false;
60 }
61 ];
62 node_wwn = initiatorName;
63 }
64 ];
65 portals = [
66 {
67 ip_address = "[::]";
68 iser = false;
69 offload = false;
70 port = 3260;
71 }
72 ];
73 tag = 1;
74 }
75 ];
76 wwn = targetName;
77 }
78 ];
79 };
80 };
81
82 networking.firewall.allowedTCPPorts = [ 3260 ];
83 networking.firewall.allowedUDPPorts = [ 3260 ];
84
85 virtualisation.memorySize = 2048;
86 virtualisation.emptyDiskImages = [ 2048 ];
87 };
88
89 initiatorAuto =
90 {
91 nodes,
92 config,
93 pkgs,
94 ...
95 }:
96 {
97 services.openiscsi = {
98 enable = true;
99 enableAutoLoginOut = true;
100 discoverPortal = "target";
101 name = initiatorName;
102 };
103
104 environment.systemPackages = with pkgs; [
105 xfsprogs
106 ];
107
108 system.extraDependencies = [ nodes.initiatorRootDisk.system.build.toplevel ];
109
110 nix.settings = {
111 substituters = lib.mkForce [ ];
112 hashed-mirrors = null;
113 connect-timeout = 1;
114 };
115 };
116
117 initiatorRootDisk =
118 {
119 config,
120 pkgs,
121 modulesPath,
122 lib,
123 ...
124 }:
125 {
126 boot.loader.grub.enable = false;
127 boot.kernelParams = lib.mkOverride 5 ([
128 "boot.shell_on_fail"
129 "console=tty1"
130 "ip=${config.networking.primaryIPAddress}:::255.255.255.0::eth1:none"
131 ]);
132
133 # defaults to true, puts some code in the initrd that tries to mount an overlayfs on /nix/store
134 virtualisation.writableStore = false;
135
136 fileSystems = lib.mkOverride 5 {
137 "/" = {
138 fsType = "xfs";
139 device = "/dev/sda";
140 options = [ "_netdev" ];
141 };
142 };
143
144 boot.iscsi-initiator = {
145 discoverPortal = "target";
146 name = initiatorName;
147 target = targetName;
148 };
149 };
150 };
151
152 testScript =
153 { nodes, ... }:
154 ''
155 target.start()
156 target.wait_for_unit("iscsi-target.service")
157
158 initiatorAuto.start()
159
160 initiatorAuto.wait_for_unit("iscsid.service")
161 initiatorAuto.wait_for_unit("iscsi.service")
162 initiatorAuto.get_unit_info("iscsi")
163
164 initiatorAuto.succeed("set -x; while ! test -e /dev/sda; do sleep 1; done")
165
166 initiatorAuto.succeed("mkfs.xfs /dev/sda")
167 initiatorAuto.succeed("mkdir /mnt && mount /dev/sda /mnt")
168 initiatorAuto.succeed(
169 "nixos-install --no-bootloader --no-root-passwd --system ${nodes.initiatorRootDisk.config.system.build.toplevel}"
170 )
171 initiatorAuto.succeed("umount /mnt && rmdir /mnt")
172 initiatorAuto.shutdown()
173
174 initiatorRootDisk.start()
175 initiatorRootDisk.wait_for_unit("multi-user.target")
176 initiatorRootDisk.wait_for_unit("iscsid")
177 initiatorRootDisk.succeed("touch test")
178 initiatorRootDisk.shutdown()
179 '';
180}