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