1import ./make-test-python.nix ({ pkgs, ... }:
2 let
3 listenPort = 30123;
4 testString = "It works!";
5 mkCreateSmallFileService = { path, loop ? false }: {
6 script = ''
7 ${pkgs.coreutils}/bin/dd if=/dev/zero of=${path} bs=1K count=100
8 ${pkgs.lib.optionalString loop
9 "${pkgs.util-linux}/bin/losetup --find ${path}"}
10 '';
11 serviceConfig = {
12 Type = "oneshot";
13 };
14 wantedBy = [ "multi-user.target" ];
15 before = [ "nbd-server.service" ];
16 };
17 in
18 {
19 name = "nbd";
20
21 nodes = {
22 server = { config, pkgs, ... }: {
23 # Create some small files of zeros to use as the ndb disks
24 ## `vault-pub.disk` is accessible from any IP
25 systemd.services.create-pub-file =
26 mkCreateSmallFileService { path = "/vault-pub.disk"; };
27 ## `vault-priv.disk` is accessible only from localhost.
28 ## It's also a loopback device to test exporting /dev/...
29 systemd.services.create-priv-file =
30 mkCreateSmallFileService { path = "/vault-priv.disk"; loop = true; };
31 ## `aaa.disk` is just here because "[aaa]" sorts before
32 ## "[generic]" lexicographically, and nbd-server breaks if
33 ## "[generic]" isn't the first section.
34 systemd.services.create-aaa-file =
35 mkCreateSmallFileService { path = "/aaa.disk"; };
36
37 # Needed only for nbd-client used in the tests.
38 environment.systemPackages = [ pkgs.nbd ];
39
40 # Open the nbd port in the firewall
41 networking.firewall.allowedTCPPorts = [ listenPort ];
42
43 # Run the nbd server and expose the small file created above
44 services.nbd.server = {
45 enable = true;
46 exports = {
47 aaa = {
48 path = "/aaa.disk";
49 };
50 vault-pub = {
51 path = "/vault-pub.disk";
52 };
53 vault-priv = {
54 path = "/dev/loop0";
55 allowAddresses = [ "127.0.0.1" "::1" ];
56 };
57 };
58 listenAddress = "0.0.0.0";
59 listenPort = listenPort;
60 };
61 };
62
63 client = { config, pkgs, ... }: {
64 programs.nbd.enable = true;
65 };
66 };
67
68 testScript = ''
69 testString = "${testString}"
70
71 start_all()
72 server.wait_for_open_port(${toString listenPort})
73
74 # Client: Connect to the server, write a small string to the nbd disk, and cleanly disconnect
75 client.succeed("nbd-client server ${toString listenPort} /dev/nbd0 -name vault-pub -persist")
76 client.succeed(f"echo '{testString}' | dd of=/dev/nbd0 conv=notrunc")
77 client.succeed("nbd-client -d /dev/nbd0")
78
79 # Server: Check that the string written by the client is indeed in the file
80 foundString = server.succeed(f"dd status=none if=/vault-pub.disk count={len(testString)}")[:len(testString)]
81 if foundString != testString:
82 raise Exception(f"Read the wrong string from nbd disk. Expected: '{testString}'. Found: '{foundString}'")
83
84 # Client: Fail to connect to the private disk
85 client.fail("nbd-client server ${toString listenPort} /dev/nbd0 -name vault-priv -persist")
86
87 # Server: Successfully connect to the private disk
88 server.succeed("nbd-client localhost ${toString listenPort} /dev/nbd0 -name vault-priv -persist")
89 server.succeed(f"echo '{testString}' | dd of=/dev/nbd0 conv=notrunc")
90 foundString = server.succeed(f"dd status=none if=/dev/loop0 count={len(testString)}")[:len(testString)]
91 if foundString != testString:
92 raise Exception(f"Read the wrong string from nbd disk. Expected: '{testString}'. Found: '{foundString}'")
93 server.succeed("nbd-client -d /dev/nbd0")
94
95 # Server: Successfully connect to the aaa disk
96 server.succeed("nbd-client localhost ${toString listenPort} /dev/nbd0 -name aaa -persist")
97 server.succeed(f"echo '{testString}' | dd of=/dev/nbd0 conv=notrunc")
98 foundString = server.succeed(f"dd status=none if=/aaa.disk count={len(testString)}")[:len(testString)]
99 if foundString != testString:
100 raise Exception(f"Read the wrong string from nbd disk. Expected: '{testString}'. Found: '{foundString}'")
101 server.succeed("nbd-client -d /dev/nbd0")
102 '';
103 })