···98989999- `pass` now does not contain `password-store.el`. Users should get `password-store.el` from Emacs lisp package set `emacs.pkgs.password-store`.
100100101101+- `services.knot` now supports `.settings` from RFC42. The change is not 100% compatible with the previous `.extraConfig`.
102102+101103- `mu` now does not install `mu4e` files by default. Users should get `mu4e` from Emacs lisp package set `emacs.pkgs.mu4e`.
102104103105- `mariadb` now defaults to `mariadb_1011` instead of `mariadb_106`, meaning the default version was upgraded from 10.6.x to 10.11.x. See the [upgrade notes](https://mariadb.com/kb/en/upgrading-from-mariadb-10-6-to-mariadb-10-11/) for potential issues.
+125-7
nixos/modules/services/networking/knot.nix
···55let
66 cfg = config.services.knot;
7788- configFile = pkgs.writeTextFile {
88+ yamlConfig = let
99+ result = assert secsCheck; nix2yaml cfg.settings;
1010+1111+ secAllow = n: hasPrefix "mod-" n || elem n [
1212+ "module"
1313+ "server" "xdp" "control"
1414+ "log"
1515+ "statistics" "database"
1616+ "keystore" "key" "remote" "remotes" "acl" "submission" "policy"
1717+ "template"
1818+ "zone"
1919+ "include"
2020+ ];
2121+ secsCheck = let
2222+ secsBad = filter (n: !secAllow n) (attrNames cfg.settings);
2323+ in if secsBad == [] then true else throw
2424+ ("services.knot.settings contains unknown sections: " + toString secsBad);
2525+2626+ nix2yaml = nix_def: concatStrings (
2727+ # We output the config section in the upstream-mandated order.
2828+ # Ordering is important due to forward-references not being allowed.
2929+ # See definition of conf_export and 'const yp_item_t conf_schema'
3030+ # upstream for reference. Last updated for 3.3.
3131+ # When changing the set of sections, also update secAllow above.
3232+ [ (sec_list_fa "id" nix_def "module") ]
3333+ ++ map (sec_plain nix_def)
3434+ [ "server" "xdp" "control" ]
3535+ ++ [ (sec_list_fa "target" nix_def "log") ]
3636+ ++ map (sec_plain nix_def)
3737+ [ "statistics" "database" ]
3838+ ++ map (sec_list_fa "id" nix_def)
3939+ [ "keystore" "key" "remote" "remotes" "acl" "submission" "policy" ]
4040+4141+ # Export module sections before the template section.
4242+ ++ map (sec_list_fa "id" nix_def) (filter (hasPrefix "mod-") (attrNames nix_def))
4343+4444+ ++ [ (sec_list_fa "id" nix_def "template") ]
4545+ ++ [ (sec_list_fa "domain" nix_def "zone") ]
4646+ ++ [ (sec_plain nix_def "include") ]
4747+ );
4848+4949+ # A plain section contains directly attributes (we don't really check that ATM).
5050+ sec_plain = nix_def: sec_name: if !hasAttr sec_name nix_def then "" else
5151+ n2y "" { ${sec_name} = nix_def.${sec_name}; };
5252+5353+ # This section contains a list of attribute sets. In each of the sets
5454+ # there's an attribute (`fa_name`, typically "id") that must exist and come first.
5555+ # Alternatively we support using attribute sets instead of lists; example diff:
5656+ # -template = [ { id = "default"; /* other attributes */ } { id = "foo"; } ]
5757+ # +template = { default = { /* those attributes */ }; foo = { }; }
5858+ sec_list_fa = fa_name: nix_def: sec_name: if !hasAttr sec_name nix_def then "" else
5959+ let
6060+ elem2yaml = fa_val: other_attrs:
6161+ " - " + n2y "" { ${fa_name} = fa_val; }
6262+ + " " + n2y " " other_attrs
6363+ + "\n";
6464+ sec = nix_def.${sec_name};
6565+ in
6666+ sec_name + ":\n" +
6767+ (if isList sec
6868+ then flip concatMapStrings sec
6969+ (elem: elem2yaml elem.${fa_name} (removeAttrs elem [ fa_name ]))
7070+ else concatStrings (mapAttrsToList elem2yaml sec)
7171+ );
7272+7373+ # This convertor doesn't care about ordering of attributes.
7474+ # TODO: it could probably be simplified even more, now that it's not
7575+ # to be used directly, but we might want some other tweaks, too.
7676+ n2y = indent: val:
7777+ if doRecurse val then concatStringsSep "\n${indent}"
7878+ (mapAttrsToList
7979+ # This is a bit wacky - set directly under a set would start on bad indent,
8080+ # so we start those on a new line, but not other types of attribute values.
8181+ (aname: aval: "${aname}:${if doRecurse aval then "\n${indent} " else " "}"
8282+ + n2y (indent + " ") aval)
8383+ val
8484+ )
8585+ + "\n"
8686+ else
8787+ /*
8888+ if isList val && stringLength indent < 4 then concatMapStrings
8989+ (elem: "\n${indent}- " + n2y (indent + " ") elem)
9090+ val
9191+ else
9292+ */
9393+ if isList val /* and long indent */ then
9494+ "[ " + concatMapStringsSep ", " quoteString val + " ]" else
9595+ if isBool val then (if val then "on" else "off") else
9696+ quoteString val;
9797+9898+ # We don't want paths like ./my-zone.txt be converted to plain strings.
9999+ quoteString = s: ''"${if builtins.typeOf s == "path" then s else toString s}"'';
100100+ # We don't want to walk the insides of derivation attributes.
101101+ doRecurse = val: isAttrs val && !isDerivation val;
102102+103103+ in result;
104104+105105+ configFile = if cfg.settingsFile != null then
106106+ assert cfg.settings == {} && cfg.keyFiles == [];
107107+ cfg.settingsFile
108108+ else pkgs.writeTextFile {
9109 name = "knot.conf";
1010- text = (concatMapStringsSep "\n" (file: "include: ${file}") cfg.keyFiles) + "\n" +
1111- cfg.extraConfig;
110110+ text = (concatMapStringsSep "\n" (file: "include: ${file}") cfg.keyFiles) + "\n" + yamlConfig;
111111+ # TODO: maybe we could do some checks even when private keys complicate this?
12112 checkPhase = lib.optionalString (cfg.keyFiles == []) ''
13113 ${cfg.package}/bin/knotc --config=$out conf-check
14114 '';
···60160 '';
61161 };
621626363- extraConfig = mkOption {
6464- type = types.lines;
6565- default = "";
163163+ settings = mkOption {
164164+ type = types.attrs;
165165+ default = {};
66166 description = lib.mdDoc ''
6767- Extra lines to be added verbatim to knot.conf
167167+ Extra configuration as nix values.
168168+ '';
169169+ };
170170+171171+ settingsFile = mkOption {
172172+ type = types.nullOr types.path;
173173+ default = null;
174174+ description = lib.mdDoc ''
175175+ As alternative to ``settings``, you can provide whole configuration
176176+ directly in the almost-YAML format of Knot DNS.
177177+ You might want to utilize ``writeTextFile`` for this.
68178 '';
69179 };
70180···78188 };
79189 };
80190 };
191191+ imports = [
192192+ # Compatibility with NixOS 23.05. At least partial, as it fails assert if used with keyFiles.
193193+ (mkChangedOptionModule [ "services" "knot" "extraConfig" ] [ "services" "knot" "settingsFile" ]
194194+ (config: pkgs.writeText "knot.conf" config.services.knot.extraConfig)
195195+ )
196196+ ];
8119782198 config = mkIf config.services.knot.enable {
83199 users.groups.knot = {};
···86202 group = "knot";
87203 description = "Knot daemon user";
88204 };
205205+206206+ environment.etc."knot/knot.conf".source = configFile; # just for user's convenience
8920790208 systemd.services.knot = {
91209 unitConfig.Documentation = "man:knotd(8) man:knot.conf(5) man:knotc(8) https://www.knot-dns.cz/docs/${cfg.package.version}/html/";