commit 9f2749629dd24d73a0bc2f2fad2e0cd924215ded
parent 7740441dafc72bd4c2d7cd4cdeb73b9fdb5a2ee8
Author: Kirill Elagin <kirelagin@gmail.com>
Date: Wed, 13 Mar 2019 12:11:34 +0100
parent 7740441dafc72bd4c2d7cd4cdeb73b9fdb5a2ee8
Author: Kirill Elagin <kirelagin@gmail.com>
Date: Wed, 13 Mar 2019 12:11:34 +0100
Add support for plain-string simple records As a prerequisite I had to clean up and simplify record name handling.
10 files changed, 85 insertions(+), 83 deletions(-)
M
|
86
++++++++++++++++++++++++++++++++++++++-----------------------------------------
diff --git a/README.md b/README.md @@ -21,7 +21,7 @@ with dns.combinators; { # Sane defaults for the remaining ones }; - NS = map ns [ # Why not `map` over your records? + NS = [ # A zone consists of lists of records grouped by type "ns.test.com." "ns2.test.com." ]; @@ -29,12 +29,12 @@ with dns.combinators; { A = [ { address = "203.0.113.1"; } # Generic A record { address = "203.0.113.2"; ttl = 60 * 60; } # Generic A with TTL - (a "203.0.113.3") # Simple a record create with the `a` combinator + (a "203.0.113.3") # Simple a record created with the `a` combinator (ttl (60 * 60) (a "203.0.113.4")) # Equivalent to the second one ]; AAAA = [ - (aaaa "4321:0:1:2:3:4:567:89ab") + "4321:0:1:2:3:4:567:89ab" # For simple records you can use a plain string ]; CAA = letsEncrypt "admin@example.com"; # Common template combinators included @@ -46,7 +46,7 @@ with dns.combinators; { ]; subdomains = { - www.A = [ (a "203.0.114.1") ]; + www.A = [ "203.0.114.1" ]; staging = delegateTo [ # Another shortcut combinator "ns1.another.com."
diff --git a/dns/types/record.nix b/dns/types/record.nix @@ -8,52 +8,48 @@ let inherit (pkgs) lib; - inherit (lib) const mkOption types; + inherit (lib) const isString mkOption types; + + defaults = { + class = "IN"; + ttl = 24 * 60 * 60; + }; + + recordType = rsubt: + let + submodule = types.submodule { + options = { + class = mkOption { + type = types.enum ["IN"]; + default = defaults.class; + example = "IN"; + description = "Resource record class. Only IN is supported"; + }; + ttl = mkOption { + type = types.ints.unsigned; # TODO: u32 + default = defaults.ttl; + example = 300; + description = "Record caching duration (in seconds)"; + }; + } // rsubt.options; + }; + in + (if rsubt ? fromString then types.either types.str else lib.id) submodule; + + writeRecord = name: rsubt: data: + let + data' = + if isString data && rsubt ? fromString + then defaults // rsubt.fromString data + else data; + name' = rsubt.nameFixup or (n: _: n) name data'; + rtype = rsubt.rtype; + in with data'; + "${name'}. ${toString ttl} ${class} ${rtype} ${rsubt.dataToString data'}"; - recordTypes = import ./records { inherit pkgs; }; in -recordType: name: types.submodule { - options = { - name = mkOption { - type = types.str; - default = name; - example = "example.com"; - description = "Name of the node to which this resource record pertains"; - }; - rtype = mkOption { - type = types.enum (lib.mapAttrsToList (n: v: v.rtype) recordTypes); - readOnly = true; - visible = false; - description = "Type of the record. Do not set this option yourself!"; - }; - _rtype = mkOption { - readOnly = true; - visible = false; - }; - class = mkOption { - type = types.enum ["IN"]; - default = "IN"; - example = "IN"; - description = "Resource record class. Only IN is supported"; - }; - ttl = mkOption { - type = types.ints.unsigned; # TODO: u32 - default = 24 * 60 * 60; - example = 300; - description = "Record caching duration (in seconds)"; - }; - __toString = mkOption { - readOnly = true; - visible = false; - }; - } // recordType.options; - config = { - rtype = recordType.rtype; - _rtype = recordType; - __toString = data@{name, rtype, class, ttl, _rtype, ...}: - let - name' = _rtype.nameFixup or (const name) data; - in "${name'}. ${toString ttl} ${class} ${rtype} ${_rtype.dataToString data}"; - }; +{ + inherit recordType; + inherit writeRecord; }
diff --git a/dns/types/records/A.nix b/dns/types/records/A.nix @@ -21,4 +21,5 @@ in }; }; dataToString = {address, ...}: address; + fromString = address: { inherit address; }; }
diff --git a/dns/types/records/AAAA.nix b/dns/types/records/AAAA.nix @@ -21,4 +21,5 @@ in }; }; dataToString = {address, ...}: address; + fromString = address: { inherit address; }; }
diff --git a/dns/types/records/CNAME.nix b/dns/types/records/CNAME.nix @@ -21,4 +21,5 @@ in }; }; dataToString = {cname, ...}: "${cname}"; + fromString = cname: { inherit cname; }; }
diff --git a/dns/types/records/NS.nix b/dns/types/records/NS.nix @@ -21,4 +21,5 @@ in }; }; dataToString = {nsdname, ...}: "${nsdname}"; + fromString = nsdname: { inherit nsdname; }; }
diff --git a/dns/types/records/SRV.nix b/dns/types/records/SRV.nix @@ -49,6 +49,6 @@ in }; dataToString = data: with data; "${toString priority} ${toString weight} ${toString port} ${target}"; - nameFixup = self: - "_${self.service}._${self.proto}.${self.name}"; + nameFixup = name: self: + "_${self.service}._${self.proto}.${name}"; }
diff --git a/dns/types/records/TXT.nix b/dns/types/records/TXT.nix @@ -21,4 +21,5 @@ in }; }; dataToString = {data, ...}: ''"${data}"''; + fromString = data: { inherit data; }; }
diff --git a/dns/types/zone.nix b/dns/types/zone.nix @@ -7,19 +7,19 @@ { pkgs }: let - inherit (builtins) filter hasAttr map removeAttrs; - inherit (pkgs.lib) concatMapStringsSep concatStringsSep id mapAttrs - optionalString; + inherit (builtins) attrValues filter map removeAttrs; + inherit (pkgs.lib) concatMapStringsSep concatStringsSep mapAttrs + mapAttrsToList optionalString; inherit (pkgs.lib) mkOption types; - record = import ./record.nix { inherit pkgs; }; + inherit (import ./record.nix { inherit pkgs; }) recordType writeRecord; - recordTypes = import ./records { inherit pkgs; }; - recordTypes' = removeAttrs recordTypes ["SOA"]; + rsubtypes = import ./records { inherit pkgs; }; + rsubtypes' = removeAttrs rsubtypes ["SOA"]; - subzoneOptions = name: { + subzoneOptions = { subdomains = mkOption { - type = types.attrsOf (subzone name); + type = types.attrsOf subzone; default = {}; example = { www = { @@ -33,35 +33,33 @@ let }; } // mapAttrs (n: t: mkOption rec { - type = types.listOf (record t name); + type = types.listOf (recordType t); default = []; example = [ t.example ]; description = "List of ${t} records for this zone/subzone"; - }) recordTypes'; + }) rsubtypes'; - subzone = pname: - types.submodule ({name, ...}: { - options = subzoneOptions "${name}.${pname}"; - }); + subzone = types.submodule { + options = subzoneOptions; + }; - writeSubzone = zone: + writeSubzone = name: zone: let - groupToString = n: - concatMapStringsSep "\n" toString (zone."${n}"); - groups = map groupToString (builtins.attrNames recordTypes'); + groupToString = subt: + concatMapStringsSep "\n" (writeRecord name subt) (zone."${subt.rtype}"); + groups = map groupToString (attrValues rsubtypes'); groups' = filter (s: s != "") groups; - sub = concatMapStringsSep "\n\n" writeSubzone (builtins.attrValues zone.subdomains); + writeSubzone' = subname: writeSubzone "${subname}.${name}"; + sub = concatStringsSep "\n\n" (mapAttrsToList writeSubzone' zone.subdomains); in concatStringsSep "\n\n" groups' + optionalString (sub != "") ("\n\n" + sub); -in -rec { zone = types.submodule ({name, ...}: { options = { SOA = mkOption rec { - type = record recordTypes.SOA name; + type = recordType rsubtypes.SOA; example = { ttl = 24 * 60 * 60; } // type.example; @@ -71,16 +69,20 @@ rec { readOnly = true; visible = false; }; - } // subzoneOptions name; + } // subzoneOptions; config = { __toString = zone@{SOA, ...}: '' - ${toString SOA} + ${writeRecord name rsubtypes.SOA SOA} - '' + writeSubzone zone + "\n"; + '' + writeSubzone name zone + "\n"; }; }); +in + +{ + inherit zone; inherit subzone; }
diff --git a/example.nix b/example.nix @@ -14,19 +14,19 @@ let serial = 2019030800; }; - NS = map ns [ + NS = [ "ns.test.com." "ns2.test.com." ]; A = [ { address = "203.0.113.1"; ttl = 60 * 60; } - (a "203.0.113.2") + "203.0.113.2" (ttl (60 * 60) (a "203.0.113.3")) ]; AAAA = [ - (aaaa "4321:0:1:2:3:4:567:89ab") + "4321:0:1:2:3:4:567:89ab" ]; MX = mx.google; @@ -46,14 +46,13 @@ let ]; subdomains = { - www = { - A = map a [ "203.0.113.4" ]; - }; + www.A = [ "203.0.113.4" ]; + staging = delegateTo [ "ns1.another.com." "ns2.another.com." ]; - foo.subdomains.www.CNAME = map cname [ "foo.test.com" ]; + foo.subdomains.www.CNAME = [ "foo.test.com." ]; }; }; in