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