keepalived service: init (#22755)

wip/yesman
Marius Bergmann 7 years ago committed by Joachim F
parent f47921f3d4
commit 6572f5e81b
  1. 1
      nixos/modules/module-list.nix
  2. 245
      nixos/modules/services/networking/keepalived/default.nix
  3. 50
      nixos/modules/services/networking/keepalived/virtual-ip-options.nix
  4. 121
      nixos/modules/services/networking/keepalived/vrrp-options.nix

@ -420,6 +420,7 @@
./services/networking/i2p.nix
./services/networking/iodine.nix
./services/networking/ircd-hybrid/default.nix
./services/networking/keepalived/default.nix
./services/networking/kippo.nix
./services/networking/kresd.nix
./services/networking/lambdabot.nix

@ -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";
};
};
};
}

@ -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.
'';
};
};
}

@ -0,0 +1,121 @@
{ lib } :
with lib;
{
options = {
interface = mkOption {
type = types.str;
description = ''
Interface for inside_network, bound by vrrp.
'';
};
state = mkOption {
type = types.enum [ "MASTER" "BACKUP" ];
default = "BACKUP";
description = ''
Initial state. As soon as the other machine(s) come up, an election will
be held and the machine with the highest "priority" will become MASTER.
So the entry here doesn't matter a whole lot.
'';
};
virtualRouterId = mkOption {
type = types.int;
description = ''
Arbitrary unique number 0..255. Used to differentiate multiple instances
of vrrpd running on the same NIC (and hence same socket).
'';
};
priority = mkOption {
type = types.int;
default = 100;
description = ''
For electing MASTER, highest priority wins. To be MASTER, make 50 more
than other machines.
'';
};
noPreempt = mkOption {
type = types.bool;
default = false;
description = ''
VRRP will normally preempt a lower priority machine when a higher
priority machine comes online. "nopreempt" allows the lower priority
machine to maintain the master role, even when a higher priority machine
comes back online. NOTE: For this to work, the initial state of this
entry must be BACKUP.
'';
};
useVmac = mkOption {
type = types.bool;
default = false;
description = ''
Use VRRP Virtual MAC.
'';
};
vmacInterface = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Name of the vmac interface to use. keepalived will come up with a name
if you don't specify one.
'';
};
vmacXmitBase = mkOption {
type = types.bool;
default = false;
description = ''
Send/Recv VRRP messages from base interface instead of VMAC interface.
'';
};
unicastSrcIp = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Default IP for binding vrrpd is the primary IP on interface. If you
want to hide location of vrrpd, use this IP as src_addr for unicast
vrrp packets.
'';
};
unicastPeers = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Do not send VRRP adverts over VRRP multicast group. Instead it sends
adverts to the following list of ip addresses using unicast design
fashion. It can be cool to use VRRP FSM and features in a networking
environment where multicast is not supported! IP Addresses specified can
IPv4 as well as IPv6.
'';
};
virtualIps = mkOption {
type = types.listOf (types.submodule (import ./virtual-ip-options.nix {
inherit lib;
}));
default = [];
example = literalExample ''
TODO: Example
'';
description = "Declarative vhost config";
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = ''
Extra lines to be added verbatim to the vrrp_instance section.
'';
};
};
}
Loading…
Cancel
Save