From 481df957a679a238520d94835296ec624a5933e5 Mon Sep 17 00:00:00 2001 From: Felix Buehler Date: Sat, 24 Aug 2024 22:05:53 +0200 Subject: [PATCH] nixos/services.mosquitto: remove `with lib;` --- .../modules/services/networking/mosquitto.nix | 185 +++++++++--------- 1 file changed, 91 insertions(+), 94 deletions(-) diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix index 468f58b56bb1c..e628be0d5b1b3 100644 --- a/nixos/modules/services/networking/mosquitto.nix +++ b/nixos/modules/services/networking/mosquitto.nix @@ -1,39 +1,36 @@ { config, lib, pkgs, ...}: - -with lib; - let cfg = config.services.mosquitto; # note that mosquitto config parsing is very simplistic as of may 2021. # often times they'll e.g. strtok() a line, check the first two tokens, and ignore the rest. # there's no escaping available either, so we have to prevent any being necessary. - str = types.strMatching "[^\r\n]*" // { + str = lib.types.strMatching "[^\r\n]*" // { description = "single-line string"; }; - path = types.addCheck types.path (p: str.check "${p}"); - configKey = types.strMatching "[^\r\n\t ]+"; - optionType = with types; oneOf [ str path bool int ] // { + path = lib.types.addCheck lib.types.path (p: str.check "${p}"); + configKey = lib.types.strMatching "[^\r\n\t ]+"; + optionType = with lib.types; oneOf [ str path bool int ] // { description = "string, path, bool, or integer"; }; optionToString = v: - if isBool v then boolToString v + if lib.isBool v then lib.boolToString v else if path.check v then "${v}" else toString v; assertKeysValid = prefix: valid: config: - mapAttrsToList + lib.mapAttrsToList (n: _: { assertion = valid ? ${n}; message = "Invalid config key ${prefix}.${n}."; }) config; - formatFreeform = { prefix ? "" }: mapAttrsToList (n: v: "${prefix}${n} ${optionToString v}"); + formatFreeform = { prefix ? "" }: lib.mapAttrsToList (n: v: "${prefix}${n} ${optionToString v}"); - userOptions = with types; submodule { + userOptions = with lib.types; submodule { options = { - password = mkOption { + password = lib.mkOption { type = uniq (nullOr str); default = null; description = '' @@ -41,7 +38,7 @@ let ''; }; - passwordFile = mkOption { + passwordFile = lib.mkOption { type = uniq (nullOr path); example = "/path/to/file"; default = null; @@ -54,7 +51,7 @@ let ''; }; - hashedPassword = mkOption { + hashedPassword = lib.mkOption { type = uniq (nullOr str); default = null; description = '' @@ -66,7 +63,7 @@ let ''; }; - hashedPasswordFile = mkOption { + hashedPasswordFile = lib.mkOption { type = uniq (nullOr path); example = "/path/to/file"; default = null; @@ -82,7 +79,7 @@ let ''; }; - acl = mkOption { + acl = lib.mkOption { type = listOf str; example = [ "read A/B" "readwrite A/#" ]; default = []; @@ -94,15 +91,15 @@ let }; userAsserts = prefix: users: - mapAttrsToList + lib.mapAttrsToList (n: _: { assertion = builtins.match "[^:\r\n]+" n != null; message = "Invalid user name ${n} in ${prefix}"; }) users - ++ mapAttrsToList + ++ lib.mapAttrsToList (n: u: { - assertion = count (s: s != null) [ + assertion = lib.count (s: s != null) [ u.password u.passwordFile u.hashedPassword u.hashedPasswordFile ] <= 1; message = "Cannot set more than one password option for user ${n} in ${prefix}"; @@ -112,26 +109,26 @@ let userScope = prefix: index: "${prefix}-user-${toString index}"; credentialID = prefix: credential: "${prefix}-${credential}"; - toScopedUsers = listenerScope: users: pipe users [ - attrNames - (imap0 (index: user: nameValuePair user + toScopedUsers = listenerScope: users: lib.pipe users [ + lib.attrNames + (lib.imap0 (index: user: lib.nameValuePair user (users.${user} // { scope = userScope listenerScope index; }) )) - listToAttrs + lib.listToAttrs ]; - userCredentials = user: credentials: pipe credentials [ - (filter (credential: user.${credential} != null)) + userCredentials = user: credentials: lib.pipe credentials [ + (lib.filter (credential: user.${credential} != null)) (map (credential: "${credentialID user.scope credential}:${user.${credential}}")) ]; - usersCredentials = listenerScope: users: credentials: pipe users [ + usersCredentials = listenerScope: users: credentials: lib.pipe users [ (toScopedUsers listenerScope) - (mapAttrsToList (_: user: userCredentials user credentials)) - concatLists + (lib.mapAttrsToList (_: user: userCredentials user credentials)) + lib.concatLists ]; - systemdCredentials = listeners: listenerCredentials: pipe listeners [ - (imap0 (index: listener: listenerCredentials (listenerScope index) listener)) - concatLists + systemdCredentials = listeners: listenerCredentials: lib.pipe listeners [ + (lib.imap0 (index: listener: listenerCredentials (listenerScope index) listener)) + lib.concatLists ]; makePasswordFile = listenerScope: users: path: @@ -139,12 +136,12 @@ let makeLines = store: file: let scopedUsers = toScopedUsers listenerScope users; in - mapAttrsToList - (name: user: ''addLine ${escapeShellArg name} "''$(systemd-creds cat ${credentialID user.scope store})"'') - (filterAttrs (_: user: user.${store} != null) scopedUsers) - ++ mapAttrsToList - (name: user: ''addFile ${escapeShellArg name} "''${CREDENTIALS_DIRECTORY}/${credentialID user.scope file}"'') - (filterAttrs (_: user: user.${file} != null) scopedUsers); + lib.mapAttrsToList + (name: user: ''addLine ${lib.escapeShellArg name} "''$(systemd-creds cat ${credentialID user.scope store})"'') + (lib.filterAttrs (_: user: user.${store} != null) scopedUsers) + ++ lib.mapAttrsToList + (name: user: ''addFile ${lib.escapeShellArg name} "''${CREDENTIALS_DIRECTORY}/${credentialID user.scope file}"'') + (lib.filterAttrs (_: user: user.${file} != null) scopedUsers); plainLines = makeLines "password" "passwordFile"; hashedLines = makeLines "hashedPassword" "hashedPasswordFile"; in @@ -154,7 +151,7 @@ let set -eu - file=${escapeShellArg path} + file=${lib.escapeShellArg path} rm -f "$file" touch "$file" @@ -170,23 +167,23 @@ let echo "$1:$(cat "$2")" >> "$file" } '' - + concatStringsSep "\n" + + lib.concatStringsSep "\n" (plainLines - ++ optional (plainLines != []) '' + ++ lib.optional (plainLines != []) '' ${cfg.package}/bin/mosquitto_passwd -U "$file" '' ++ hashedLines)); - authPluginOptions = with types; submodule { + authPluginOptions = with lib.types; submodule { options = { - plugin = mkOption { + plugin = lib.mkOption { type = path; description = '' Plugin path to load, should be a `.so` file. ''; }; - denySpecialChars = mkOption { + denySpecialChars = lib.mkOption { type = bool; description = '' Automatically disallow all clients using `#` @@ -195,7 +192,7 @@ let default = true; }; - options = mkOption { + options = lib.mkOption { type = attrsOf optionType; description = '' Options for the auth plugin. Each key turns into a `auth_opt_*` @@ -207,7 +204,7 @@ let }; authAsserts = prefix: auth: - mapAttrsToList + lib.mapAttrsToList (n: _: { assertion = configKey.check n; message = "Invalid auth plugin key ${prefix}.${n}"; @@ -253,9 +250,9 @@ let use_username_as_clientid = 1; }; - listenerOptions = with types; submodule { + listenerOptions = with lib.types; submodule { options = { - port = mkOption { + port = lib.mkOption { type = port; description = '' Port to listen on. Must be set to 0 to listen on a unix domain socket. @@ -263,7 +260,7 @@ let default = 1883; }; - address = mkOption { + address = lib.mkOption { type = nullOr str; description = '' Address to listen on. Listen on `0.0.0.0`/`::` @@ -272,7 +269,7 @@ let default = null; }; - authPlugins = mkOption { + authPlugins = lib.mkOption { type = listOf authPluginOptions; description = '' Authentication plugin to attach to this listener. @@ -282,7 +279,7 @@ let default = []; }; - users = mkOption { + users = lib.mkOption { type = attrsOf userOptions; example = { john = { password = "123456"; acl = [ "readwrite john/#" ]; }; }; description = '' @@ -291,7 +288,7 @@ let default = {}; }; - omitPasswordAuth = mkOption { + omitPasswordAuth = lib.mkOption { type = bool; description = '' Omits password checking, allowing anyone to log in with any user name unless @@ -300,7 +297,7 @@ let default = false; }; - acl = mkOption { + acl = lib.mkOption { type = listOf str; description = '' Additional ACL items to prepend to the generated ACL file. @@ -309,7 +306,7 @@ let default = []; }; - settings = mkOption { + settings = lib.mkOption { type = submodule { freeformType = attrsOf optionType; }; @@ -324,7 +321,7 @@ let listenerAsserts = prefix: listener: assertKeysValid "${prefix}.settings" freeformListenerKeys listener.settings ++ userAsserts prefix listener.users - ++ imap0 + ++ lib.imap0 (i: v: authAsserts "${prefix}.authPlugins.${toString i}" v) listener.authPlugins; @@ -333,9 +330,9 @@ let "listener ${toString listener.port} ${toString listener.address}" "acl_file /etc/mosquitto/acl-${toString idx}.conf" ] - ++ optional (! listener.omitPasswordAuth) "password_file ${cfg.dataDir}/passwd-${toString idx}" + ++ lib.optional (! listener.omitPasswordAuth) "password_file ${cfg.dataDir}/passwd-${toString idx}" ++ formatFreeform {} listener.settings - ++ concatMap formatAuthPlugin listener.authPlugins; + ++ lib.concatMap formatAuthPlugin listener.authPlugins; freeformBridgeKeys = { bridge_alpn = 1; @@ -373,19 +370,19 @@ let try_private = 1; }; - bridgeOptions = with types; submodule { + bridgeOptions = with lib.types; submodule { options = { - addresses = mkOption { + addresses = lib.mkOption { type = listOf (submodule { options = { - address = mkOption { + address = lib.mkOption { type = str; description = '' Address of the remote MQTT broker. ''; }; - port = mkOption { + port = lib.mkOption { type = port; description = '' Port of the remote MQTT broker. @@ -400,7 +397,7 @@ let ''; }; - topics = mkOption { + topics = lib.mkOption { type = listOf str; description = '' Topic patterns to be shared between the two brokers. @@ -411,7 +408,7 @@ let example = [ "# both 2 local/topic/ remote/topic/" ]; }; - settings = mkOption { + settings = lib.mkOption { type = submodule { freeformType = attrsOf optionType; }; @@ -426,14 +423,14 @@ let bridgeAsserts = prefix: bridge: assertKeysValid "${prefix}.settings" freeformBridgeKeys bridge.settings ++ [ { - assertion = length bridge.addresses > 0; + assertion = lib.length bridge.addresses > 0; message = "Bridge ${prefix} needs remote broker addresses"; } ]; formatBridge = name: bridge: [ "connection ${name}" - "addresses ${concatMapStringsSep " " (a: "${a.address}:${toString a.port}") bridge.addresses}" + "addresses ${lib.concatMapStringsSep " " (a: "${a.address}:${toString a.port}") bridge.addresses}" ] ++ map (t: "topic ${t}") bridge.topics ++ formatFreeform {} bridge.settings; @@ -468,12 +465,12 @@ let websockets_log_level = 1; }; - globalOptions = with types; { - enable = mkEnableOption "the MQTT Mosquitto broker"; + globalOptions = with lib.types; { + enable = lib.mkEnableOption "the MQTT Mosquitto broker"; - package = mkPackageOption pkgs "mosquitto" { }; + package = lib.mkPackageOption pkgs "mosquitto" { }; - bridges = mkOption { + bridges = lib.mkOption { type = attrsOf bridgeOptions; default = {}; description = '' @@ -481,7 +478,7 @@ let ''; }; - listeners = mkOption { + listeners = lib.mkOption { type = listOf listenerOptions; default = []; description = '' @@ -489,7 +486,7 @@ let ''; }; - includeDirs = mkOption { + includeDirs = lib.mkOption { type = listOf path; description = '' Directories to be scanned for further config files to include. @@ -500,7 +497,7 @@ let default = []; }; - logDest = mkOption { + logDest = lib.mkOption { type = listOf (either path (enum [ "stdout" "stderr" "syslog" "topic" "dlt" ])); description = '' Destinations to send log messages to. @@ -508,7 +505,7 @@ let default = [ "stderr" ]; }; - logType = mkOption { + logType = lib.mkOption { type = listOf (enum [ "debug" "error" "warning" "notice" "information" "subscribe" "unsubscribe" "websockets" "none" "all" ]); description = '' @@ -517,7 +514,7 @@ let default = []; }; - persistence = mkOption { + persistence = lib.mkOption { type = bool; description = '' Enable persistent storage of subscriptions and messages. @@ -525,15 +522,15 @@ let default = true; }; - dataDir = mkOption { + dataDir = lib.mkOption { default = "/var/lib/mosquitto"; - type = types.path; + type = lib.types.path; description = '' The data directory. ''; }; - settings = mkOption { + settings = lib.mkOption { type = submodule { freeformType = attrsOf optionType; }; @@ -545,10 +542,10 @@ let }; globalAsserts = prefix: cfg: - flatten [ + lib.flatten [ (assertKeysValid "${prefix}.settings" freeformGlobalKeys cfg.settings) - (imap0 (n: l: listenerAsserts "${prefix}.listener.${toString n}" l) cfg.listeners) - (mapAttrsToList (n: b: bridgeAsserts "${prefix}.bridge.${n}" b) cfg.bridges) + (lib.imap0 (n: l: listenerAsserts "${prefix}.listener.${toString n}" l) cfg.listeners) + (lib.mapAttrsToList (n: b: bridgeAsserts "${prefix}.bridge.${n}" b) cfg.bridges) ]; formatGlobal = cfg: @@ -561,12 +558,12 @@ let cfg.logDest ++ map (t: "log_type ${t}") cfg.logType ++ formatFreeform {} cfg.settings - ++ concatLists (imap0 formatListener cfg.listeners) - ++ concatLists (mapAttrsToList formatBridge cfg.bridges) + ++ lib.concatLists (lib.imap0 formatListener cfg.listeners) + ++ lib.concatLists (lib.mapAttrsToList formatBridge cfg.bridges) ++ map (d: "include_dir ${d}") cfg.includeDirs; configFile = pkgs.writeText "mosquitto.conf" - (concatStringsSep "\n" (formatGlobal cfg)); + (lib.concatStringsSep "\n" (formatGlobal cfg)); in @@ -578,7 +575,7 @@ in ###### Implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = globalAsserts "services.mosquitto" cfg; @@ -633,13 +630,13 @@ in ReadWritePaths = [ cfg.dataDir "/tmp" # mosquitto_passwd creates files in /tmp before moving them - ] ++ filter path.check cfg.logDest; + ] ++ lib.filter path.check cfg.logDest; ReadOnlyPaths = map (p: "${p}") (cfg.includeDirs - ++ filter + ++ lib.filter (v: v != null) - (flatten [ + (lib.flatten [ (map (l: [ (l.settings.psk_file or null) @@ -652,7 +649,7 @@ in (l.settings.keyfile or null) ]) cfg.listeners) - (mapAttrsToList + (lib.mapAttrsToList (_: b: [ (b.settings.bridge_cafile or null) (b.settings.bridge_capath or null) @@ -680,26 +677,26 @@ in UMask = "0077"; }; preStart = - concatStringsSep + lib.concatStringsSep "\n" - (imap0 + (lib.imap0 (idx: listener: makePasswordFile (listenerScope idx) listener.users "${cfg.dataDir}/passwd-${toString idx}") cfg.listeners); }; - environment.etc = listToAttrs ( - imap0 + environment.etc = lib.listToAttrs ( + lib.imap0 (idx: listener: { name = "mosquitto/acl-${toString idx}.conf"; value = { user = config.users.users.mosquitto.name; group = config.users.users.mosquitto.group; mode = "0400"; - text = (concatStringsSep + text = (lib.concatStringsSep "\n" - (flatten [ + (lib.flatten [ listener.acl - (mapAttrsToList + (lib.mapAttrsToList (n: u: [ "user ${n}" ] ++ map (t: "topic ${t}") u.acl) listener.users) ]));