nix-config/modules/nncp.nix

203 lines
6.4 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
nncpCfgFile = "/run/nncp.hjson";
programCfg = config.programs.nncp;
callerCfg = config.services.nncp.caller;
daemonCfg = config.services.nncp.daemon;
settingsFormat = pkgs.formats.json { };
jsonCfgFile = settingsFormat.generate "nncp.json" programCfg.settings;
pkg = programCfg.package;
in {
options = {
programs.nncp = {
enable = mkEnableOption "NNCP (Node to Node copy) utilities";
package = mkOption {
type = types.package;
default = pkgs.nncp;
defaultText = literalExpression "pkgs.nncp";
description = "The NNCP package to use system-wide.";
};
secrets = mkOption {
type = with types; listOf str;
example = [ "/run/keys/nncp.hjson" ];
description = ''
A list of paths to NNCP configuration files that should not be
in the Nix store. These files are layered on top of the values at
<xref linkend="opt-programs.nncp.settings"/>.
'';
};
settings = mkOption {
type = settingsFormat.type;
description = ''
NNCP configuration, see
<link xlink:href="http://www.nncpgo.org/Configuration.html"/>.
At runtime these settings will be overlayed by the contents of
<xref linkend="opt-programs.nncp.secrets"/> into the file
<literal>${nncpCfgFile}</literal>. Node keypairs go in
<literal>secrets</literal>, do not specify them in
<literal>settings</literal> as they will be leaked into
<literal>/nix/store</literal>!
'';
default = { };
};
};
services.nncp = {
caller = {
enable = mkEnableOption ''
croned NNCP TCP daemon caller.
The daemon will take configuration from
<xref linkend="opt-programs.nncp.settings"/>
'';
extraArgs = mkOption {
type = with types; listOf str;
description = "Extra command-line arguments to pass to caller.";
default = [ ];
example = [ "-autotoss" ];
};
};
daemon = {
enable = mkEnableOption ''
NNCP TCP synronization daemon.
The daemon will take configuration from
<xref linkend="opt-programs.nncp.settings"/>
'';
socketActivation = {
enable = mkEnableOption ''
Whether to run nncp-daemon persistently or socket-activated.
'';
listenStreams = mkOption {
type = with types; listOf str;
description = ''
TCP sockets to bind to.
See <xref linkend="opt-systemd.sockets._name_.listenStreams"/>.
'';
default = [ "5400" ];
};
};
extraArgs = mkOption {
type = with types; listOf str;
description = "Extra command-line arguments to pass to daemon.";
default = [ ];
example = [ "-autotoss" ];
};
};
};
};
config = mkIf (programCfg.enable or callerCfg.enable or daemonCfg.enable) {
assertions = [{
assertion = with builtins;
let
callerCongfigured =
let neigh = config.programs.nncp.settings.neigh or { };
in lib.lists.any (x: hasAttr "calls" x && x.calls != [ ])
(attrValues neigh);
in !callerCfg.enable || callerCongfigured;
message = "NNCP caller enabled but call configuration is missing";
}];
programs.nncp.settings = {
spool = mkDefault "/var/spool/nncp";
log = mkDefault "/var/spool/nncp/log";
};
environment = mkIf programCfg.enable {
systemPackages = [ pkg ];
etc."nncp.hjson".source = nncpCfgFile;
};
systemd.tmpfiles.rules = [
"d ${programCfg.settings.spool} 0770 root uucp"
"f ${programCfg.settings.log} 0770 root uucp"
];
system.activationScripts.nncp = ''
nncpCfgDir=$(mktemp --directory nncp.XXXXXXXXXX)
for f in ${jsonCfgFile} ${toString config.programs.nncp.secrets}; do
tmpdir=$(mktemp --directory nncp.XXXXXXXXXX)
${pkg}/bin/nncp-cfgdir -cfg $f -dump $tmpdir
${pkgs.findutils}/bin/find $tmpdir -size 1c -delete
cp -a $tmpdir/* $nncpCfgDir/
rm -rf $tmpdir
done
${pkg}/bin/nncp-cfgdir -load $nncpCfgDir > ${nncpCfgFile}
rm -rf $nncpCfgDir
chgrp uucp ${nncpCfgFile}
'';
systemd.services."nncp-caller" = {
inherit (callerCfg) enable;
description = "Croned NNCP TCP daemon caller.";
documentation = [ "http://www.nncpgo.org/nncp_002dcaller.html" ];
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = ''
${pkg}/bin/nncp-caller -noprogress -cfg "${nncpCfgFile}" ${
lib.strings.escapeShellArgs callerCfg.extraArgs
}'';
Group = "uucp";
UMask = "0002";
};
};
systemd.services."nncp-daemon" = mkIf daemonCfg.enable {
enable = !daemonCfg.socketActivation.enable;
description = "NNCP TCP syncronization daemon.";
documentation = [ "http://www.nncpgo.org/nncp_002ddaemon.html" ];
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = ''
${pkg}/bin/nncp-daemon -noprogress -cfg "${nncpCfgFile}" ${
lib.strings.escapeShellArgs daemonCfg.extraArgs
}'';
Restart = "on-failure";
Group = "uucp";
UMask = "0002";
};
};
systemd.services."nncp-daemon@" = mkIf daemonCfg.socketActivation.enable {
description = "NNCP TCP syncronization daemon.";
documentation = [ "http://www.nncpgo.org/nncp_002ddaemon.html" ];
after = [ "network.target" ];
serviceConfig = {
ExecStart = ''
${pkg}/bin/nncp-daemon -noprogress -ucspi -cfg "${nncpCfgFile}" ${
lib.strings.escapeShellArgs daemonCfg.extraArgs
}'';
Group = "uucp";
UMask = "0002";
StandardInput = "socket";
StandardOutput = "inherit";
StandardError = "journal";
};
};
systemd.sockets.nncp-daemon = mkIf daemonCfg.socketActivation.enable {
inherit (daemonCfg.socketActivation) listenStreams;
description = "socket for NNCP TCP syncronization.";
conflicts = [ "nncp-daemon.service" ];
wantedBy = [ "sockets.target" ];
socketConfig.Accept = true;
};
};
}