lol

nixos/nbd: fix nbd-server config section ordering

Closes #169103

+44 -15
+28 -15
nixos/modules/services/networking/nbd.nix
··· 4 4 5 5 let 6 6 cfg = config.services.nbd; 7 - configFormat = pkgs.formats.ini { }; 8 7 iniFields = with types; attrsOf (oneOf [ bool int float str ]); 9 - serverConfig = configFormat.generate "nbd-server-config" 10 - ({ 11 - generic = 12 - (cfg.server.extraOptions // { 13 - user = "root"; 14 - group = "root"; 15 - port = cfg.server.listenPort; 16 - } // (optionalAttrs (cfg.server.listenAddress != null) { 17 - listenaddr = cfg.server.listenAddress; 18 - })); 19 - } 20 - // (mapAttrs 8 + # The `[generic]` section must come before all the others in the 9 + # config file. This means we can't just dump an attrset to INI 10 + # because that sorts the sections by name. Instead, we serialize it 11 + # on its own first. 12 + genericSection = { 13 + generic = (cfg.server.extraOptions // { 14 + user = "root"; 15 + group = "root"; 16 + port = cfg.server.listenPort; 17 + } // (optionalAttrs (cfg.server.listenAddress != null) { 18 + listenaddr = cfg.server.listenAddress; 19 + })); 20 + }; 21 + exportSections = 22 + mapAttrs 21 23 (_: { path, allowAddresses, extraOptions }: 22 24 extraOptions // { 23 25 exportname = path; 24 26 } // (optionalAttrs (allowAddresses != null) { 25 27 authfile = pkgs.writeText "authfile" (concatStringsSep "\n" allowAddresses); 26 28 })) 27 - cfg.server.exports) 28 - ); 29 + cfg.server.exports; 30 + serverConfig = 31 + pkgs.writeText "nbd-server-config" '' 32 + ${lib.generators.toINI {} genericSection} 33 + ${lib.generators.toINI {} exportSections} 34 + ''; 29 35 splitLists = 30 36 partition 31 37 (path: hasPrefix "/dev/" path) ··· 103 109 }; 104 110 105 111 config = mkIf cfg.server.enable { 112 + assertions = [ 113 + { 114 + assertion = !(cfg.server.exports ? "generic"); 115 + message = "services.nbd.server exports must not be named 'generic'"; 116 + } 117 + ]; 118 + 106 119 boot.kernelModules = [ "nbd" ]; 107 120 108 121 systemd.services.nbd-server = {
+16
nixos/tests/nbd.nix
··· 28 28 ## It's also a loopback device to test exporting /dev/... 29 29 systemd.services.create-priv-file = 30 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"; }; 31 36 32 37 # Needed only for nbd-client used in the tests. 33 38 environment.systemPackages = [ pkgs.nbd ]; ··· 39 44 services.nbd.server = { 40 45 enable = true; 41 46 exports = { 47 + aaa = { 48 + path = "/aaa.disk"; 49 + }; 42 50 vault-pub = { 43 51 path = "/vault-pub.disk"; 44 52 }; ··· 80 88 server.succeed("nbd-client localhost ${toString listenPort} /dev/nbd0 -name vault-priv -persist") 81 89 server.succeed(f"echo '{testString}' | dd of=/dev/nbd0 conv=notrunc") 82 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)] 83 99 if foundString != testString: 84 100 raise Exception(f"Read the wrong string from nbd disk. Expected: '{testString}'. Found: '{foundString}'") 85 101 server.succeed("nbd-client -d /dev/nbd0")