aboutsummaryrefslogtreecommitdiff
path: root/nixpkgs/nixos/modules/services/networking/keepalived/default.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/services/networking/keepalived/default.nix')
-rw-r--r--nixpkgs/nixos/modules/services/networking/keepalived/default.nix303
1 files changed, 303 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/services/networking/keepalived/default.nix b/nixpkgs/nixos/modules/services/networking/keepalived/default.nix
new file mode 100644
index 00000000000..c9ac2ee2599
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/keepalived/default.nix
@@ -0,0 +1,303 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ cfg = config.services.keepalived;
+
+ keepalivedConf = pkgs.writeText "keepalived.conf" ''
+ global_defs {
+ ${optionalString cfg.enableScriptSecurity "enable_script_security"}
+ ${snmpGlobalDefs}
+ ${cfg.extraGlobalDefs}
+ }
+
+ ${vrrpScriptStr}
+ ${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"
+ );
+
+ vrrpScriptStr = concatStringsSep "\n" (map (s:
+ ''
+ vrrp_script ${s.name} {
+ script "${s.script}"
+ interval ${toString s.interval}
+ fall ${toString s.fall}
+ rise ${toString s.rise}
+ timeout ${toString s.timeout}
+ weight ${toString s.weight}
+ user ${s.user} ${optionalString (s.group != null) s.group}
+
+ ${s.extraConfig}
+ }
+ ''
+ ) vrrpScripts);
+
+ 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}
+ }
+
+ ${optionalString (builtins.length i.trackScripts > 0) ''
+ track_script {
+ ${concatStringsSep "\n" i.trackScripts}
+ }
+ ''}
+
+ ${optionalString (builtins.length i.trackInterfaces > 0) ''
+ track_interface {
+ ${concatStringsSep "\n" i.trackInterfaces}
+ }
+ ''}
+
+ ${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 == "");
+
+ vrrpScripts = mapAttrsToList (name: config:
+ {
+ inherit name;
+ } // config
+ ) cfg.vrrpScripts;
+
+ 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)
+ ++ flatten (map (vrrpScriptAssertion i.name) i.trackScripts);
+
+ virtualIpAssertions = vrrpName: ip: [
+ { assertion = ip.addr != "";
+ message = "The 'addr' option for an services.keepalived.vrrpInstances.${vrrpName}.virtualIps entry cannot be empty.";
+ }
+ ];
+
+ vrrpScriptAssertion = vrrpName: scriptName: {
+ assertion = builtins.hasAttr scriptName cfg.vrrpScripts;
+ message = "services.keepalived.vrrpInstances.${vrrpName} trackscript ${scriptName} is not defined in services.keepalived.vrrpScripts.";
+ };
+
+ pidFile = "/run/keepalived.pid";
+
+in
+{
+
+ options = {
+ services.keepalived = {
+
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable Keepalived.
+ '';
+ };
+
+ enableScriptSecurity = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Don't run scripts configured to be run as root if any part of the path is writable by a non-root user.
+ '';
+ };
+
+ 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.
+ '';
+ };
+
+ };
+
+ vrrpScripts = mkOption {
+ type = types.attrsOf (types.submodule (import ./vrrp-script-options.nix {
+ inherit lib;
+ }));
+ default = {};
+ description = "Declarative vrrp script config";
+ };
+
+ vrrpInstances = mkOption {
+ type = types.attrsOf (types.submodule (import ./vrrp-instance-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";
+ };
+ };
+ };
+}