keepalived service: init (#22755)
This commit is contained in:
parent
f47921f3d4
commit
6572f5e81b
|
@ -420,6 +420,7 @@
|
||||||
./services/networking/i2p.nix
|
./services/networking/i2p.nix
|
||||||
./services/networking/iodine.nix
|
./services/networking/iodine.nix
|
||||||
./services/networking/ircd-hybrid/default.nix
|
./services/networking/ircd-hybrid/default.nix
|
||||||
|
./services/networking/keepalived/default.nix
|
||||||
./services/networking/kippo.nix
|
./services/networking/kippo.nix
|
||||||
./services/networking/kresd.nix
|
./services/networking/kresd.nix
|
||||||
./services/networking/lambdabot.nix
|
./services/networking/lambdabot.nix
|
||||||
|
|
245
nixos/modules/services/networking/keepalived/default.nix
Normal file
245
nixos/modules/services/networking/keepalived/default.nix
Normal file
|
@ -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.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
121
nixos/modules/services/networking/keepalived/vrrp-options.nix
Normal file
121
nixos/modules/services/networking/keepalived/vrrp-options.nix
Normal file
|
@ -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…
Reference in a new issue