feat(pacemaker): make VIPs a list of sets and impl dependsOn
All checks were successful
Discord / discord commits (push) Has been skipped

This commit is contained in:
matt1432 2024-01-23 12:26:49 -05:00
parent 33f3d60f1c
commit 711d088988
2 changed files with 102 additions and 60 deletions

View file

@ -13,7 +13,13 @@
resources = { resources = {
"caddy" = { "caddy" = {
enable = true; enable = true;
virtualIp = "10.0.0.130"; virtualIps = [
{
id = "main";
interface = "eno1";
ip = "10.0.0.130";
}
];
}; };
}; };
}; };

View file

@ -12,6 +12,7 @@
concatMapStringsSep concatMapStringsSep
elemAt elemAt
filterAttrs filterAttrs
isAttrs
mkIf mkIf
mkOption mkOption
types types
@ -25,11 +26,6 @@ in {
imports = ["${nixpkgs-pacemaker}/nixos/modules/${pacemakerPath}"]; imports = ["${nixpkgs-pacemaker}/nixos/modules/${pacemakerPath}"];
options.services.pacemaker = { options.services.pacemaker = {
networkInterface = mkOption {
default = "eno1";
type = types.str;
};
resources = mkOption { resources = mkOption {
default = {}; default = {};
type = with types; type = with types;
@ -45,14 +41,36 @@ in {
type = types.str; type = types.str;
}; };
virtualIp = mkOption { # TODO: add assertion to not have same id
default = null; virtualIps = mkOption {
type = types.nullOr types.str; default = [];
type = with types;
listOf (submodule {
options = {
id = mkOption {
type = types.str;
}; };
interface = mkOption {
default = "eno1";
type = types.str;
};
ip = mkOption {
type = types.str;
};
cidr = mkOption {
default = 24;
type = types.int;
};
};
});
};
# TODO: add assertion, needs to be an existing systemdName
dependsOn = mkOption { dependsOn = mkOption {
default = []; default = [];
# TODO: implement dependsOn
type = types.listOf types.str; type = types.listOf types.str;
}; };
@ -64,46 +82,48 @@ in {
config = mkIf cfg.enable { config = mkIf cfg.enable {
systemd.services = let systemd.services = let
mkVirtIp = res: '' mkVirtIps = res:
<primitive class="ocf" id="${res.systemdName}vip" provider="heartbeat" type="IPaddr2"> concatMapStringsSep "\n" (vip: ''
<instance_attributes id="${res.systemdName}vip-attrs"> <primitive class="ocf" id="${res.systemdName}-${vip.id}-vip" provider="heartbeat" type="IPaddr2">
<instance_attributes id="${res.systemdName}-${vip.id}-vip-attrs">
<nvpair <nvpair
id="${res.systemdName}vip-attrs-cidr_netmask" id="${res.systemdName}-${vip.id}-vip-attrs-cidr_netmask"
name="cidr_netmask" name="cidr_netmask"
value="24" value="${toString vip.cidr}"
/> />
<nvpair <nvpair
id="${res.systemdName}vip-attrs-ip" id="${res.systemdName}-${vip.id}-vip-attrs-ip"
name="ip" name="ip"
value="${res.virtualIp}" value="${vip.ip}"
/> />
<nvpair <nvpair
id="${res.systemdName}vip-attrs-nic" id="${res.systemdName}-${vip.id}-vip-attrs-nic"
name="nic" name="nic"
value="${cfg.networkInterface}" value="${vip.interface}"
/> />
</instance_attributes> </instance_attributes>
<operations> <operations>
<op <op
id="${res.systemdName}vip-monitor-interval-30s" id="${res.systemdName}-${vip.id}-vip-monitor-interval-30s"
interval="30s" interval="30s"
name="monitor" name="monitor"
/> />
<op <op
id="${res.systemdName}vip-start-interval-0s" id="${res.systemdName}-${vip.id}-vip-start-interval-0s"
interval="0s" interval="0s"
name="start" name="start"
timeout="20s" timeout="20s"
/> />
<op <op
id="${res.systemdName}vip-stop-interval-0s" id="${res.systemdName}-${vip.id}-vip-stop-interval-0s"
interval="0s" interval="0s"
name="stop" name="stop"
timeout="20s" timeout="20s"
/> />
</operations> </operations>
</primitive> </primitive>
''; '')
res.virtualIps;
mkSystemdResource = res: '' mkSystemdResource = res: ''
<primitive id="${res.systemdName}" class="systemd" type="${res.systemdName}"> <primitive id="${res.systemdName}" class="systemd" type="${res.systemdName}">
@ -115,25 +135,40 @@ in {
</primitive> </primitive>
''; '';
mkConstraint = first: res: '' mkConstraint = res: first: let
firstName =
if isAttrs first
then first.systemdName
else first;
in ''
<rsc_order <rsc_order
id="order-${res.systemdName}" id="order-${res.systemdName}-${firstName}"
first="${first}" first="${firstName}"
then="${res.systemdName}" then="${res.systemdName}"
kind="Mandatory" kind="Mandatory"
/> />
<rsc_colocation <rsc_colocation
id="colocate-${res.systemdName}" id="colocate-${res.systemdName}-${firstName}"
rsc="${first}" rsc="${firstName}"
with-rsc="${res.systemdName}" with-rsc="${res.systemdName}"
score="INFINITY" score="INFINITY"
/> />
''; '';
mkDependsOn = res: let
mkConstraint' = first:
mkConstraint res first;
in
concatMapStringsSep "\n" mkConstraint' res.dependsOn;
mkVipConstraint = res: mkVipConstraint = res:
concatMapStringsSep "\n" (
vip:
mkConstraint mkConstraint
(res.systemdName + "vip") res
res; "${res.systemdName}-${vip.id}-vip"
)
res.virtualIps;
# If we're updating resources we have to kill constraints to add new resources # If we're updating resources we have to kill constraints to add new resources
constraintsEmpty = toFile "constraints.xml" '' constraintsEmpty = toFile "constraints.xml" ''
@ -143,11 +178,11 @@ in {
resEnabled = filterAttrs (n: v: v.enable) cfg.resources; resEnabled = filterAttrs (n: v: v.enable) cfg.resources;
resWithIp = filterAttrs (n: v: ! isNull v.virtualIp) resEnabled; resWithIp = filterAttrs (n: v: ! isNull v.virtualIps) resEnabled;
resources = toFile "resources.xml" '' resources = toFile "resources.xml" ''
<resources> <resources>
${concatMapStringsSep "\n" mkVirtIp (attrValues resWithIp)} ${concatMapStringsSep "\n" mkVirtIps (attrValues resWithIp)}
${concatMapStringsSep "\n" mkSystemdResource (attrValues resEnabled)} ${concatMapStringsSep "\n" mkSystemdResource (attrValues resEnabled)}
</resources> </resources>
''; '';
@ -155,6 +190,7 @@ in {
constraints = toFile "constraints.xml" '' constraints = toFile "constraints.xml" ''
<constraints> <constraints>
${concatMapStringsSep "\n" mkVipConstraint (attrValues resWithIp)} ${concatMapStringsSep "\n" mkVipConstraint (attrValues resWithIp)}
${concatMapStringsSep "\n" mkDependsOn (attrValues resEnabled)}
</constraints> </constraints>
''; '';