at master 9.3 kB view raw
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 = pkgs.lib.teams.deshaw.members; 10 }; 11 12 nodes = { 13 target = 14 { 15 config, 16 pkgs, 17 lib, 18 ... 19 }: 20 { 21 virtualisation.vlans = [ 22 1 23 2 24 ]; 25 services.target = { 26 enable = true; 27 config = { 28 fabric_modules = [ ]; 29 storage_objects = [ 30 { 31 dev = "/dev/vdb"; 32 name = "test"; 33 plugin = "block"; 34 write_back = true; 35 wwn = "92b17c3f-6b40-4168-b082-ceeb7b495522"; 36 } 37 ]; 38 targets = [ 39 { 40 fabric = "iscsi"; 41 tpgs = [ 42 { 43 enable = true; 44 attributes = { 45 authentication = 0; 46 generate_node_acls = 1; 47 }; 48 luns = [ 49 { 50 alias = "94dfe06967"; 51 alua_tg_pt_gp_name = "default_tg_pt_gp"; 52 index = 0; 53 storage_object = "/backstores/block/test"; 54 } 55 ]; 56 node_acls = [ 57 { 58 mapped_luns = [ 59 { 60 alias = "d42f5bdf8a"; 61 index = 0; 62 tpg_lun = 0; 63 write_protect = false; 64 } 65 ]; 66 node_wwn = initiatorName; 67 } 68 ]; 69 portals = [ 70 { 71 ip_address = "0.0.0.0"; 72 iser = false; 73 offload = false; 74 port = 3260; 75 } 76 ]; 77 tag = 1; 78 } 79 ]; 80 wwn = targetName; 81 } 82 ]; 83 }; 84 }; 85 86 networking.firewall.allowedTCPPorts = [ 3260 ]; 87 networking.firewall.allowedUDPPorts = [ 3260 ]; 88 89 virtualisation.memorySize = 2048; 90 virtualisation.emptyDiskImages = [ 2048 ]; 91 }; 92 93 initiatorAuto = 94 { 95 nodes, 96 config, 97 pkgs, 98 ... 99 }: 100 { 101 virtualisation.vlans = [ 102 1 103 2 104 ]; 105 106 services.multipath = { 107 enable = true; 108 defaults = '' 109 find_multipaths yes 110 user_friendly_names yes 111 ''; 112 pathGroups = [ 113 { 114 alias = 123456; 115 wwid = "3600140592b17c3f6b404168b082ceeb7"; 116 } 117 ]; 118 }; 119 120 services.openiscsi = { 121 enable = true; 122 enableAutoLoginOut = true; 123 discoverPortal = "target"; 124 name = initiatorName; 125 }; 126 127 environment.systemPackages = with pkgs; [ 128 xfsprogs 129 ]; 130 131 environment.etc."initiator-root-disk-closure".source = 132 nodes.initiatorRootDisk.config.system.build.toplevel; 133 134 nix.settings = { 135 substituters = lib.mkForce [ ]; 136 hashed-mirrors = null; 137 connect-timeout = 1; 138 }; 139 }; 140 141 initiatorRootDisk = 142 { 143 config, 144 pkgs, 145 modulesPath, 146 lib, 147 ... 148 }: 149 { 150 boot.initrd.network.enable = true; 151 boot.loader.grub.enable = false; 152 153 boot.kernelParams = lib.mkOverride 5 ([ 154 "boot.shell_on_fail" 155 "console=tty1" 156 "ip=192.168.1.1:::255.255.255.0::ens9:none" 157 "ip=192.168.2.1:::255.255.255.0::ens10:none" 158 ]); 159 160 # defaults to true, puts some code in the initrd that tries to mount an overlayfs on /nix/store 161 virtualisation.writableStore = false; 162 virtualisation.vlans = [ 163 1 164 2 165 ]; 166 167 services.multipath = { 168 enable = true; 169 defaults = '' 170 find_multipaths yes 171 user_friendly_names yes 172 ''; 173 pathGroups = [ 174 { 175 alias = 123456; 176 wwid = "3600140592b17c3f6b404168b082ceeb7"; 177 } 178 ]; 179 }; 180 181 fileSystems = lib.mkOverride 5 { 182 "/" = { 183 fsType = "xfs"; 184 device = "/dev/mapper/123456"; 185 options = [ "_netdev" ]; 186 }; 187 }; 188 189 boot.initrd.extraFiles."etc/multipath/wwids".source = 190 pkgs.writeText "wwids" "/3600140592b17c3f6b404168b082ceeb7/"; 191 192 boot.iscsi-initiator = { 193 discoverPortal = "target"; 194 name = initiatorName; 195 target = targetName; 196 extraIscsiCommands = '' 197 iscsiadm -m discovery -o update -t sendtargets -p 192.168.2.3 --login 198 ''; 199 }; 200 }; 201 202 }; 203 204 testScript = 205 { nodes, ... }: 206 '' 207 target.start() 208 target.wait_for_unit("iscsi-target.service") 209 210 initiatorAuto.start() 211 212 initiatorAuto.wait_for_unit("iscsid.service") 213 initiatorAuto.wait_for_unit("iscsi.service") 214 initiatorAuto.get_unit_info("iscsi") 215 216 # Expecting this to fail since we should already know about 192.168.1.3 217 initiatorAuto.fail("iscsiadm -m discovery -o update -t sendtargets -p 192.168.1.3 --login") 218 # Expecting this to succeed since we don't yet know about 192.168.2.3 219 initiatorAuto.succeed("iscsiadm -m discovery -o update -t sendtargets -p 192.168.2.3 --login") 220 221 # /dev/sda is provided by iscsi on target 222 initiatorAuto.succeed("set -x; while ! test -e /dev/sda; do sleep 1; done") 223 224 initiatorAuto.succeed("mkfs.xfs /dev/sda") 225 initiatorAuto.succeed("mkdir /mnt") 226 227 # Start by verifying /dev/sda and /dev/sdb are both the same disk 228 initiatorAuto.succeed("mount /dev/sda /mnt") 229 initiatorAuto.succeed("touch /mnt/hi") 230 initiatorAuto.succeed("umount /mnt") 231 232 initiatorAuto.succeed("mount /dev/sdb /mnt") 233 initiatorAuto.succeed("test -e /mnt/hi") 234 initiatorAuto.succeed("umount /mnt") 235 236 initiatorAuto.succeed("systemctl restart multipathd") 237 initiatorAuto.succeed("systemd-cat multipath -ll") 238 239 # Install our RootDisk machine to 123456, the alias to the device that multipath is now managing 240 initiatorAuto.succeed("mount /dev/mapper/123456 /mnt") 241 initiatorAuto.succeed("mkdir -p /mnt/etc/{multipath,iscsi}") 242 initiatorAuto.succeed("cp -r /etc/multipath/wwids /mnt/etc/multipath/wwids") 243 initiatorAuto.succeed("cp -r /etc/iscsi/{nodes,send_targets} /mnt/etc/iscsi") 244 initiatorAuto.succeed( 245 "nixos-install --no-bootloader --no-root-passwd --system /etc/initiator-root-disk-closure" 246 ) 247 initiatorAuto.succeed("umount /mnt") 248 initiatorAuto.shutdown() 249 250 initiatorRootDisk.start() 251 initiatorRootDisk.wait_for_unit("multi-user.target") 252 initiatorRootDisk.wait_for_unit("iscsid") 253 254 # Log in over both nodes 255 initiatorRootDisk.fail("iscsiadm -m discovery -o update -t sendtargets -p 192.168.1.3 --login") 256 initiatorRootDisk.fail("iscsiadm -m discovery -o update -t sendtargets -p 192.168.2.3 --login") 257 initiatorRootDisk.succeed("systemctl restart multipathd") 258 initiatorRootDisk.succeed("systemd-cat multipath -ll") 259 260 # Verify we can write and sync the root disk 261 initiatorRootDisk.succeed("mkdir /scratch") 262 initiatorRootDisk.succeed("touch /scratch/both-up") 263 initiatorRootDisk.succeed("sync /scratch") 264 265 # Verify we can write to the root with ens9 (sda, 192.168.1.3) down 266 initiatorRootDisk.succeed("ip link set ens9 down") 267 initiatorRootDisk.succeed("touch /scratch/ens9-down") 268 initiatorRootDisk.succeed("sync /scratch") 269 initiatorRootDisk.succeed("ip link set ens9 up") 270 271 # todo: better way to wait until multipath notices the link is back 272 initiatorRootDisk.succeed("sleep 5") 273 initiatorRootDisk.succeed("touch /scratch/both-down") 274 initiatorRootDisk.succeed("sync /scratch") 275 276 # Verify we can write to the root with ens10 (sdb, 192.168.2.3) down 277 initiatorRootDisk.succeed("ip link set ens10 down") 278 initiatorRootDisk.succeed("touch /scratch/ens10-down") 279 initiatorRootDisk.succeed("sync /scratch") 280 initiatorRootDisk.succeed("ip link set ens10 up") 281 initiatorRootDisk.succeed("touch /scratch/ens10-down") 282 initiatorRootDisk.succeed("sync /scratch") 283 284 initiatorRootDisk.succeed("ip link set ens9 up") 285 initiatorRootDisk.succeed("ip link set ens10 up") 286 initiatorRootDisk.shutdown() 287 288 # Verify we can boot with the target's eth1 down, forcing 289 # it to multipath via the second link 290 target.succeed("ip link set eth1 down") 291 initiatorRootDisk.start() 292 initiatorRootDisk.wait_for_unit("multi-user.target") 293 initiatorRootDisk.wait_for_unit("iscsid") 294 initiatorRootDisk.succeed("test -e /scratch/both-up") 295 ''; 296}