Merge pull request #126785 from oxzi/ucarp-1.5.2
ucarp: init at 1.5.2 / nixos/ucarp: init / nixos/test/ucarp: init
This commit is contained in:
commit
5ad54b5bc9
8 changed files with 293 additions and 0 deletions
|
@ -40,6 +40,14 @@
|
|||
<link xlink:href="options.html#opt-services.sourcehut.enable">services.sourcehut</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xlink:href="https://download.pureftpd.org/pub/ucarp/README">ucarp</link>,
|
||||
an userspace implementation of the Common Address Redundancy
|
||||
Protocol (CARP). Available as
|
||||
<link xlink:href="options.html#opt-networking.ucarp.enable">networking.ucarp</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section xml:id="backward-incompatibilities">
|
||||
|
|
|
@ -18,6 +18,10 @@ In addition to numerous new and upgraded packages, this release has the followin
|
|||
development. Available as
|
||||
[services.sourcehut](options.html#opt-services.sourcehut.enable).
|
||||
|
||||
* [ucarp](https://download.pureftpd.org/pub/ucarp/README), an userspace
|
||||
implementation of the Common Address Redundancy Protocol (CARP). Available as
|
||||
[networking.ucarp](options.html#opt-networking.ucarp.enable).
|
||||
|
||||
## Backward Incompatibilities
|
||||
|
||||
* The `staticjinja` package has been upgraded from 1.0.4 to 2.0.0
|
||||
|
|
|
@ -839,6 +839,7 @@
|
|||
./services/networking/tox-node.nix
|
||||
./services/networking/toxvpn.nix
|
||||
./services/networking/tvheadend.nix
|
||||
./services/networking/ucarp.nix
|
||||
./services/networking/unbound.nix
|
||||
./services/networking/unifi.nix
|
||||
./services/networking/v2ray.nix
|
||||
|
|
183
nixos/modules/services/networking/ucarp.nix
Normal file
183
nixos/modules/services/networking/ucarp.nix
Normal file
|
@ -0,0 +1,183 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.networking.ucarp;
|
||||
|
||||
ucarpExec = concatStringsSep " " (
|
||||
[
|
||||
"${cfg.package}/bin/ucarp"
|
||||
"--interface=${cfg.interface}"
|
||||
"--srcip=${cfg.srcIp}"
|
||||
"--vhid=${toString cfg.vhId}"
|
||||
"--passfile=${cfg.passwordFile}"
|
||||
"--addr=${cfg.addr}"
|
||||
"--advbase=${toString cfg.advBase}"
|
||||
"--advskew=${toString cfg.advSkew}"
|
||||
"--upscript=${cfg.upscript}"
|
||||
"--downscript=${cfg.downscript}"
|
||||
"--deadratio=${toString cfg.deadratio}"
|
||||
]
|
||||
++ (optional cfg.preempt "--preempt")
|
||||
++ (optional cfg.neutral "--neutral")
|
||||
++ (optional cfg.shutdown "--shutdown")
|
||||
++ (optional cfg.ignoreIfState "--ignoreifstate")
|
||||
++ (optional cfg.noMcast "--nomcast")
|
||||
++ (optional (cfg.extraParam != null) "--xparam=${cfg.extraParam}")
|
||||
);
|
||||
in {
|
||||
options.networking.ucarp = {
|
||||
enable = mkEnableOption "ucarp, userspace implementation of CARP";
|
||||
|
||||
interface = mkOption {
|
||||
type = types.str;
|
||||
description = "Network interface to bind to.";
|
||||
example = "eth0";
|
||||
};
|
||||
|
||||
srcIp = mkOption {
|
||||
type = types.str;
|
||||
description = "Source (real) IP address of this host.";
|
||||
};
|
||||
|
||||
vhId = mkOption {
|
||||
type = types.ints.between 1 255;
|
||||
description = "Virtual IP identifier shared between CARP hosts.";
|
||||
example = 1;
|
||||
};
|
||||
|
||||
passwordFile = mkOption {
|
||||
type = types.str;
|
||||
description = "File containing shared password between CARP hosts.";
|
||||
example = "/run/keys/ucarp-password";
|
||||
};
|
||||
|
||||
preempt = mkOption {
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Enable preemptive failover.
|
||||
Thus, this host becomes the CARP master as soon as possible.
|
||||
'';
|
||||
default = false;
|
||||
};
|
||||
|
||||
neutral = mkOption {
|
||||
type = types.bool;
|
||||
description = "Do not run downscript at start if the host is the backup.";
|
||||
default = false;
|
||||
};
|
||||
|
||||
addr = mkOption {
|
||||
type = types.str;
|
||||
description = "Virtual shared IP address.";
|
||||
};
|
||||
|
||||
advBase = mkOption {
|
||||
type = types.ints.unsigned;
|
||||
description = "Advertisement frequency in seconds.";
|
||||
default = 1;
|
||||
};
|
||||
|
||||
advSkew = mkOption {
|
||||
type = types.ints.unsigned;
|
||||
description = "Advertisement skew in seconds.";
|
||||
default = 0;
|
||||
};
|
||||
|
||||
upscript = mkOption {
|
||||
type = types.path;
|
||||
description = ''
|
||||
Command to run after become master, the interface name, virtual address
|
||||
and optional extra parameters are passed as arguments.
|
||||
'';
|
||||
example = ''
|
||||
pkgs.writeScript "upscript" '''
|
||||
#!/bin/sh
|
||||
$\{pkgs.iproute2\}/bin/ip addr add "$2"/24 dev "$1"
|
||||
''';
|
||||
'';
|
||||
};
|
||||
|
||||
downscript = mkOption {
|
||||
type = types.path;
|
||||
description = ''
|
||||
Command to run after become backup, the interface name, virtual address
|
||||
and optional extra parameters are passed as arguments.
|
||||
'';
|
||||
example = ''
|
||||
pkgs.writeScript "downscript" '''
|
||||
#!/bin/sh
|
||||
$\{pkgs.iproute2\}/bin/ip addr del "$2"/24 dev "$1"
|
||||
''';
|
||||
'';
|
||||
};
|
||||
|
||||
deadratio = mkOption {
|
||||
type = types.ints.unsigned;
|
||||
description = "Ratio to consider a host as dead.";
|
||||
default = 3;
|
||||
};
|
||||
|
||||
shutdown = mkOption {
|
||||
type = types.bool;
|
||||
description = "Call downscript at exit.";
|
||||
default = false;
|
||||
};
|
||||
|
||||
ignoreIfState = mkOption {
|
||||
type = types.bool;
|
||||
description = "Ignore interface state, e.g., down or no carrier.";
|
||||
default = false;
|
||||
};
|
||||
|
||||
noMcast = mkOption {
|
||||
type = types.bool;
|
||||
description = "Use broadcast instead of multicast advertisements.";
|
||||
default = false;
|
||||
};
|
||||
|
||||
extraParam = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
description = "Extra parameter to pass to the up/down scripts.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
description = ''
|
||||
Package that should be used for ucarp.
|
||||
|
||||
Please note that the default package, pkgs.ucarp, has not received any
|
||||
upstream updates for a long time and can be considered as unmaintained.
|
||||
'';
|
||||
default = pkgs.ucarp;
|
||||
defaultText = "pkgs.ucarp";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.ucarp = {
|
||||
description = "ucarp, userspace implementation of CARP";
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
ExecStart = ucarpExec;
|
||||
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = true;
|
||||
PrivateTmp = true;
|
||||
ProtectClock = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectControlGroups = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
RestrictRealtime = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ oxzi ];
|
||||
}
|
|
@ -433,6 +433,7 @@ in
|
|||
trilium-server = handleTestOn ["x86_64-linux"] ./trilium-server.nix {};
|
||||
tuptime = handleTest ./tuptime.nix {};
|
||||
turbovnc-headless-server = handleTest ./turbovnc-headless-server.nix {};
|
||||
ucarp = handleTest ./ucarp.nix {};
|
||||
ucg = handleTest ./ucg.nix {};
|
||||
udisks2 = handleTest ./udisks2.nix {};
|
||||
unbound = handleTest ./unbound.nix {};
|
||||
|
|
66
nixos/tests/ucarp.nix
Normal file
66
nixos/tests/ucarp.nix
Normal file
|
@ -0,0 +1,66 @@
|
|||
import ./make-test-python.nix ({ pkgs, lib, ...} :
|
||||
|
||||
let
|
||||
addrShared = "192.168.0.1";
|
||||
addrHostA = "192.168.0.10";
|
||||
addrHostB = "192.168.0.11";
|
||||
|
||||
mkUcarpHost = addr: { config, pkgs, lib, ... }: {
|
||||
networking.interfaces.eth1.ipv4.addresses = lib.mkForce [
|
||||
{ address = addr; prefixLength = 24; }
|
||||
];
|
||||
|
||||
networking.ucarp = {
|
||||
enable = true;
|
||||
interface = "eth1";
|
||||
srcIp = addr;
|
||||
vhId = 1;
|
||||
passwordFile = "${pkgs.writeText "ucarp-pass" "secure"}";
|
||||
addr = addrShared;
|
||||
upscript = pkgs.writeScript "upscript" ''
|
||||
#!/bin/sh
|
||||
${pkgs.iproute2}/bin/ip addr add "$2"/24 dev "$1"
|
||||
'';
|
||||
downscript = pkgs.writeScript "downscript" ''
|
||||
#!/bin/sh
|
||||
${pkgs.iproute2}/bin/ip addr del "$2"/24 dev "$1"
|
||||
'';
|
||||
};
|
||||
};
|
||||
in {
|
||||
name = "ucarp";
|
||||
meta.maintainers = with lib.maintainers; [ oxzi ];
|
||||
|
||||
nodes = {
|
||||
hostA = mkUcarpHost addrHostA;
|
||||
hostB = mkUcarpHost addrHostB;
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
def is_master(host):
|
||||
ipOutput = host.succeed("ip addr show dev eth1")
|
||||
return "inet ${addrShared}/24" in ipOutput
|
||||
|
||||
|
||||
start_all()
|
||||
|
||||
# First, let both hosts start and let a master node be selected
|
||||
for host, peer in [(hostA, "${addrHostB}"), (hostB, "${addrHostA}")]:
|
||||
host.wait_for_unit("ucarp.service")
|
||||
host.succeed(f"ping -c 1 {peer}")
|
||||
|
||||
hostA.sleep(5)
|
||||
|
||||
hostA_master, hostB_master = is_master(hostA), is_master(hostB)
|
||||
assert hostA_master != hostB_master, "only one master node is allowed"
|
||||
|
||||
master_host = hostA if hostA_master else hostB
|
||||
backup_host = hostB if hostA_master else hostA
|
||||
|
||||
# Let's crash the master host and let the backup take over
|
||||
master_host.crash()
|
||||
|
||||
backup_host.sleep(5)
|
||||
assert is_master(backup_host), "backup did not take over"
|
||||
'';
|
||||
})
|
28
pkgs/servers/ucarp/default.nix
Normal file
28
pkgs/servers/ucarp/default.nix
Normal file
|
@ -0,0 +1,28 @@
|
|||
{ stdenv, lib, fetchurl, libpcap }:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "ucarp";
|
||||
version = "1.5.2";
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://download.pureftpd.org/pub/ucarp/ucarp-${version}.tar.bz2";
|
||||
sha256 = "0qidz5sr55nxlmnl8kcbjsrff2j97b44h9l1dmhvvjl46iji7q7j";
|
||||
};
|
||||
|
||||
buildInputs = [ libpcap ];
|
||||
|
||||
meta = with lib; {
|
||||
description = "Userspace implementation of CARP";
|
||||
longDescription = ''
|
||||
UCARP allows a couple of hosts to share common virtual IP addresses in
|
||||
order to provide automatic failover. It is a portable userland
|
||||
implementation of the secure and patent-free Common Address Redundancy
|
||||
Protocol (CARP, OpenBSD's alternative to the patents-bloated VRRP).
|
||||
|
||||
Warning: This package has not received any upstream updates for a long
|
||||
time and can be considered as unmaintained.
|
||||
'';
|
||||
license = with licenses; [ isc bsdOriginal bsd2 gpl2Plus ];
|
||||
maintainers = with maintainers; [ oxzi ];
|
||||
};
|
||||
}
|
|
@ -9403,6 +9403,8 @@ in
|
|||
|
||||
ubertooth = callPackage ../applications/radio/ubertooth { };
|
||||
|
||||
ucarp = callPackage ../servers/ucarp { };
|
||||
|
||||
ucl = callPackage ../development/libraries/ucl { };
|
||||
|
||||
ucspi-tcp = callPackage ../tools/networking/ucspi-tcp { };
|
||||
|
|
Loading…
Reference in a new issue