Merge pull request #218633 from onny/networkd-dispatcher-rules

nixos/networkd-dispatcher: add rules option

Changed files
+80 -26
nixos
modules
services
pkgs
tools
networking
+61 -26
nixos/modules/services/networking/networkd-dispatcher.nix
···
with lib;
let
+
cfg = config.services.networkd-dispatcher;
+
in {
+
options = {
services.networkd-dispatcher = {
···
for usage.
'');
-
scriptDir = mkOption {
-
type = types.path;
-
default = "/var/lib/networkd-dispatcher";
-
description = mdDoc ''
-
This directory is used for keeping various scripts read and run by
-
networkd-dispatcher. See [https://gitlab.com/craftyguy/networkd-dispatcher](upstream instructions)
-
for directory structure and script usage.
+
rules = mkOption {
+
default = {};
+
example = lib.literalExpression ''
+
{ "restart-tor" = {
+
onState = ["routable" "off"];
+
script = '''
+
#!''${pkgs.runtimeShell}
+
if [[ $IFACE == "wlan0" && $AdministrativeState == "configured" ]]; then
+
echo "Restarting Tor ..."
+
systemctl restart tor
+
fi
+
exit 0
+
''';
+
};
+
};
'';
+
description = lib.mdDoc ''
+
Declarative configuration of networkd-dispatcher rules. See
+
[https://gitlab.com/craftyguy/networkd-dispatcher](upstream instructions)
+
for an introduction and example scripts.
+
'';
+
type = types.attrsOf (types.submodule {
+
options = {
+
onState = mkOption {
+
type = types.listOf (types.enum [
+
"routable" "dormant" "no-carrier" "off" "carrier" "degraded"
+
"configuring" "configured"
+
]);
+
default = null;
+
description = lib.mdDoc ''
+
List of names of the systemd-networkd operational states which
+
should trigger the script. See <https://www.freedesktop.org/software/systemd/man/networkctl.html>
+
for a description of the specific state type.
+
'';
+
};
+
script = mkOption {
+
type = types.lines;
+
description = lib.mdDoc ''
+
Shell commands executed on specified operational states.
+
'';
+
};
+
};
+
});
};
};
···
config = mkIf cfg.enable {
systemd = {
-
packages = [ pkgs.networkd-dispatcher ];
services.networkd-dispatcher = {
wantedBy = [ "multi-user.target" ];
# Override existing ExecStart definition
-
serviceConfig.ExecStart = [
+
serviceConfig.ExecStart = let
+
scriptDir = pkgs.symlinkJoin {
+
name = "networkd-dispatcher-script-dir";
+
paths = lib.mapAttrsToList (name: cfg:
+
(map(state:
+
pkgs.writeTextFile {
+
inherit name;
+
text = cfg.script;
+
destination = "/${state}.d/${name}";
+
executable = true;
+
}
+
) cfg.onState)
+
) cfg.rules;
+
};
+
in [
""
-
"${pkgs.networkd-dispatcher}/bin/networkd-dispatcher -v --script-dir ${cfg.scriptDir} $networkd_dispatcher_args"
+
"${pkgs.networkd-dispatcher}/bin/networkd-dispatcher -v --script-dir ${scriptDir} $networkd_dispatcher_args"
];
};
-
-
# Directory structure required according to upstream instructions
-
# https://gitlab.com/craftyguy/networkd-dispatcher
-
tmpfiles.rules = [
-
"d '${cfg.scriptDir}' 0750 root root - -"
-
"d '${cfg.scriptDir}/routable.d' 0750 root root - -"
-
"d '${cfg.scriptDir}/dormant.d' 0750 root root - -"
-
"d '${cfg.scriptDir}/no-carrier.d' 0750 root root - -"
-
"d '${cfg.scriptDir}/off.d' 0750 root root - -"
-
"d '${cfg.scriptDir}/carrier.d' 0750 root root - -"
-
"d '${cfg.scriptDir}/degraded.d' 0750 root root - -"
-
"d '${cfg.scriptDir}/configuring.d' 0750 root root - -"
-
"d '${cfg.scriptDir}/configured.d' 0750 root root - -"
-
];
-
};
-
};
}
+6
pkgs/tools/networking/networkd-dispatcher/default.nix
···
hash = "sha256-yO9/HlUkaQmW/n9N3vboHw//YMzBjxIHA2zAxgZNEv0=";
};
+
patches = [
+
# Support rule files in NixOS store paths. Required for the networkd-dispatcher
+
# module to work
+
./support_nix_store_path.patch
+
];
+
postPatch = ''
# Fix paths in systemd unit file
substituteInPlace networkd-dispatcher.service \
+13
pkgs/tools/networking/networkd-dispatcher/support_nix_store_path.patch
···
+
diff --git a/networkd-dispatcher b/networkd-dispatcher
+
index ef877ce..8c341f2 100755
+
--- a/networkd-dispatcher
+
+++ b/networkd-dispatcher
+
@@ -171,6 +171,8 @@ def check_perms(path, mode=0o755, uid=0, gid=0):
+
+
if not os.path.exists(path):
+
raise FileNotFoundError
+
+ if re.search('^/nix/store/.*', str(path)):
+
+ return True
+
st = os.stat(path, follow_symlinks=False)
+
st_mode = st.st_mode & 0x00FFF
+
if st.st_uid == uid and st.st_gid == gid and st_mode == mode: