network/nix/nixos-module/pacemaker.nix

168 lines
4.2 KiB
Nix

{ self, pkgs, lib, config, ... }:
let
description = "Pacemaker HA cluster manager";
cfg = config.services.pacemaker;
in {
options.services = with lib; {
corosync = {
clusterName = mkOption {
type = types.str;
default = "nixcluster";
};
extraOptions = mkOption {
type = types.str;
default = "";
};
nodelist = mkOption {
default = [];
type = with types; listOf (submodule {
options = {
nodeid = mkOption {
type = int;
};
name = mkOption {
type = str;
};
ring_addrs = mkOption {
type = listOf str;
};
};
});
};
};
pacemaker = {
enable = mkEnableOption description;
package = mkOption {
type = types.package;
default = self.packages.${pkgs.system}.pacemaker;
};
};
};
config = lib.mkIf cfg.enable {
nixpkgs.config.packageOverrides = pkgs: {
corosync = pkgs.corosync.overrideAttrs ({ buildInputs, configureFlags, ... }: {
buildInputs = buildInputs ++ [
pkgs.systemd.dev
];
configureFlags = configureFlags ++ [
# allows Type=notfiy in the systemd.service
"--enable-systemd"
];
});
};
environment.systemPackages = with pkgs; [
corosync
cfg.package
];
environment.etc."corosync/corosync.conf".text = ''
totem {
version: 2
secauth: off
cluster_name: ${config.services.corosync.clusterName}
transport: knet
# TODO: secauth
}
nodelist {
${lib.concatMapStrings ({ nodeid, name, ring_addrs }: ''
node {
nodeid: ${toString nodeid}
name: ${name}
${lib.concatStrings (lib.imap0 (i: addr: ''
ring${toString i}_addr: ${addr}
'') ring_addrs)}
}
'') config.services.corosync.nodelist}
}
quorum {
# only corosync_votequorum is supported
provider: corosync_votequorum
wait_for_all: 0
${lib.optionalString (builtins.length config.services.corosync.nodelist < 3) ''
two_node: 1
''}
}
logging {
to_syslog: yes
}
'';
environment.etc."corosync/uidgid.d/root".text = ''
# allow pacemaker connection by root
uidgid {
uid: 0
gid: 0
}
'';
systemd.tmpfiles.rules = [
"d /var/lib/corosync 0700 root root -"
"d /var/lib/pacemaker 0700 hacluster pacemaker -"
"d /var/lib/pacemaker/cib 0700 hacluster pacemaker -"
];
# used by pacemaker
users.users.hacluster = {
isSystemUser = true;
group = "pacemaker";
};
users.groups.pacemaker = {};
systemd.services = {
# see ${corosync.src}/init/corosync.service.in
corosync = {
requires = [ "network-online.target" ];
after= [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${pkgs.corosync}/sbin/corosync -f ${config.services.corosync.extraOptions}";
ExecStop= "${pkgs.corosync}/sbin/corosync-cfgtool -H --force";
Type = "notify";
StandardError = "null";
};
};
# see ${pacemaker.src}/daemons/pacemakerd/pacemaker.service.in
pacemaker = {
inherit description;
after = [
"network.target" "time-sync.target" "dbus.service"
#"resource-agents-deps.target"
"corosync.service"
];
wants = [ "dbus.service" ];
requires = [ "corosync.service" ];
wantedBy = [ "multi-user.target" ];
script = ''
cp -srf ${cfg.package}/var/lib/pacemaker/* /var/lib/pacemaker/
exec ${cfg.package}/sbin/pacemakerd
'';
serviceConfig = {
Type = "simple";
KillMode = "process";
NotifyAccess = "main";
SuccessExitStatus = 100;
TasksMax = "infinity";
SendSIGKILL = false;
TimeoutStopSec = "30min";
TimeoutStartSec = "60s";
Restart = "on-failure";
StandardError = "null";
};
};
};
};
}