Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
417 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
245 changes: 245 additions & 0 deletions
245
nixos/modules/services/networking/keepalived/default.nix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,245 @@ | ||
{ config, lib, pkgs, ... }: | ||
|
||
with lib; | ||
|
||
let | ||
|
||
cfg = config.services.keepalived; | ||
|
||
keepalivedConf = pkgs.writeText "keepalived.conf" '' | ||
global_defs { | ||
${snmpGlobalDefs} | ||
${cfg.extraGlobalDefs} | ||
} | ||
${vrrpInstancesStr} | ||
${cfg.extraConfig} | ||
''; | ||
|
||
snmpGlobalDefs = with cfg.snmp; optionalString enable ( | ||
optionalString (socket != null) "snmp_socket ${socket}\n" | ||
+ optionalString enableKeepalived "enable_snmp_keepalived\n" | ||
+ optionalString enableChecker "enable_snmp_checker\n" | ||
+ optionalString enableRfc "enable_snmp_rfc\n" | ||
+ optionalString enableRfcV2 "enable_snmp_rfcv2\n" | ||
+ optionalString enableRfcV3 "enable_snmp_rfcv3\n" | ||
+ optionalString enableTraps "enable_traps" | ||
); | ||
|
||
vrrpInstancesStr = concatStringsSep "\n" (map (i: | ||
'' | ||
vrrp_instance ${i.name} { | ||
interface ${i.interface} | ||
state ${i.state} | ||
virtual_router_id ${toString i.virtualRouterId} | ||
priority ${toString i.priority} | ||
${optionalString i.noPreempt "nopreempt"} | ||
${optionalString i.useVmac ( | ||
"use_vmac" + optionalString (i.vmacInterface != null) " ${i.vmacInterface}" | ||
)} | ||
${optionalString i.vmacXmitBase "vmac_xmit_base"} | ||
${optionalString (i.unicastSrcIp != null) "unicast_src_ip ${i.unicastSrcIp}"} | ||
unicast_peer { | ||
${concatStringsSep "\n" i.unicastPeers} | ||
} | ||
virtual_ipaddress { | ||
${concatMapStringsSep "\n" virtualIpLine i.virtualIps} | ||
} | ||
${i.extraConfig} | ||
} | ||
'' | ||
) vrrpInstances); | ||
|
||
virtualIpLine = (ip: | ||
ip.addr | ||
+ optionalString (notNullOrEmpty ip.brd) " brd ${ip.brd}" | ||
+ optionalString (notNullOrEmpty ip.dev) " dev ${ip.dev}" | ||
+ optionalString (notNullOrEmpty ip.scope) " scope ${ip.scope}" | ||
+ optionalString (notNullOrEmpty ip.label) " label ${ip.label}" | ||
); | ||
|
||
notNullOrEmpty = s: !(s == null || s == ""); | ||
|
||
vrrpInstances = mapAttrsToList (iName: iConfig: | ||
{ | ||
name = iName; | ||
} // iConfig | ||
) cfg.vrrpInstances; | ||
|
||
vrrpInstanceAssertions = i: [ | ||
{ assertion = i.interface != ""; | ||
message = "services.keepalived.vrrpInstances.${i.name}.interface option cannot be empty."; | ||
} | ||
{ assertion = i.virtualRouterId >= 0 && i.virtualRouterId <= 255; | ||
message = "services.keepalived.vrrpInstances.${i.name}.virtualRouterId must be an integer between 0..255."; | ||
} | ||
{ assertion = i.priority >= 0 && i.priority <= 255; | ||
message = "services.keepalived.vrrpInstances.${i.name}.priority must be an integer between 0..255."; | ||
} | ||
{ assertion = i.vmacInterface == null || i.useVmac; | ||
message = "services.keepalived.vrrpInstances.${i.name}.vmacInterface has no effect when services.keepalived.vrrpInstances.${i.name}.useVmac is not set."; | ||
} | ||
{ assertion = !i.vmacXmitBase || i.useVmac; | ||
message = "services.keepalived.vrrpInstances.${i.name}.vmacXmitBase has no effect when services.keepalived.vrrpInstances.${i.name}.useVmac is not set."; | ||
} | ||
] ++ flatten (map (virtualIpAssertions i.name) i.virtualIps); | ||
|
||
virtualIpAssertions = vrrpName: ip: [ | ||
{ assertion = ip.addr != ""; | ||
message = "The 'addr' option for an services.keepalived.vrrpInstances.${vrrpName}.virtualIps entry cannot be empty."; | ||
} | ||
]; | ||
|
||
pidFile = "/run/keepalived.pid"; | ||
|
||
in | ||
{ | ||
|
||
options = { | ||
services.keepalived = { | ||
|
||
enable = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = '' | ||
Whether to enable Keepalived. | ||
''; | ||
}; | ||
|
||
snmp = { | ||
|
||
enable = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = '' | ||
Whether to enable the builtin AgentX subagent. | ||
''; | ||
}; | ||
|
||
socket = mkOption { | ||
type = types.nullOr types.str; | ||
default = null; | ||
description = '' | ||
Socket to use for connecting to SNMP master agent. If this value is | ||
set to null, keepalived's default will be used, which is | ||
unix:/var/agentx/master, unless using a network namespace, when the | ||
default is udp:localhost:705. | ||
''; | ||
}; | ||
|
||
enableKeepalived = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = '' | ||
Enable SNMP handling of vrrp element of KEEPALIVED MIB. | ||
''; | ||
}; | ||
|
||
enableChecker = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = '' | ||
Enable SNMP handling of checker element of KEEPALIVED MIB. | ||
''; | ||
}; | ||
|
||
enableRfc = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = '' | ||
Enable SNMP handling of RFC2787 and RFC6527 VRRP MIBs. | ||
''; | ||
}; | ||
|
||
enableRfcV2 = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = '' | ||
Enable SNMP handling of RFC2787 VRRP MIB. | ||
''; | ||
}; | ||
|
||
enableRfcV3 = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = '' | ||
Enable SNMP handling of RFC6527 VRRP MIB. | ||
''; | ||
}; | ||
|
||
enableTraps = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = '' | ||
Enable SNMP traps. | ||
''; | ||
}; | ||
|
||
}; | ||
|
||
vrrpInstances = mkOption { | ||
type = types.attrsOf (types.submodule (import ./vrrp-options.nix { | ||
inherit lib; | ||
})); | ||
default = {}; | ||
description = "Declarative vhost config"; | ||
}; | ||
|
||
extraGlobalDefs = mkOption { | ||
type = types.lines; | ||
default = ""; | ||
description = '' | ||
Extra lines to be added verbatim to the 'global_defs' block of the | ||
configuration file | ||
''; | ||
}; | ||
|
||
extraConfig = mkOption { | ||
type = types.lines; | ||
default = ""; | ||
description = '' | ||
Extra lines to be added verbatim to the configuration file. | ||
''; | ||
}; | ||
|
||
}; | ||
}; | ||
|
||
config = mkIf cfg.enable { | ||
|
||
assertions = flatten (map vrrpInstanceAssertions vrrpInstances); | ||
|
||
systemd.timers.keepalived-boot-delay = { | ||
description = "Keepalive Daemon delay to avoid instant transition to MASTER state"; | ||
after = [ "network.target" "network-online.target" "syslog.target" ]; | ||
requires = [ "network-online.target" ]; | ||
wantedBy = [ "multi-user.target" ]; | ||
timerConfig = { | ||
OnActiveSec = "5s"; | ||
Unit = "keepalived.service"; | ||
}; | ||
}; | ||
|
||
systemd.services.keepalived = { | ||
description = "Keepalive Daemon (LVS and VRRP)"; | ||
after = [ "network.target" "network-online.target" "syslog.target" ]; | ||
wants = [ "network-online.target" ]; | ||
serviceConfig = { | ||
Type = "forking"; | ||
PIDFile = pidFile; | ||
KillMode = "process"; | ||
ExecStart = "${pkgs.keepalived}/sbin/keepalived" | ||
+ " -f ${keepalivedConf}" | ||
+ " -p ${pidFile}" | ||
+ optionalString cfg.snmp.enable " --snmp"; | ||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; | ||
Restart = "always"; | ||
RestartSec = "1s"; | ||
}; | ||
}; | ||
}; | ||
} |
50 changes: 50 additions & 0 deletions
50
nixos/modules/services/networking/keepalived/virtual-ip-options.nix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
{ lib } : | ||
|
||
with lib; | ||
{ | ||
options = { | ||
|
||
addr = mkOption { | ||
type = types.str; | ||
description = '' | ||
IP address, optionally with a netmask: IPADDR[/MASK] | ||
''; | ||
}; | ||
|
||
brd = mkOption { | ||
type = types.nullOr types.str; | ||
default = null; | ||
description = '' | ||
The broadcast address on the interface. | ||
''; | ||
}; | ||
|
||
dev = mkOption { | ||
type = types.nullOr types.str; | ||
default = null; | ||
description = '' | ||
The name of the device to add the address to. | ||
''; | ||
}; | ||
|
||
scope = mkOption { | ||
type = types.nullOr types.str; | ||
default = null; | ||
description = '' | ||
The scope of the area where this address is valid. | ||
''; | ||
}; | ||
|
||
label = mkOption { | ||
type = types.nullOr types.str; | ||
default = null; | ||
description = '' | ||
Each address may be tagged with a label string. In order to preserve | ||
compatibility with Linux-2.0 net aliases, this string must coincide with | ||
the name of the device or must be prefixed with the device name followed | ||
by colon. | ||
''; | ||
}; | ||
|
||
}; | ||
} |
Oops, something went wrong.