1{ config 2, lib 3, pkgs 4, ... 5}: 6 7with lib; 8 9let 10 cfg = config.services.kea; 11 12 xor = x: y: (!x && y) || (x && !y); 13 format = pkgs.formats.json {}; 14 15 chooseNotNull = x: y: if x != null then x else y; 16 17 ctrlAgentConfig = chooseNotNull cfg.ctrl-agent.configFile (format.generate "kea-ctrl-agent.conf" { 18 Control-agent = cfg.ctrl-agent.settings; 19 }); 20 21 dhcp4Config = chooseNotNull cfg.dhcp4.configFile (format.generate "kea-dhcp4.conf" { 22 Dhcp4 = cfg.dhcp4.settings; 23 }); 24 25 dhcp6Config = chooseNotNull cfg.dhcp6.configFile (format.generate "kea-dhcp6.conf" { 26 Dhcp6 = cfg.dhcp6.settings; 27 }); 28 29 dhcpDdnsConfig = chooseNotNull cfg.dhcp-ddns.configFile (format.generate "kea-dhcp-ddns.conf" { 30 DhcpDdns = cfg.dhcp-ddns.settings; 31 }); 32 33 package = pkgs.kea; 34in 35{ 36 options.services.kea = with types; { 37 ctrl-agent = mkOption { 38 description = lib.mdDoc '' 39 Kea Control Agent configuration 40 ''; 41 default = {}; 42 type = submodule { 43 options = { 44 enable = mkEnableOption (lib.mdDoc "Kea Control Agent"); 45 46 extraArgs = mkOption { 47 type = listOf str; 48 default = []; 49 description = lib.mdDoc '' 50 List of additional arguments to pass to the daemon. 51 ''; 52 }; 53 54 configFile = mkOption { 55 type = nullOr path; 56 default = null; 57 description = lib.mdDoc '' 58 Kea Control Agent configuration as a path, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/agent.html>. 59 60 Takes preference over [settings](#opt-services.kea.ctrl-agent.settings). 61 Most users should prefer using [settings](#opt-services.kea.ctrl-agent.settings) instead. 62 ''; 63 }; 64 65 settings = mkOption { 66 type = format.type; 67 default = null; 68 description = lib.mdDoc '' 69 Kea Control Agent configuration as an attribute set, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/agent.html>. 70 ''; 71 }; 72 }; 73 }; 74 }; 75 76 dhcp4 = mkOption { 77 description = lib.mdDoc '' 78 DHCP4 Server configuration 79 ''; 80 default = {}; 81 type = submodule { 82 options = { 83 enable = mkEnableOption (lib.mdDoc "Kea DHCP4 server"); 84 85 extraArgs = mkOption { 86 type = listOf str; 87 default = []; 88 description = lib.mdDoc '' 89 List of additional arguments to pass to the daemon. 90 ''; 91 }; 92 93 configFile = mkOption { 94 type = nullOr path; 95 default = null; 96 description = lib.mdDoc '' 97 Kea DHCP4 configuration as a path, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp4-srv.html>. 98 99 Takes preference over [settings](#opt-services.kea.dhcp4.settings). 100 Most users should prefer using [settings](#opt-services.kea.dhcp4.settings) instead. 101 ''; 102 }; 103 104 settings = mkOption { 105 type = format.type; 106 default = null; 107 example = { 108 valid-lifetime = 4000; 109 renew-timer = 1000; 110 rebind-timer = 2000; 111 interfaces-config = { 112 interfaces = [ 113 "eth0" 114 ]; 115 }; 116 lease-database = { 117 type = "memfile"; 118 persist = true; 119 name = "/var/lib/kea/dhcp4.leases"; 120 }; 121 subnet4 = [ { 122 subnet = "192.0.2.0/24"; 123 pools = [ { 124 pool = "192.0.2.100 - 192.0.2.240"; 125 } ]; 126 } ]; 127 }; 128 description = lib.mdDoc '' 129 Kea DHCP4 configuration as an attribute set, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp4-srv.html>. 130 ''; 131 }; 132 }; 133 }; 134 }; 135 136 dhcp6 = mkOption { 137 description = lib.mdDoc '' 138 DHCP6 Server configuration 139 ''; 140 default = {}; 141 type = submodule { 142 options = { 143 enable = mkEnableOption (lib.mdDoc "Kea DHCP6 server"); 144 145 extraArgs = mkOption { 146 type = listOf str; 147 default = []; 148 description = lib.mdDoc '' 149 List of additional arguments to pass to the daemon. 150 ''; 151 }; 152 153 configFile = mkOption { 154 type = nullOr path; 155 default = null; 156 description = lib.mdDoc '' 157 Kea DHCP6 configuration as a path, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp6-srv.html>. 158 159 Takes preference over [settings](#opt-services.kea.dhcp6.settings). 160 Most users should prefer using [settings](#opt-services.kea.dhcp6.settings) instead. 161 ''; 162 }; 163 164 settings = mkOption { 165 type = format.type; 166 default = null; 167 example = { 168 valid-lifetime = 4000; 169 renew-timer = 1000; 170 rebind-timer = 2000; 171 preferred-lifetime = 3000; 172 interfaces-config = { 173 interfaces = [ 174 "eth0" 175 ]; 176 }; 177 lease-database = { 178 type = "memfile"; 179 persist = true; 180 name = "/var/lib/kea/dhcp6.leases"; 181 }; 182 subnet6 = [ { 183 subnet = "2001:db8:1::/64"; 184 pools = [ { 185 pool = "2001:db8:1::1-2001:db8:1::ffff"; 186 } ]; 187 } ]; 188 }; 189 description = lib.mdDoc '' 190 Kea DHCP6 configuration as an attribute set, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp6-srv.html>. 191 ''; 192 }; 193 }; 194 }; 195 }; 196 197 dhcp-ddns = mkOption { 198 description = lib.mdDoc '' 199 Kea DHCP-DDNS configuration 200 ''; 201 default = {}; 202 type = submodule { 203 options = { 204 enable = mkEnableOption (lib.mdDoc "Kea DDNS server"); 205 206 extraArgs = mkOption { 207 type = listOf str; 208 default = []; 209 description = lib.mdDoc '' 210 List of additional arguments to pass to the daemon. 211 ''; 212 }; 213 214 configFile = mkOption { 215 type = nullOr path; 216 default = null; 217 description = lib.mdDoc '' 218 Kea DHCP-DDNS configuration as a path, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/ddns.html>. 219 220 Takes preference over [settings](#opt-services.kea.dhcp-ddns.settings). 221 Most users should prefer using [settings](#opt-services.kea.dhcp-ddns.settings) instead. 222 ''; 223 }; 224 225 settings = mkOption { 226 type = format.type; 227 default = null; 228 example = { 229 ip-address = "127.0.0.1"; 230 port = 53001; 231 dns-server-timeout = 100; 232 ncr-protocol = "UDP"; 233 ncr-format = "JSON"; 234 tsig-keys = [ ]; 235 forward-ddns = { 236 ddns-domains = [ ]; 237 }; 238 reverse-ddns = { 239 ddns-domains = [ ]; 240 }; 241 }; 242 description = lib.mdDoc '' 243 Kea DHCP-DDNS configuration as an attribute set, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/ddns.html>. 244 ''; 245 }; 246 }; 247 }; 248 }; 249 }; 250 251 config = let 252 commonServiceConfig = { 253 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 254 DynamicUser = true; 255 User = "kea"; 256 ConfigurationDirectory = "kea"; 257 RuntimeDirectory = "kea"; 258 StateDirectory = "kea"; 259 UMask = "0077"; 260 }; 261 in mkIf (cfg.ctrl-agent.enable || cfg.dhcp4.enable || cfg.dhcp6.enable || cfg.dhcp-ddns.enable) (mkMerge [ 262 { 263 environment.systemPackages = [ package ]; 264 } 265 266 (mkIf cfg.ctrl-agent.enable { 267 assertions = [{ 268 assertion = xor (cfg.ctrl-agent.settings == null) (cfg.ctrl-agent.configFile == null); 269 message = "Either services.kea.ctrl-agent.settings or services.kea.ctrl-agent.configFile must be set to a non-null value."; 270 }]; 271 272 environment.etc."kea/ctrl-agent.conf".source = ctrlAgentConfig; 273 274 systemd.services.kea-ctrl-agent = { 275 description = "Kea Control Agent"; 276 documentation = [ 277 "man:kea-ctrl-agent(8)" 278 "https://kea.readthedocs.io/en/kea-${package.version}/arm/agent.html" 279 ]; 280 281 after = [ 282 "network-online.target" 283 "time-sync.target" 284 ]; 285 wantedBy = [ 286 "kea-dhcp4-server.service" 287 "kea-dhcp6-server.service" 288 "kea-dhcp-ddns-server.service" 289 ]; 290 291 environment = { 292 KEA_PIDFILE_DIR = "/run/kea"; 293 KEA_LOCKFILE_DIR = "/run/kea"; 294 }; 295 296 restartTriggers = [ 297 ctrlAgentConfig 298 ]; 299 300 serviceConfig = { 301 ExecStart = "${package}/bin/kea-ctrl-agent -c /etc/kea/ctrl-agent.conf ${lib.escapeShellArgs cfg.ctrl-agent.extraArgs}"; 302 KillMode = "process"; 303 Restart = "on-failure"; 304 } // commonServiceConfig; 305 }; 306 }) 307 308 (mkIf cfg.dhcp4.enable { 309 assertions = [{ 310 assertion = xor (cfg.dhcp4.settings == null) (cfg.dhcp4.configFile == null); 311 message = "Either services.kea.dhcp4.settings or services.kea.dhcp4.configFile must be set to a non-null value."; 312 }]; 313 314 environment.etc."kea/dhcp4-server.conf".source = dhcp4Config; 315 316 systemd.services.kea-dhcp4-server = { 317 description = "Kea DHCP4 Server"; 318 documentation = [ 319 "man:kea-dhcp4(8)" 320 "https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp4-srv.html" 321 ]; 322 323 after = [ 324 "network-online.target" 325 "time-sync.target" 326 ]; 327 wantedBy = [ 328 "multi-user.target" 329 ]; 330 331 environment = { 332 KEA_PIDFILE_DIR = "/run/kea"; 333 KEA_LOCKFILE_DIR = "/run/kea"; 334 }; 335 336 restartTriggers = [ 337 dhcp4Config 338 ]; 339 340 serviceConfig = { 341 ExecStart = "${package}/bin/kea-dhcp4 -c /etc/kea/dhcp4-server.conf ${lib.escapeShellArgs cfg.dhcp4.extraArgs}"; 342 # Kea does not request capabilities by itself 343 AmbientCapabilities = [ 344 "CAP_NET_BIND_SERVICE" 345 "CAP_NET_RAW" 346 ]; 347 CapabilityBoundingSet = [ 348 "CAP_NET_BIND_SERVICE" 349 "CAP_NET_RAW" 350 ]; 351 } // commonServiceConfig; 352 }; 353 }) 354 355 (mkIf cfg.dhcp6.enable { 356 assertions = [{ 357 assertion = xor (cfg.dhcp6.settings == null) (cfg.dhcp6.configFile == null); 358 message = "Either services.kea.dhcp6.settings or services.kea.dhcp6.configFile must be set to a non-null value."; 359 }]; 360 361 environment.etc."kea/dhcp6-server.conf".source = dhcp6Config; 362 363 systemd.services.kea-dhcp6-server = { 364 description = "Kea DHCP6 Server"; 365 documentation = [ 366 "man:kea-dhcp6(8)" 367 "https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp6-srv.html" 368 ]; 369 370 after = [ 371 "network-online.target" 372 "time-sync.target" 373 ]; 374 wantedBy = [ 375 "multi-user.target" 376 ]; 377 378 environment = { 379 KEA_PIDFILE_DIR = "/run/kea"; 380 KEA_LOCKFILE_DIR = "/run/kea"; 381 }; 382 383 restartTriggers = [ 384 dhcp6Config 385 ]; 386 387 serviceConfig = { 388 ExecStart = "${package}/bin/kea-dhcp6 -c /etc/kea/dhcp6-server.conf ${lib.escapeShellArgs cfg.dhcp6.extraArgs}"; 389 # Kea does not request capabilities by itself 390 AmbientCapabilities = [ 391 "CAP_NET_BIND_SERVICE" 392 ]; 393 CapabilityBoundingSet = [ 394 "CAP_NET_BIND_SERVICE" 395 ]; 396 } // commonServiceConfig; 397 }; 398 }) 399 400 (mkIf cfg.dhcp-ddns.enable { 401 assertions = [{ 402 assertion = xor (cfg.dhcp-ddns.settings == null) (cfg.dhcp-ddns.configFile == null); 403 message = "Either services.kea.dhcp-ddns.settings or services.kea.dhcp-ddns.configFile must be set to a non-null value."; 404 }]; 405 406 environment.etc."kea/dhcp-ddns.conf".source = dhcpDdnsConfig; 407 408 systemd.services.kea-dhcp-ddns-server = { 409 description = "Kea DHCP-DDNS Server"; 410 documentation = [ 411 "man:kea-dhcp-ddns(8)" 412 "https://kea.readthedocs.io/en/kea-${package.version}/arm/ddns.html" 413 ]; 414 415 after = [ 416 "network-online.target" 417 "time-sync.target" 418 ]; 419 wantedBy = [ 420 "multi-user.target" 421 ]; 422 423 environment = { 424 KEA_PIDFILE_DIR = "/run/kea"; 425 KEA_LOCKFILE_DIR = "/run/kea"; 426 }; 427 428 restartTriggers = [ 429 dhcpDdnsConfig 430 ]; 431 432 serviceConfig = { 433 ExecStart = "${package}/bin/kea-dhcp-ddns -c /etc/kea/dhcp-ddns.conf ${lib.escapeShellArgs cfg.dhcp-ddns.extraArgs}"; 434 AmbientCapabilities = [ 435 "CAP_NET_BIND_SERVICE" 436 ]; 437 CapabilityBoundingSet = [ 438 "CAP_NET_BIND_SERVICE" 439 ]; 440 } // commonServiceConfig; 441 }; 442 }) 443 444 ]); 445 446 meta.maintainers = with maintainers; [ hexa ]; 447 # uses attributes of the linked package 448 meta.buildDocsInSandbox = false; 449}